前幾節分別詳細介紹了面向對象設計原則中的開閉原則、里氏替換原則、依賴倒置原則、單一職責原則和接口隔離原則,本節將詳細介紹迪米特法則。
迪米特法則(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)。其含義是:如果兩個軟件實體無須直接通信,那么就不應當發生直接的相互調用,可以通過第三方轉發該調用。其目的是降低類之間的耦合度,提高模塊的相對獨立性。
迪米特法則中的“朋友”是指:當前對象本身、當前對象的成員對象、當前對象所創建的對象、當前對象的方法參數等,這些對象同當前對象存在關聯、聚合或組合關系,可以直接訪問這些對象的方法。
迪米特法則要求限制軟件實體之間通信的寬度和深度,正確使用迪米特法則將有以下兩個優點。
1. 降低了類之間的耦合度,提高了模塊的相對獨立性。
2. 由于親合度降低,從而提高了類的可復用率和系統的擴展性。
但是,過度使用迪米特法則會使系統產生大量的中介類,從而增加系統的復雜性,使模塊之間的通信效率降低。所以,在釆用迪米特法則時需要反復權衡,確保高內聚和低耦合的同時,保證系統的結構清晰。
從迪米特法則的定義和特點可知,它強調以下兩點:
1. 從依賴者的角度來說,只依賴應該依賴的對象。
2. 從被依賴者的角度說,只暴露應該暴露的方法。
所以,在運用迪米特法則時要注意以下 6 點。
1. 在類的劃分上,應該創建弱耦合的類。類與類之間的耦合越弱,就越有利于實現可復用的目標。
2. 在類的結構設計上,盡量降低類成員的訪問權限。
3. 在類的設計上,優先考慮將一個類設置成不變類。
4. 在對其他類的引用上,將引用其他對象的次數降到最低。
5. 不暴露類的屬性成員,而應該提供相應的訪問器(set 和 get 方法)。
6. 謹慎使用序列化(Serializable)功能。
【例1】明星與經紀人的關系實例。
分析:明星由于全身心投入藝術,所以許多日常事務由經紀人負責處理,如與粉絲的見面會,與媒體公司的業務洽淡等。這里的經紀人是明星的朋友,而粉絲和媒體公司是陌生人,所以適合使用迪米特法則,其類圖如圖 1 所示。
圖1 明星與經紀人的關系圖
程序代碼如下:
package principle;
public class LoDtest
{
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;
}
}
程序的運行結果如下:
粉絲韓丞與明星林心如見面了。
中國傳媒有限公司與明星林心如洽淡業務。