設計模式六大原則 - 迪米特法則
迪米特法則有很多種說法,比如:一個類應該應該對其他類盡可能了解得最少;類只與直接的朋友通信等等。但是其最終目的只有一個,就是讓類間解耦。
定義
迪米特法則:Law Of Demeter,LoD。
也被稱為最少知識原則,Least Knowledge Principle,LKP。
就是說一個對象應該對其他對象保持最少的了解。正如最少知識原則這個定義一樣,一個類應該對其耦合的其他類或所調用的類知道得最少。所耦合的類內部無論如何復雜,怎么實現的我都不需要知道,我只調用你public出來的這些方法,其他都不用知道。
另外可以解釋一下開頭提到的只與直接的朋友通信,什么叫直接的朋友呢?我們繼續看。
舉個例子
光看定義可能無法完全理解它所表達的含義,以及在什么場景下才需要使用這個迪米特法則。現在我們就來舉個“栗子”。
現在市面上各種人脈書上很多都會提到“六度人脈”這個理論,這個理論說的是你與世界上任何一個人中間只隔了六個人。也就是說你想找任何一個人,無論這個人是政界要人,還是商界巨鱷,抑或是明星名人,你最多只通過六個人就可以聯系到他(想想還有點小激動呢-_-#)。
我們暫且不論這個理論是對是錯,在現實生活中我們也經常遇到這樣的情況。比如你想辦一件事情,但是憑借你的能力是做不到的,而你周圍的朋友也無法幫你辦到。但是恰好你有一個朋友認識有另外一個朋友可以辦得成此事,那么你只有拜托你這位朋友中間牽線搭橋,讓他的朋友幫你辦好此事。
在這個例子中,我們就暫且定義你為A,你的朋友為B,你朋友的朋友為C好了。
反面教材
我們先來看看表達此種關系的UML類圖:
實現代碼如下:
1.類A和類B是好朋友,能找到類B來幫忙:
public classA{
public String name;
publicA(String name){
this.name = name;
}
publicBgetB(String name){
return new B(name);
}
publicvoidwork(){
B b = getB("李四");
C c = b.getC("王五");
c.work();
}
}
2.類B和類C是好朋友,能知道類C來幫忙:
public classB{
private String name;
publicB(String name){
this.name = name;
}
publicCgetC(String name){
return new C(name);
}
}
3.類C能夠辦成此事:
public classC{
public String name;
publicC(String name){
this.name = name;
}
publicvoidwork(){
System.out.println(name + "把這件事做好了");
}
}
4.場景類
public classClient{
publicstaticvoidmain(String[] args){
A a = new A("張三");
a.work();
}
}
運行結果如下:
王五把這件事做好了
上面的輸出雖然是把事情成功辦好了,但是仔細看業務邏輯明顯是不對的。A和C又不是好朋友,為什么在類A中會出現類C呢?他們又互相不認識。
看到這里很多人都會明白,這種場景在實際開發中是非常常見的一種情況。對象A需要調用對象B的方法,對象B有需要調用對象C的方法……就是常見的getXXX().getXXX().getXXX()……類似于這種代碼。如果你發現你的代碼中也有這樣的代碼,那就考慮下是不是違反迪米特法則,是不是要重構一下了。
正確例子
為了符合迪米特法則,也為了讓業務邏輯能夠說得通,我們把上面的例子稍微修改一下。
UML類圖如下:
代碼如下:
1.類A和類B是好朋友,能找到類B來幫忙:
public classA{
public String name;
publicA(String name){
this.name = name;
}
publicBgetB(String name){
return new B(name);
}
publicvoidwork(){
B b = getB("李四");
b.work();
}
}
2.類B和類C是好朋友,能知道類C來幫忙:
public classB{
private String name;
publicB(String name){
this.name = name;
}
publicCgetC(String name){
return new C(name);
}
publicvoidwork(){
C c = getC("王五");
c.work();
}
}
3.類C能夠辦成此事:
public classC{
public String name;
publicC(String name){
this.name = name;
}
publicvoidwork(){
System.out.println(name + "把這件事做好了");
}
}
4.場景類
public classClient{
publicstaticvoidmain(String[] args){
A a = new A("張三");
a.work();
}
}
運行結果如下:
王五把這件事做好了
上面代碼只是修改了下類A和B的work方法,使之符合了迪米特法則:
- 類A只與最直接的朋友類B通信,不與類C通信;
- 類A只調用類B提供的方法即可,不用關心類B內部是如何實現的(至于B是怎么調用的C,這些A都不用關心)。
總結
迪米特法則的目的是讓類之間解耦,降低耦合度。只有這樣,類的可復用性才能提高。
但是迪米特法則也有弊端,它會產生大量的中轉類或跳轉類,導致系統的復雜度提高。
所以我們不要太死板的遵守這個迪米特法則,在系統設計的時候,在弱耦合和結構清晰之間反復權衡。盡量保證系統結構清晰,又能做到低耦合。
來自:https://tianweili.github.io/2015/02/12/設計模式六大原則-迪米特法則/