My friends, my life, my style - James S.F. Hsieh

2/17/2009

Coupling and Decoupling

軟體工程的耦合與相依有許多種形式, 而這些相依是不可能完全消除的, 因為唯有相依才能合作並達成目的, 以下這些相依是幾個常見相依關係

  • 編譯相依: 編譯時, 需要參考特定型別的定義或函數才能正常編譯
  • 行為相依: 執行時, 需要仰賴特定的流程, 協定, 或前置狀態才能正常運作
  • 模組相依: 執行時, 需要仰賴特定模組的服務才能正常運作
  • 潛在相依: 在軟體未來的發展中, 因為功能擴充或是程式誤用而產生的相依

以軟體工程來說, 單向相依比雙向來的好, 沒有相依比有相依來的好, 如果非得要有相依性, 那就將它收斂於特定少數的點, 這點其實跟 Dependency Inversion Principle 有著相同的的精神, 以下是 DIP 的想法

High level modules should not depend upon low level modules. Both should depend upon abstractions. Abstractions should not depend upon details. Details should depend upon abstractions.

DIP 耐人尋味的地方在於, 在過去軟體設計經驗中, 高階的模組相依低階的模組是天經地義的, 相反的, 不希望低階模組相依高階模組則是個較為容易達成的理想 (雖然台灣多數的軟體公司完全不考慮這些問題), 而 DIP 則認為上述的相依性仍然可以剔除, 其實, 關鍵在於利用軟體工程做常用的技法, 增加一層間接性, 然後將所有的相依性封裝於這層見間性上 - 其實就是所謂的 抽象界面

其實, COM, Java 或是 .NET 中的介面, 就可以做到這樣的理想, 但是, 不是只要有定義了介面, 這件事情就可以自然的發生, 界面的設計的抽象性才是成功的關鍵因素

關於上述的相依性, 可以用幾種技巧來達到 Decoupling 的效果

  • 編譯相依: Pimpl, 編譯防火牆, 減少型別的濫用, 妥善規劃 Header file 並免非必要的宣告汙染
  • 行為相依: 將 Class分解成小的單元, 將 Inheritance 轉化成 composition , 定義抽象界面
  • 模組相依: 剔除非必要引用的模組, 延遲載入 Delay load
  • 潛在相依: 利用編譯手法來剔除未定義或非必要的程式行為, 只提供有限度的自由

Dependency Inversion Principle