定義
如果兩個類不必彼此直接通信,那麼這兩個類就不應該發生直接的互相作用。如果一個類需要調用另一個類的某一個方法的話,可以通過第三者轉發這個應用。
- 迪米特法則強調:在類的結構設計上,每一個類都應該盡量降低成員變量的通路權限。也就是說一個類應該包裝好自己的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;
}
}
運作結果如下:
粉絲與明星胡歌見面了。
上海唐人電影制作有限公司與明星胡歌洽淡業務。
迪米特法則的優點
迪米特法則要求限制軟體實體之間通信的寬度和深度,正确使用迪米特法則将有以下兩個優點。
- 降低了類之間的耦合度,提高了子產品的相對獨立性。
- 由于親合度降低,進而提高了類的可複用率和系統的擴充性。
但是凡事都有度,雖然可以避免與非直接的類通信,但是要通信,必然會通過一個“中介”來發生聯系,例如本例中,明星就是通過經紀人這個“中介”來與媒體公司、粉絲發生聯系的。過分的使用迪米特原則,會産生大量這樣的中介和傳遞類,導緻系統複雜度變大。是以,在釆用迪米特法則時需要反複權衡,確定高内聚和低耦合的同時,保證系統的結構清晰。