###### tags: `無瑕的程式碼:整潔的軟體設計和架構篇` # 第 14 章:元件耦合性 ## 三大原則 ### 無環依賴原則 (ADP):在元件的依賴關係圖中不允許出現環 + **隔天早上症候群** + 終於完成某項功能回家,隔天早上卻發現壞掉了 + 因為有人比你更晚走,並且修改了你修改功能依賴的物件 + **解決方案** + **每週建置**:每週前 4 天在各自的副本開發,第 5 天再合併建置。==結果第 5 天變得很痛苦== + **解開環** #### 解開環 + **什麼是依賴環** ![](https://i.imgur.com/5c8Vszp.png) ![](https://i.imgur.com/m9cCmM0.png) + 依賴環造成改 A 壞 B,改 B 壞 C,改 C 壞 A = **工作製造機**,這時 ABC 已經可以被視為一個合併的大元件 + 解決方式 + 依賴反轉 (DIP) + 較推薦的解法 + 經常會搭配控制反轉 (IoC) 與依賴注入 (DI) ![](https://i.imgur.com/aNbnRYW.png) + 新開一個 Entity 跟 Authorizer 都共同依賴的元件 + 隨著應用程式增長,仍有可能出現環 + 為了解除環,可能會使依賴結構不斷增長 ![](https://i.imgur.com/imfrXih.png) ### 穩定依賴原則 (SDP):朝著穩定的方向進行依賴 + 高穩定度元件:變更會影響多個元件,造成巨大的工作量 ![](https://i.imgur.com/VnkSMXe.png) + 低穩定度元件:變更不會影響其他元件,工作量較少 ![](https://i.imgur.com/BAH0ZQ8.png) + 穩定性定義: + Fan-In: 輸入依賴度,外部元件依賴此元件的數量 + Fan-Out: 輸出依賴度,元件依賴的外部元件數量 + Instability: 不穩定性 I = (FO)/(FI+FO)。 + 0 代表非常穩定 + 1 代表非常不穩定 + ==穩定性高低,不代表元件好壞== + 看範例 + Ca 元件 FI = 0, FO = 2, I = 1 + Cb 元件 FI = 0, FO = 1, I = 1 + Cc 元件 FI = 3, FO = 1, I = 1/4 + Cd 元件 FI = 1, FO = 0, I = 0 + 不穩定性: Ca = Cb > Cc > Cd,==朝著穩定的方向進行依賴== ![](https://i.imgur.com/50sK2p9.png) + 如果讓高穩定性元件去依賴低穩定性元件,容易造成低穩定性元件跟著變成高穩定性元件而變得難以修改 + 解法:==DIP==,讓 UServer 這個抽象類別 I=0 的高穩定性元件,被原本的低穩定性與高穩定性元件所依賴 ![](https://i.imgur.com/JkNMXjA.png) ![](https://i.imgur.com/9erU2mj.png) ### 穩定抽象原則 (SAP):元件的抽象程度應該與元件的穩定程度一致 + SDP: 朝著穩定方向依賴 + SDP + SAP = 依賴應該「朝著抽象的方向」進行 > DIP 是一個處理類別的原則,只有抽象與不抽象,然而 SDP + SAP 表達類別可以部分抽象及部分穩定 + 抽象性的度量 + 抽象性 = (元件中抽象類別及介面的總數) / (元件中所有類別個數) + 痛苦地帶:高穩定性低抽象元件,難以擴展修改困難 + database schema: 更新它通常都很痛苦 + utility library + 可以提高抽象性以脫離痛苦地帶 + 無用地帶:高抽象程度,但卻沒有元件依賴它 + 主序列:希望元件盡量分布在主序列線上附近 ![](https://i.imgur.com/COBFHe3.png) ### 結論 上述的度量不是萬能的,但至少是個不錯的標準,希望你覺得他們有用處 ㄎㄎ ![](https://i.imgur.com/c1fD1I7.png) ### Demo + 解開依賴環 + Dependency Inversion Principle, DIP 依賴反轉 + 實體皆依賴於抽象介面 (interface) + 使用時宣告型別為抽象介面 (interface) + Inversion of Control, IOC 控制反轉 + 讓別人幫你實體化,常搭配 DI 使用 + 註冊在 IoC 容器 + 抽象工廠 + Dependency Injection, DI 依賴注入 + 再利用建構子注入 + setter 注入