DIP 是軟體架構中最具深度的原則之一,它告訴我們: 「靈活的系統,其原始碼依賴關係應該只涉及抽象(Abstract),而不涉及具體(Concrete)。」
在靜態型別語言(如 Java)中,這意味著 import, use, include 指令只應該指向包含介面(Interface)或抽象類別(Abstract
Class)的模組,而不該指向具體的實作類別。
一、穩定抽象 vs. 易變具體#
為什麼要依賴抽象?
- 穩定性(Stable): 抽象介面通常比具體實作穩定。修改一個介面通常意味著要修改所有實作;但修改一個實作,通常不需要修改介面
- 易變性(Volatile): 具體類別包含了運作細節,這正是系統中變動最頻繁的部分
架構師的目標是:依賴那些穩定的東西,避開那些易變的東西。
二、DIP 的四大編碼規範#
為了落實 DIP,作者提出了四個具體編碼建議:
| 規範 | 說明 |
|---|---|
| 不參考易變的具體類別 | 改為參考抽象介面;促成「抽象工廠」模式的使用 |
| 不從易變的具體類別衍生 | 繼承是最強、難修改的依賴關係;應謹慎使用 |
| 不覆寫具體函數 | 具體函數包含依賴,覆寫後原始依賴仍存在;應宣告為抽象 |
| 不提到任何具體和易變名稱 | 上述原則的總結 |
三、解決物件建立問題:抽象工廠#
這條原則最難遵守的地方在於「物件建立」。
為執行程式,我們終究需要 new 一個具體物件實例(這會產生對具體類別的依賴)。
為了解決這矛盾,我們使用 抽象工廠模式 (Abstract Factory Pattern)。
- 控制流程:
Application➡️ 呼叫 ➡️ServiceFactoryImpl➡️ 建立 ➡️ConcreteImpl - 依賴方向:
Application➡️ 依賴 ➡️ServiceFactory(介面) - 結果: 原始碼的依賴與控制流程反向。這邊界將系統切為兩半:抽象層(高層)與具體層(低層)

Figure 11.1: Use of the Abstract Factory pattern
四、Main 元件:必要的髒污#
我們無法 100% 消除對具體類別的依賴。總有人負責啟動系統並建立第一個物件。
這個地方就是 Main 函式。
- 集中髒污:
Main是系統中違反 DIP 的特例。它負責實例化所有的工廠、策略與具體類別,
然後將它們交給高層的抽象模組 - 架構意義: 將所有「骯髒」依賴集中在
Main這邊界上,
從而讓系統其他部分保持潔淨(只依賴抽象)
DIP 是架構的基礎。
如果依賴方向沒有反轉(指向抽象),高層策略就會受制於低層細節,導致系統脆弱且難以維護。