最少知識原則(Least Knowledge Principle),或者稱迪米特法則(Law of Demeter),是一種面向對象程序設計的指導原則,它描述了一種保持代碼松耦合的策略。其可簡單的歸納為:
Each unit should have only limited knowledge about other units: only units "closely" related to the current unit.
每個單元對其他單元只擁有有限的知識,只了解與當前單元緊密聯系的單元;
再簡潔些:
Each unit should only talk to its friends; don't talk to strangers.
每個單元只能和它的 "朋友" 交談,不能和 "陌生人" 交談;
更簡潔些:
Only talk to your immediate friends.
只和自己直接的 "朋友" 交談。
應用到面向對象的程序設計中時,可描述為 "類應該與其協作類進行交互但無需了解它們的內部結構"。
A class should interact directly with its collaborators and be shielded from understanding their internal structure.
迪米特法則(Law of Demeter)由 Northeastern University 的 Ian Holland 在 1987 年提出,"Law of Demeter" 名稱是來自當時正在進行的一項研究 "The Demeter Project"。
Demeter = Greek Goddess of Agriculture; grow software in small steps.
在 2004 年,Karl Lieberherr 在其論文 "Controlling the Complexity of Software Designs" 中將 LoD 的定義由 "Only talk to your friends" 改進為:
Only talk to your friends who share your concerns.
改進后的原則稱為 LoDC(Law of Demeter for Concerns),它為軟件設計帶來了兩個主要的益處:
It leads to better information hiding.
It leads to less information overload.
即,更好的信息隱藏和更少的信息重載。LoDC 原則在面向方面的軟件開發(AOSD:Aspect-Oriented Software Development)中有著良好的應用。
最少知識原則在面向對象編程中的應用
在 "Law of Demeter" 應用于面向對象編程中時,可以簡稱為 "LoD-F:Law of Demeter for Functions/Methods"。
對于對象 O 中的一個方法 m ,m 方法僅能訪問如下這些類型的對象:
- O 對象自身;
- m 方法的參數對象;
- 任何在 m 方法內創建的對象;
- O 對象直接依賴的對象;
具體點兒就是,對象應盡可能地避免調用由另一個方法返回的對象的方法。
現代面向對象程序設計語言通常使用 "." 作為訪問標識,LoD 可以被簡化為 "僅使用一個點(use only one dot)"。也就是說,代碼 a.b.Method() 違反了 LoD,而 a.Method() 則符合 LoD。打個比方,人可以命令一條狗行走,但是不應該直接指揮狗的腿行走,應該由狗去指揮它的腿行走。
你是否見過類似下面這樣兒的代碼?
1 public Emailer(Server server) {…} // taking a server in the constructor 2 public void sendSupportEmail(String message, String toAddress) { 3 EmailSystem emailSystem = server.getEmailSystem(); 4 String fromAddress = emailSystem.getFromAddress(); 5 emailSystem.getSenderSubsystem().send(fromAddress, toAddress, message); 6 }
上面這個設計有幾點問題:
- 復雜而且看起來不必要。Emailer 與多個它可能不是真的需要的 API 進行交互,例如 EmailSystem。
- 依賴于 Server 和 EmailSystem 的內部結構,如果兩者之一進行了修改,則 Emailer 有可能被破壞。
- 不能重用。任何其他的 Server 實現也必須包含一個能返回 EmailSystem 的 API。
除了上面這幾個問題之外,還有一個問題是這段代碼是可測試的嗎?你可能會說肯定可測啊,因為這個類使用了依賴注入(Dependency Injection),我們可以模擬 Server、EmailSystem 和 Sender 類。但真正的問題是,除了多出了這些模擬代碼,任何對 API 的修改都將破壞所有的測試用例,使得設計和測試都變得非常脆弱。
解決上述問題的辦法就是應用最少知識原則,僅通過構造函數注入直接依賴的對象。Emailer 無需了解是否 Server 類包含了一個 EmailSystem,也不知道 EmailSystem 包含了一個 Sender。
1 public Emailer(Sender sender, String fromAddress) {…} 2 public void sendSupportEmail(String message, String toAddress) { 3 sender.send(fromAddress, toAddress, message); 4 }
這個設計較為合理些。現在 Emailer 不再依賴 Server 和 EmailSystem,而是通過構造函數得到了所有的依賴項。同時 Emailer 也變得更容易理解,因為所有與其交互的對象都顯式的呈現出來。
Emailer 與 Server 和 EmailSystem 也達到了解耦合的效果。Emailer 不再需要了解 Server 和 EmailSystem 的內部結構,任何對 Server 和 EmailSystem 的修改都不再會影響 Emailer。
而且,Emailer 的變得更易被復用。如果切換到另外一個環境中時,僅需實現一個不同的 Sender 即可。
對于測試而言,現在我們僅需模擬 Sender 依賴即可。
應用最少知識原則優點和缺點
優點:遵守 Law of Demeter 將降低模塊間的耦合,提升了軟件的可維護性和可重用性。
缺點:應用 Law of Demeter 可能會導致不得不在類中設計出很多用于中轉的包裝方法(Wrapper Method),這會提升類設計的復雜度。
面向對象設計的原則
參考資料
- Principle of Least Knowledge
- Demeter: Aspect-Oriented Software Development
- Law of Demeter
- Controlling the Complexity of Software Designs
- Introducing Demeter and its Laws
- The Paperboy, The Wallet, and The Law Of Demeter
- Principle of Least Knowledge
- Loose Coupling with Demeter
- An Empirical Validation of the Benefits of Adhering to the Law of Demeter
本文《最少知識原則(Least Knowledge Principle)》由 Dennis Gao 原創并發表自博客園,未經作者本人同意禁止任何形式的轉載,任何自動或人為的爬蟲行為均為耍流氓。
文章列表
留言列表