什麼是物件導向(OO)?教科書常說它是「真實世界的模擬」,或用三特質定義:封裝、繼承、多型
但從架構師來看,前兩特質非 OO 獨有,唯有第三個特質——多型,才是 OO 賦予架構師的超能力。

一、重新檢視 OO 的三大特質#

1. 封裝 (Encapsulation)#

  • 定義: 隱藏資料與實作細節,僅暴露介面
  • 事實: OO 沒有發明封裝。
    早期的 C 透過 header files (.h) 和實作檔 (.c) 就能達成完美的封裝。
    反而是許多 OO 語言(如 Java, C++)破壞了部分封裝性
    (因得把 private 成員宣告在 header 裡)
  • 結論: 封裝不是 OO 的獨門絕技

2. 繼承 (Inheritance)#

  • 定義: 在封閉範圍內重新宣告一組變數和函式
  • 事實: C 也可透過 struct 的記憶體佈局模擬繼承。
    但 OO 確實讓繼承變更容易、方便
  • 結論: OO 優化了繼承,但這不是變革性創新

3. 多型 (Polymorphism)#

  • 定義: 透過統一的介面操作不同物件
  • 本質: 函式指標(Function Pointers) 的應用
  • 貢獻: OO 出現前,用函式指標非常危險(需手動維護,易產生難追查的 Bug)。
    OO 將多型變安全且方便,成為隨手可得的工具
  • 結論: OO 的真正威力所在

二、多型的架構力量:依賴反轉#

為什麼多型如此重要?因它允許我們打破傳統「控制流程」與「原始碼依賴」間的鎖鏈。

1. 傳統結構 (無多型)#

  • 控制流程: 高層呼叫低層模組(Main ➡️ High Level ➡️ Low Level)
  • 依賴關係: 原始碼依賴方向緊貼著控制流程。呼叫者必須 importinclude 被呼叫者
  • 後果: 高層策略被迫依賴低層細節,導致高層策略無法獨立於細節變更
flowchart LR
    subgraph 傳統結構
        M1[Main] -->|呼叫| HL1[High Level]
        HL1 -->|呼叫| LL1[Low Level]
        M1 -.->|依賴| HL1
        HL1 -.->|依賴| LL1
    end

2. 多型結構 (依賴反轉)#

透過多型(介面),我們可以反轉依賴方向:

  • 控制流程: 仍是 High Level ➡️ Low Level
  • 依賴關係: Low 實作 High Level 定義的介面,因此 Low 依賴 High Level
  • 結果: 高層策略不再依賴低層細節,而是低層細節依賴高層策略
flowchart LR
    subgraph 多型結構
        HL2[High Level] -->|呼叫| I[Interface]
        LL2[Low Level] -.->|實作/依賴| I
    end

    style I fill:#fff3cd,stroke:#856404
    style HL2 fill:#d4edda,stroke:#155724
    style LL2 fill:#cce5ff,stroke:#004085

OO 的真正威力在於多型。 它讓架構師能控制依賴方向,實現「插件架構」——讓低層細節成為高層策略的外掛。

Figure 5.3: The database and the user interface depend on the business rules