本章主軸#

學設計模式有兩種方式:學會把模式套到合適的情境,或學會模式背後的原則與策略。本章專注在後者——這些原則才是讓你在沒有現成模式可套時,也能想出「像模式般優雅」的解法的能力來源。

開放封閉原則(OCP, Open-Closed Principle)#

模組、方法、類別應對「擴充」開放,對「修改」封閉。

由 Bertrand Meyer 提出。意思是:設計軟體時,要讓未來能加新功能而不必改動既有程式

100% 達成 OCP 通常不可能,但作為目標,它指引我們做出更耐改的設計。Bridge 就是 OCP 的典型示範——加新實作完全不用動既有類別。

從脈絡設計(Designing from Context)#

延續 Alexander 的思想。Bridge 模式是最佳範例:

  • 設計 Implementation 介面時,要看 Abstraction 衍生類別會怎麼用它
  • 介面從「服務需求」反推回來決定,而不是先做完才看怎麼配

依賴倒置原則(Dependency Inversion Principle)#

  • 高層模組不應依賴低層模組——雙方都應依賴抽象
  • 抽象不應依賴細節——細節應依賴抽象

Liskov 替換原則(Liskov Substitution Principle)#

衍生類別必須支援基底類別的所有行為。

作者更進一步:使用方根本不該察覺有衍生發生。子類別不應在基底介面之外再加新公開方法,且基底必須是該概念完整的規格。

「機會 ≠ 必須立刻採用」#

模式提醒我們可能的變動點,但不代表現在就要為這些變動寫程式碼。

透過模式建立的良好抽象,就足以容納未來的變動——即使那是當初沒預料到的變動。

用脈絡決定實作#

以 Abstract Factory 為例,可有多種實作方式:

實作方式取捨
為每個家族做一個衍生類經典做法,遵守 OCP,但較繁瑣
單一物件加 switch不嚴格 OCP,但簡單,所有規則集中一處
配置檔 + switch較具彈性,仍要改程式
配置檔 + 動態類別載入最具彈性,新類別不需改程式

比較不同方案時,不要問「哪個比較好」,要問「在什麼情境下哪一個比較好」「哪個情境最像我的問題」。

這個小小的思考切換,會讓你考慮到變動性與可擴展性,並避免太快收斂在第一個答案。

Adapter 與 Facade 都是脈絡型模式#

  • Adapter 必須依被適配到的介面而定,介面不存在就無法定義
  • Facade 的介面常常隨著系統發展逐步成形,每個新的使用者都會塑造它

作者一度以為「Adapter / Facade 一定不是 seniormost」。後來發現有些系統必須符合既定介面,這時 Facade 或 Adapter 反而會是最外層。

封裝變動的原則#

作者觀察自己的設計:繼承很少超過兩層;只在 Decorator 那種模式下會有第三層。理由:

我從不讓一個類別同時承載兩個會獨立變動的議題,除非這兩者本就緊密耦合。

各模式封裝變動的方式:

  • Bridge:封裝實作的變動
  • Abstract Factory:封裝「該建立哪一群物件」的變動
  • Adapter:把不同介面統一,配合其他模式的變動需求
  • Facade:通常不是封裝變動,但同一介面包不同子系統時,可順便達成

模式不只在封裝變動,也定義了物件之間的關係——例如 Bridge 同時定義抽象與實作的兩個變動軸如何關聯。

抽象類別 vs 介面#

表面差異#

抽象類別可包含共同狀態與行為;介面只能定義方法。Java、C# 只允許單一繼承,因此選錯就回不去。

設計層差異#

  • 抽象類別:把相關實作收攏(focus on encapsulating implementations),仍可遵循依賴倒置
  • 介面:思考「使用方需要什麼樣的介面」,可拆得更細、更精簡(thin interface)

兩者不是一個比另一個好。可先用介面定義出最小契約,再用抽象類別實作以共享預設行為。

健康的懷疑(Healthy Skepticism)#

模式是經驗的提煉,不是真理。

它必須與真實世界資料對照後使用。

模式可能犯下的錯誤:

錯誤描述
表面化(Superficiality)對下層情況了解不深,太快選定模式
偏見(Bias)過度相信模式,把所有資料都用它來解讀
選錯(Selection)不熟悉適用脈絡,選了錯誤模式
誤診(Misdiagnosis)對整套模式不夠熟悉,導致誤判
削足適履(Fit)為了讓現實符合模式,刻意忽略例外

「對的」模式存在於問題本身,不是被你硬套上去。實作方式也應由問題的限制決定,而不是模式書上長什麼樣。

本章重點#

原則摘要
OCP開放擴充、封閉修改
依賴倒置高低層皆依賴抽象
封裝變動找出變動軸並隔離
健康懷疑模式只是工具,不是真理