今天,我們講最后一個設計原則:迪米特法則。盡管它不像 SOLID、KISS、DRY 原則那樣,人盡皆知,但它卻非常實用。
利用這個原則,能夠幫我們實現代碼的“高內聚、松耦合”。今天,我們就圍繞下面幾個問題,並結合兩個代碼實戰案例,來深入地學習這個法則。
- 什么是“高內聚、松耦合”?
- 如何利用迪米特法則來實現“高內聚、松耦合”?
- 有哪些代碼設計是明顯違背迪米特法則的?對此又該如何重構?
話不多說,讓我們開始今天的學習吧!
何為“高內聚、松耦合”?
“高內聚、松耦合”是一個非常重要的設計思想,能夠有效地提高代碼的可讀性和可維護性,縮小功能改動導致的代碼改動范圍。
上,在前面的章節中,我們已經多次提到過這個設計思想。
很多設計原則都以實現代碼的“高內聚、松耦合”為目的,比如單一職責原則、基於接口而非實現編程等。
實際上,“高內聚、松耦合”是一個比較通用的設計思想,可以用來指導不同粒度代碼的設計與開發,
比如系統、模塊、類,甚至是函數,也可以應用到不同的開發場景中,比如微服務、框架、組件、類庫等。
為了方便我講解,接下來我以“類”作為這個設計思想的應用對象來展開講解,其他應用場景你可以自行類比。
在這個設計思想中,“高內聚”用來指導類本身的設計,“松耦合”用來指導類與類之間依賴關系的設計。
不過,這兩者並非完全獨立不相干。高內聚有助於松耦合,松耦合又需要高內聚的支持。
那到底什么是“高內聚”呢?
所謂高內聚,就是指相近的功能應該放到同一個類中,不相近的功能不要放到同一個類中。
相近的功能往往會被同時修改,放到同一個類中,修改會比較集中,代碼容易維護。
實際上,我們前面講過的單一職責原則是實現代碼高內聚非常有效的設計原則。
我們再來看一下,什么是“松耦合”?
所謂松耦合是說,在代碼中,類與類之間的依賴關系簡單清晰。
即使兩個類有依賴關系,一個類的代碼改動不會或者很少導致依賴類的代碼改動。
實際上,我們前面講的依賴注入、接口隔離、基於接口而非實現編程,以及今天講的迪米特法則,都是為了實現代碼的松耦合。
最后,我們來看一下,“內聚”和“耦合”之間的關系。
前面也提到,“高內聚”有助於“松耦合”,同理,“低內聚”也會導致“緊耦合”。
關於這一點,我畫了一張對比圖來解釋。圖中左邊部分的代碼結構是“高內聚、松耦合”;右邊部分正好相反,是“低內聚、緊耦合”。
圖中左邊部分的代碼設計中,類的粒度比較小,每個類的職責都比較單一。相近的功能都放到了一個類中,不相近的功能被分割到了多個類中。
這樣類更加獨立,代碼的內聚性更好。因為職責單一,所以每個類被依賴的類就會比較少,代碼低耦合。一個類的修改,只會影響到一個依賴類的代碼改動。
我們只需要測試這一個依賴類是否還能正常工作就行了。
圖中右邊部分的代碼設計中,類粒度比較大,低內聚,功能大而全,不相近的功能放到了一個類中。
這就導致很多其他類都依賴這個類。當我們修改這個類的某一個功能代碼的時候,會影響依賴它的多個類。
我們需要測試這三個依賴類,是否還能正常工作。這也就是所謂的“牽一發而動全身”。
除此之外,從圖中我們也可以看出,高內聚、低耦合的代碼結構更加簡單、清晰,相應地,在可維護性和可讀性上確實要好很多。
“迪米特法則”理論描述
迪米特法則的英文翻譯是:Law of Demeter,縮寫是 LOD。
單從這個名字上來看,我們完全猜不出這個原則講的是什么。
不過,它還有另外一個更加達意的名字,叫作最小知識原則,英文翻譯為:The Least Knowledge Principle。