A. 高階模組不該依賴低階模組,兩者都該依賴抽象;B. 抽象不該依賴細節,細節該依賴抽象。這是 OO 設計與程序式設計最根本的分界——被稱為「良好 OO 設計的標誌」,也是分層架構與框架的基石。它跟 DI 不同:DIP 是原則,DI 是達成它的工法之一。
🧠 When to Use
TIP
訊號:核心的商業策略碼裡直接 new 出某個資料庫 / 硬體 / 第三方類別;想把高階邏輯搬到另一個情境重用,卻被低階細節綁死拖不動。
- 高階策略(你最想重用的部分)目前直接依賴低階實作。
- 想建立乾淨的分層 / 框架:讓框架不被綁在特定實作上,使用者靠實作介面來擴展。
- 低階細節(DB、UI、裝置、網路)易變,想把易變性擋在抽象之外。
⚖️ Structure & Variants
所有權反轉 — Button / Lamp
// ❌ 天真設計:Button 直接依賴具體 Lamp,換不了裝置
class Button(private val lamp: Lamp) {
fun poll() { if (pressed()) lamp.turnOn() }
}
// ✅ 引入由『高階模組』定義的抽象,Lamp 去實作它
interface SwitchableDevice { fun turnOn(); fun turnOff() }
class Button(private val device: SwitchableDevice) { // 依賴抽象
fun poll() { if (pressed()) device.turnOn() }
}
class Lamp : SwitchableDevice { /* ... */ } // 細節依賴抽象- 關鍵:介面
SwitchableDevice由使用它的 Button 那一層擁有,而非 Lamp 那一層——這是「所有權反轉(ownership inversion)」,也就是 Hollywood 原則「Don’t call us; we’ll call you」。 - 命名要反映高階語境:叫
SwitchableDevice比叫ILamp好,因為 Button 不只為了控制燈泡而存在。
把演算法從硬體上剝下來 — Regulate
// ❌ 調節策略(高階)綁死在硬體 I/O 位址(低階)
fun regulate(minTemp: Double, maxTemp: Double) {
while (true) {
while (input(THERMOSTAT) > minTemp) wait(1); output(FURNACE, ENGAGE)
while (input(THERMOSTAT) < maxTemp) wait(1); output(FURNACE, DISENGAGE)
}
}
// ✅ 依賴抽象,同一套演算法能配任何溫度計 + 加熱器
interface Thermometer { fun read(): Double }
interface Heater { fun engage(); fun disengage() }
fun regulate(t: Thermometer, h: Heater, minTemp: Double, maxTemp: Double) {
while (true) {
while (t.read() > minTemp) wait(1); h.engage()
while (t.read() < maxTemp) wait(1); h.disengage()
}
}- 高階策略完全與硬體無關,可重用於暖爐、熱水器……任何實作這兩個介面的組合。
經驗法則(與其例外)
- 不讓變數持有具體類別的參考;不繼承具體類別;不覆寫父類已實作的方法。
- 但這是針對易變的具體類別。像
String這種幾乎不會變的具體類別,依賴它並無大礙——別把法則當教條。
⚠️ Misuse & Anti-patterns
- 抽象放錯邊:介面由低階模組定義(
ILamp),高階去配合——那只是換個名字的耦合,沒有真正反轉所有權。介面該由高階模組擁有。 - 對不變的細節也硬抽象:為
String、Int這類穩定型別套 DIP,只是徒增層次。原則瞄準的是易變的具體依賴。 - 把 DIP 當成 DI:注入只是傳遞依賴的手段;沒有先把依賴指向抽象、沒有反轉所有權,光注入具體類別不算 DIP。
🔑 Takeaways
- 高階與低階都依賴抽象;細節依賴抽象——這是 OO 相對程序式設計的分界。
- 「反轉」不只是方向反轉,更是所有權反轉:高階定義介面,低階實作(Hollywood 原則)。
- 是分層架構與框架的基石;DI/IoC 是把它落地的工法,別把兩者混為一談。
No notes yet — jot your takeaways or Q&A here.