天天看點

迪米特法則(最少知識原則)

定義

如果兩個類不必彼此直接通信,那麼這兩個類就不應該發生直接的互相作用。如果一個類需要調用另一個類的某一個方法的話,可以通過第三者轉發這個應用。
  • 迪米特法則強調:在類的結構設計上,每一個類都應該盡量降低成員變量的通路權限。也就是說一個類應該包裝好自己的private狀态,不需要讓别的類知道的字段或行為就不要公開;
  • 迪米特法則的根本思想是:強調類之間的松耦合;
  • 類之間的耦合越弱,越有利于複用,一個處于弱耦合的類被修改了,不會對有關系的類造成波及;

問題由來:類與類之間的關系越密切,耦合度越大,當一個類發生改變時,對另一個類的影響也越大。

解決方案:盡量降低類與類之間的耦合。

  自從我們接觸程式設計開始,就知道了軟體程式設計的總的原則:低耦合,高内聚。無論是面向過程程式設計還是面向對象程式設計,隻有使各個子產品之間的耦合盡量的低,才能提高代碼的複用率。低耦合的優點不言而喻,但是怎麼樣程式設計才能做到低耦合呢?那正是迪米特法則要去完成的。

  迪米特法則(Law of Demeter,LoD)又叫作最少知識原則(Least Knowledge Principle,LKP),産生于 1987 年美國東北大學(Northeastern University)的一個名為迪米特(Demeter)的研究項目,由伊恩·荷蘭(Ian Holland)提出,被 UML 創始者之一的布奇(Booch)普及,後來又因為在經典著作《程式員修煉之道》(The Pragmatic Programmer)提及而廣為人知。

  迪米特法則的定義是:隻與你的直接朋友交談,不跟“陌生人”說話(Talk only to your immediate friends and not to strangers)。其含義是:如果兩個軟體實體無須直接通信,那麼就不應當發生直接的互相調用,可以通過第三方轉發該調用。其目的是降低類之間的耦合度,提高子產品的相對獨立性。

  通俗的來講,就是一個類對自己依賴的類知道的越少越好。也就是說,對于被依賴的類來說,無論邏輯多麼複雜,都盡量地的将邏輯封裝在類的内部,對外除了提供的public方法,不對外洩漏任何資訊。迪米特法則還有一個更簡單的定義:隻與直接的朋友通信。首先來解釋一下什麼是直接的朋友:迪米特法則中的“朋友”是指:目前對象本身、目前對象的成員對象、目前對象所建立的對象、目前對象的方法參數等,這些對象同目前對象存在關聯、聚合或組合關系,可以直接通路這些對象的方法。隻要兩個對象之間有耦合關系,我們就說這兩個對象之間是朋友關系。耦合的方式很多,依賴、關聯、組合、聚合等。其中,我們稱出現成員變量、方法參數、方法傳回值中的類為直接的朋友,而出現在局部變量中的類則不是直接的朋友。也就是說,陌生的類最好不要作為局部變量的形式出現在類的内部。

迪米特法則的實作方法

從迪米特法則的定義和特點可知,它強調以下兩點:

  • 從依賴者的角度來說,隻依賴應該依賴的對象。
  • 從被依賴者的角度說,隻暴露應該暴露的方法。

是以,在運用迪米特法則時要注意以下 6 點。

  • 在類的劃分上,應該建立弱耦合的類。類與類之間的耦合越弱,就越有利于實作可複用的目标。
  • 在類的結構設計上,盡量降低類成員的通路權限。
  • 在類的設計上,優先考慮将一個類設定成不變類。
  • 在對其他類的引用上,将引用其他對象的次數降到最低。
  • 不暴露類的屬性成員,而應該提供相應的通路器(set 和 get 方法)。
  • 謹慎使用序列化(Serializable)功能。
  • 明星與經紀人的關系執行個體

  明星由于全身心投入藝術,是以許多日常事務由經紀人負責處理,如與粉絲的見面會,與媒體公司的業務洽淡等。這裡的經紀人是明星的朋友,而粉絲和媒體公司是陌生人,是以适合使用迪米特法則,其類圖如圖

代碼如下

package test;

public class test {

    public static void main(String[] args)
    {
        Agent agent=new Agent();
        agent.setStar(new Star("胡歌"));
        agent.setFans(new Fans("粉絲"));
        agent.setCompany(new Company("上海唐人電影制作有限公司"));
        agent.meeting();
        agent.business();
    }
}
//經紀人
class Agent
{
    private Star myStar;
    private Fans myFans;
    private Company myCompany;
    public void setStar(Star myStar)
    {
        this.myStar=myStar;
    }
    public void setFans(Fans myFans)
    {
        this.myFans=myFans;
    }
    public void setCompany(Company myCompany)
    {
        this.myCompany=myCompany;
    }
    public void meeting()
    {
        System.out.println(myFans.getName()+"與明星"+myStar.getName()+"見面了。");
    }
    public void business()
    {
        System.out.println(myCompany.getName()+"與明星"+myStar.getName()+"洽淡業務。");
    }
}
//明星
class Star
{
    private String name;
    Star(String name)
    {
        this.name=name;
    }
    public String getName()
    {
        return name;
    }
}
//粉絲
class Fans
{
    private String name;
    Fans(String name)
    {
        this.name=name;
    }
    public String getName()
    {
        return name;
    }
}
//媒體公司
class Company
{
    private String name;
    Company(String name)
    {
        this.name=name;
    }
    public String getName()
    {
        return name;
    }
}

運作結果如下:

粉絲與明星胡歌見面了。
上海唐人電影制作有限公司與明星胡歌洽淡業務。
           

迪米特法則的優點

迪米特法則要求限制軟體實體之間通信的寬度和深度,正确使用迪米特法則将有以下兩個優點。

  • 降低了類之間的耦合度,提高了子產品的相對獨立性。
  • 由于親合度降低,進而提高了類的可複用率和系統的擴充性。

  但是凡事都有度,雖然可以避免與非直接的類通信,但是要通信,必然會通過一個“中介”來發生聯系,例如本例中,明星就是通過經紀人這個“中介”來與媒體公司、粉絲發生聯系的。過分的使用迪米特原則,會産生大量這樣的中介和傳遞類,導緻系統複雜度變大。是以,在釆用迪米特法則時需要反複權衡,確定高内聚和低耦合的同時,保證系統的結構清晰。

繼續閱讀