☆ 迪米特法則,又叫最少知識原則,就是說,一個對象應當對其他對象有儘可能少的瞭解。
ξ 11.1 迪米特法則的各種表述
① 只與你直接的朋友們通訊;
② 不要跟“陌生人”說話;
③ 每一個軟體單位對其他的單位都只有最少的知識,而且局限於那些與本單位密切相關的軟體單位。
ξ 11.2 狹義的迪米特法則
☆ 如果兩個類不必彼此直接通訊,那麼這兩個類就不應當發生直接的相互作用。如果其中的一個類需要調用另外一個類的某一個方法,可以通過第三者轉寄這個調用。
參考下例,Someone、Friend和Stranger三個類。
Someone類有一個方法接受一個Friend類型的變數:
public class Someone
...{
public void operation1( Friend friend )
...{
Stranger stranger = friend.provide() ;
stranger.operation3() ;
}
}
所以Someone和Friend是朋友類(直接通訊的類)。
同理,Friend類持有一個Stranger類的私人對象,他們是朋友類:
public class Friend
...{
private Stranger stranger = new Stranger() ;
public void operation2()...{}
public Stranger provide()
...{
return stranger ;
}
}
在這裡,Someone類和Stranger類不是朋友類,但Someone類卻通過Friend類知道了Stranger類的存在,這顯然違反迪米特法則。
現在,我們對Someone和Friend類進行重構。首先在Friend類裡添加一個方法,封裝對Stranger類的操作:
public class Friend
...{
private Stranger stranger = new Stranger() ;
public void operation2()...{}
public Stranger provide()
...{
return stranger ;
}
public void forward()
...{
stranger.operation3() ;
}
}
然後,我們重構Someone的operation1方法,讓其調用新提供的forward方法:
public class Someone
...{
public void operation1( Friend friend )
...{
friend.forward() ;
}
}
現在Someone對Stranger的依賴完全通過Friend隔離,這樣的結構已經符合狹義迪米特法則了。
仔細觀察上述結構,會發現狹義迪米特法則一個明顯的缺點:會在系統裡造出大量的小方法,散落在系統的各個角落。這些方法僅僅是傳遞間接的調用,因此與系統的商務邏輯無關,當設計師試圖從一張類圖看出總體的架構時,這些小的方法會造成迷惑和困擾。遵循迪米特法則會使一個系統的局部設計簡化,因為每一個局部都不會和遠距離的對象有直接關聯。但是,這也會造成系統的不同模組之間的通訊效率降低,也會使系統的不同模組之間不容易協調。
結合依賴倒轉原則,我們對代碼進行如下重構來解決這個問題,首先添加一個抽象的Stranger類,使Someone依賴於抽象的“Stranger”角色,而不是具體實現:
public abstract class AbstractStranger
...{
abstract void operation3() ;
}
然後,讓Stranger從該類繼承:
public class Stranger extends AbstractStranger
...{
public void operation3() ...{}
}
隨後,我們重構Someone使其依賴抽象的Stranger角色:
public class Someone
...{
public void operation1( Friend friend )
...{
AbstractStranger stranger = friend.provide() ;
stranger.operation3() ;
}
}
最後,我們重構Friend的provide方法,使其返回抽象角色:
public class Friend
...{
private Stranger stranger = new Stranger() ;
public void operation2()...{}
public AbstractStranger provide()
...{
return stranger ;
}
}
現在,AbstractStranger成為Someone的朋友類,而Friend類可以隨時替換掉AbstractStranger的實作類別,Someone不再需要瞭解Stranger的內部實現細節。是重構後的UML類圖:
ξ 11.3 迪米特法則與設計模式
對迪米特法則的最好描述,可以參考門面模式和調停者模式。
ξ 11.4 廣義迪米特法則
☆ 在將迪米特法則運用到系統的設計中時,應注意的幾點:
① 在類的劃分上,應該建立有弱耦合的類;
② 在類的結構設計上,每一個類都應當盡量降低成員的存取權限;
③ 在類的設計上,只要有可能,一個類應當設計成不變類;
④ 在對其他類的引用上,一個對象對其它對象的引用應當降到最低;
⑤ 盡量降低類的存取權限;
⑥ 謹慎使用序列化功能;
⑦ 不要暴露類成員,而應該提供相應的訪問器(屬性)。