迪米特法則——合理的封裝

weixin_34127717發表於2018-07-01

title: 迪米特法則——合理的封裝
date: 2016-10-22 18:55:36
tags:

  • Java
  • 設計模式
    categories: 設計模式

背景

以服務員,客戶,錢包為載體,模擬一個付款過程,闡述不恰當的封裝行為。

說明合理封裝的一般過程以及不合理封裝所表現的一般形式,介紹迪米特法則相關的基本內容,遵循迪米特法則對問題程式碼進行重構。

看似沒有問題的問題

先看一個簡單程式碼,分別描述錢包、客戶、服務員:

public class Wallet {
    private double value;
     public double getTotalMoney() {
        return value;
    }
    public void setTotalMoney(double newValue) {
        value = newValue;
    }
    public void addMoney(double deposit) {
        value += deposit;
    }
    public void subtractMoney(double debit) {
        value -= debit;
    }
    // 省略其它欄位,方法
}

public class Customer {
    private Wallet myWallet;
    // 省略其它欄位,方法
}

public class Paperboy {
  private Customer myCustomer;
  public void pay(double payment) {
    Wallet theWallet = myCustomer.getWallet();
    if (theWallet.getTotalMoney() > payment) {
        theWallet.subtractMoney(payment);
    } else {
        //money not enough
    }
  }
}

一眼看過去,沒毛病。幾個基本的簡單類在Paperboy的pay方法中實現了簡單的業務邏輯,但翻譯成“人類語言”就有點問題了:

業務的第一步造作:通過客戶獲取其錢包。

等等這樣真的好嗎?現實生活中彷彿講不通啊,程式設計中其實違反了迪米特法則。

聽到迪米特法則那一瞬間,我想到的是各種設計模式概念,尷尬的是就是想不起迪米特到底是個啥!

迪米特法則

迪米特法則(最小知識法則,強調專注性):

任何一個物件或者方法,它應該只能呼叫下列物件:

  • 該物件本身和物件的屬性
  • 作為引數傳進方法的物件
  • 在方法內建立的物件

這下好像清晰多了,其實再通俗一點上面的程式碼就是違反了封裝的原則。

合理的封裝分為兩步

  1. 分辨職責
    1. 依據:資料與行為應該封裝在一起(資訊專家模式)
    2. 過程:職責操作哪些資料,資料在哪個(些)類,進而確定職責在哪個類
  2. 判別哪些是實現細節,哪些是可以公開的介面,以保證對細節的合理隱藏

不良封裝造成的結果:Feature Envy(依戀情結)

不良封裝可能的程式碼樣式

obj1.obj1_fun().obj2_fun();

類似鏈式的方法呼叫,但方法返回的是不同物件,這時候的程式碼很有可能是不良封裝,違反迪米特法則了。

問題的解決

上面程式碼良好的封裝示例:

public class Customer {
    private Wallet myWallet;

    public void pay(float payment) {
        Wallet theWallet = myWallet;
        if (theWallet.getTotalMoney() > payment) {
            theWallet.subtractMoney(payment);
        } else {
            //money not enough
        }
    }
}

public class Paperboy {
    private Customer myCustomer;

    public void pay(float payment) {
        myCustomer.pay(payment);
    }

}

相關文章