上一篇談到五大設計原則
今天再來補充一下兩個常用到的概念(姑且讓我這樣稱呼)
一個叫做*“迪米特法則”*
另一個是*“組合/聚合復用原則”*
為什麼要介紹這兩個設計概念呢?
賣個關子最後再做說明吧
迪米特法則(Law of Demeter)
各單元對其他單元所知應當有限
(又稱為最少知識原則)
物件導向觀念,在一個類的方法中只給使用自己定義的方法、傳入引數的方法、自建物件之方法或實例擁有物件之方法
舉例
在『Clean Code』一書中
Martin大師舉了一個來自Apache專案裏的一段代碼來說明
final String outputDir = ctxt.getOptions().getScritchDir().getAbsolutePath();
如上例有人說若是一段程式有很多的dot
那就很有可能不滿足迪米特法則
立馬將它拆開
Options option = cxtx.getOptions();
File file = option.getScratchDir();
final String outputDir = file.getAbsolutePath();
但在書中說這還是違反迪米特法則
所以關鍵不是判斷dot
而是不應該“跟陌生人講話”
對於這段程式來說option file都是陌生人
程式本身不應該知道他們而是應該直接用ctxt來處理
那再修改一下如下
final String outputDir = ctxt.getAbsolutePathOfScratchDirectoryPath();
那這樣是不是就ok呢?
還沒有喔
因為大師說這會使ctxt暴露出非必要的方法資訊
若是繼續往下看這個outputDir是為了組出一個BufferedOutputStream
所以在修改一下
BufferedOutputStream bos = ctxt.createScratchFileStream(classFileName);
寫了那麼多大師的話
那現在就我自己的領會把它簡化整理一下
1.在一個方法中不要使用陌生人的方法(不要用朋友的物件這是不道德的,要用就自己new一個來用)
2.不要隨便return一個物件(暴露過多物件只會讓不道德的人拿去用)
但可以return資料結構或是自己本身(例如java裡的bean或是使用builder模式時)
以上若盡量遵守我想迪米特法則應該就不會違背了!
組合/聚合復用原則(Composition/Aggregation Reuse Principle)
盡量使用組合/聚合,盡量不要使用繼承
(組合/聚合優於繼承)
物件導向的概念,若要重複使用一個類時,應該優先考慮使用成員屬性或是成員屬性的陣列來表示
對於繼承(is-a)來說,是一個強的擁有關係
組合/聚合(has-a)來說,是一個弱的擁有關係
用UML圖來表示繼承時會如下圖
表示組合與聚合會如下圖
舉例
例如設計一個員工系統時,一家公司可能會有不少職位
例如:工讀生、雇員、正職員工、經理、主管、董事長等等
若是以繼承的角度來看,會設計一位員工類
再由其他不同的職位去繼承他達到復用
但是這樣會有一個問題
若是今天公司有一個特別的任務
要讓一位正職員工身兼另一個新的研發團隊的專案經理
這樣對這位員工來說
對於原部門是一位正職員工,對於新的團隊卻是專案經理
那目前現有的架構就不能表達了
這時候就要用組合和聚合來解決問題
多新增一個抽象類或是介面(這裡稱作角色)
並利用各職務去實作這個角色
因此一位員工可以擁有多種角色
如此就可以滿足這樣的需求了
由此可知在設計架構時盡量多用組合/聚合是比用繼承來的好低~
最後來回答一下開頭的問題
我自己的認知是這兩個概念是凌駕在上一篇五大原則之上
其目的是讓我們更容易去嗅出程式碼的“壞味道”
讓工程師能及早重構這樣的程式並使其變得更易擴展更易維護
以整體增強系統的壯健性!