天天看點

設計模式原則(5)--Law of Demeter(LoD)--迪米特法則

一個軟體實體應當盡可能少地與其他實體發生互相作用。

作者QQ:1095737364    QQ群:123300273     歡迎加入!

1.定義:

  一個軟體實體應當盡可能少地與其他實體發生互相作用。也就是說:一個類對自己依賴的類知道的越少越好。也就是說無論被依賴的類多麼複雜,都應該将邏輯封裝在方法的内部,通過public方法提供給外部。這樣當被依賴的類變化時,才能最小的影響該類。

2.使用場景:

  如果類A有兩個職責:d1,d2。當職責d1需要修改時,可能會導緻原本運作正常的職責d2功能産生問題。即如果一個類包含多種職責,就應該把類拆分。分别建立兩個類A、B,讓A負責d1,B負責d2。當需要修改某一職責,那麼将不會對另外一個功能産生影響。

3.使用特點

     如果一個系統符合迪米特法則,那麼當其中某一個子產品發生修改時,就會盡量少地影響其他子產品,擴充會相對容易,這是對軟體實體之間通信的限制,迪米特法則要求限制軟體實體之間通信的寬度和深度。迪米特法則可降低系統的耦合度,使類與類之間保持松散的耦合關系。

     迪米特法則要求我們在設計系統時,應該盡量減少對象之間的互動,如果兩個對象之間不必彼此直接通信,那麼這兩個對象就不應當發生任何直接的互相作用,如果其中的一個對象需要調用另一個對象的某一個方法的話,可以通過第三者轉發這個調用。簡言之,就是通過引入一個合理的第三者來降低現有對象之間的耦合度。

      在将迪米特法則運用到系統設計中時,要注意下面的幾點:在類的劃分上,應當盡量建立松耦合的類,類之間的耦合度越低,就越有利于複用,一個處在松耦合中的類一旦被修改,不會對關聯的類造成太大波及;在類的結構設計上,每一個類都應當盡量降低其成員變量和成員函數的通路權限;在類的設計上,隻要有可能,一個類型應當設計成不變類;在對其他類的引用上,一個對象對其他對象的引用應當降到最低。

4.實作案例

舉一個例子:有一個集團公司,下屬機關有分公司和直屬部門,現在要求列印出所有下屬機關的員工ID。先來看一下違反迪米特法則的設計。

//總公司員工
class Employee{
    private String id;
    public void setId(String id){
        this.id = id;
    }
    public String getId(){
        return id;
    }
}

//分公司員工
class SubEmployee{
    private String id;
    public void setId(String id){
        this.id = id;
    }
    public String getId(){
        return id;
    }
}

class SubCompanyManager{
    public List<SubEmployee> getAllEmployee(){
        List<SubEmployee> list = new ArrayList<SubEmployee>();
        for(int i=0; i<100; i++){
            SubEmployee emp = new SubEmployee();
            //為分公司人員按順序配置設定一個ID
            emp.setId("分公司"+i);
            list.add(emp);
        }
        return list;
    }
}

class CompanyManager{

    public List<Employee> getAllEmployee(){
        List<Employee> list = new ArrayList<Employee>();
        for(int i=0; i<30; i++){
            Employee emp = new Employee();
            //為總公司人員按順序配置設定一個ID
            emp.setId("總公司"+i);
            list.add(emp);
        }
        return list;
    }
    
    public void printAllEmployee(SubCompanyManager sub){
        List<SubEmployee> list1 = sub.getAllEmployee();
        for(SubEmployee e:list1){
            System.out.println(e.getId());
        }

        List<Employee> list2 = this.getAllEmployee();
        for(Employee e:list2){
            System.out.println(e.getId());
        }
    }
}

public class Client{
    public static void main(String[] args){
        CompanyManager e = new CompanyManager();
        e.printAllEmployee(new SubCompanyManager());
    }
}      

  現在這個設計的主要問題出在CompanyManager中,根據迪米特法則,隻與直接的朋友發生通信,而SubEmployee類并不是CompanyManager類的直接朋友(以局部變量出現的耦合不屬于直接朋友),從邏輯上講總公司隻與他的分公司耦合就行了,與分公司的員工并沒有任何聯系,這樣設計顯然是增加了不必要的耦合。按照迪米特法則,應該避免類中出現這樣非直接朋友關系的耦合。修改後的代碼如下:

class SubCompanyManager{
    public List<SubEmployee> getAllEmployee(){
        List<SubEmployee> list = new ArrayList<SubEmployee>();
        for(int i=0; i<100; i++){
            SubEmployee emp = new SubEmployee();
            //為分公司人員按順序配置設定一個ID
            emp.setId("分公司"+i);
            list.add(emp);
        }
        return list;
    }
    public void printEmployee(){
        List<SubEmployee> list = this.getAllEmployee();
        for(SubEmployee e:list){
            System.out.println(e.getId());
        }
    }
}

class CompanyManager{
    public List<Employee> getAllEmployee(){
        List<Employee> list = new ArrayList<Employee>();
        for(int i=0; i<30; i++){
            Employee emp = new Employee();
            //為總公司人員按順序配置設定一個ID
            emp.setId("總公司"+i);
            list.add(emp);
        }
        return list;
    }
    
    public void printAllEmployee(SubCompanyManager sub){
        sub.printEmployee();
        List<Employee> list2 = this.getAllEmployee();
        for(Employee e:list2){
            System.out.println(e.getId());
        }
    }
}      

  修改後,為分公司增加了列印人員ID的方法,總公司直接調用來列印,進而避免了與分公司的員工發生耦合。

5.注意事項

  迪米特法則的初衷是降低類之間的耦合,由于每個類都減少了不必要的依賴,是以的确可以降低耦合關系。但是凡事都有度,雖然可以避免與非直接的類通信,但是要通信,必然會通過一個“中介”來發生聯系,例如本例中,總公司就是通過分公司這個“中介”來與分公司的員工發生聯系的。過分的使用迪米特原則,會産生大量這樣的中介和傳遞類,導緻系統複雜度變大。是以在采用迪米特法則時要反複權衡,既做到結構清晰,又要高内聚低耦合。

繼續閱讀