Java與設計模式(七)迪米特法則(最少知道原則)

一、定義

迪米特法則來自於1987年美國東北大學(Northeastern University)一個名爲“Demeter”的研究項目。迪米特法則又稱爲最少知識原則(LeastKnowledge Principle, LKP),其定義如下:
迪米特法則(Law of Demeter, LoD):一個軟件實體應當儘可能少地與其他實體發生相互作用。

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

迪米特法則還有幾種定義形式,包括:不要和“陌生人”說話、只與你的直接朋友通信等,在迪米特法則中,對於一個對象,其朋友包括以下幾類:

  • 當前對象本身(this);
  • 以參數形式傳入到當前對象方法中的對象;
  • 當前對象的成員對象;
  • 如果當前對象的成員對象是一個集合,那麼集合中的元素也都是朋友;
  • 當前對象所創建的對象。

任何一個對象,如果滿足上面的條件之一,就是當前對象的“朋友”,否則就是“陌生人”。在應用迪米特法則時,一個對象只能與直接朋友發生交互,不要與“陌生人”發生直接交互,這樣做可以降
低系統的耦合度,一個對象的改變不會給太多其他對象帶來影響。

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

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

二、代碼示例

//總公司員工  
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的方法,總公司直接調用來打印,從而避免了與分公司的員工發生耦合。

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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章