1.1 什麼是 Design Pattern#
設計物件導向軟體很難,設計可重用的物件導向軟體更難。有經驗的設計師不會每次都從零開始解決問題,而是重用過去成功的解決方案。這些反覆出現在物件導向系統中的 class 與物件溝通模式,就是 Design Pattern。
Christopher Alexander 的定義:每個 pattern 描述一個在環境中反覆出現的問題,以及該問題的核心解法,使你能無限次使用它,而每次的應用方式都不完全相同。
一個 Design Pattern 包含四個基本要素:
| 要素 | 說明 |
|---|---|
| Pattern Name | 用一兩個詞描述設計問題及其解法,提升設計詞彙的抽象層次 |
| Problem | 描述何時該套用此 pattern,包含問題的背景脈絡與前提條件 |
| Solution | 描述設計中的元素、關係、職責與協作方式。不是具體實作,而是可應用於多種情境的模板 |
| Consequences | 套用 pattern 的結果與權衡,包括對彈性、擴充性、可移植性的影響 |
本書的 Design Pattern 聚焦在特定抽象層級:不是像 linked list 那樣可直接編碼重用的資料結構,也不是整個應用系統的領域設計,而是用來解決特定 context 中一般性設計問題的、可自訂的 class 與物件溝通描述。
1.2 Smalltalk MVC 中的 Design Pattern#
Model/View/Controller (MVC) 是 Smalltalk-80 中建構 UI 的經典架構,其中蘊含多個 Design Pattern:
- Observer Pattern:Model 與 View 之間透過 subscribe/notify 協定解耦。當 Model 資料變更時通知所有 View 更新,允許同一 Model 附加多個不同呈現方式的 View
- Composite Pattern:View 可以巢狀組合(CompositeView),將多個子 View 當作單一 View 操作,形成 part-whole 階層
- Strategy Pattern:View 與 Controller 的關係 — Controller 封裝了使用者輸入的回應策略,可在執行期替換不同的 Controller 來改變行為
此外,MVC 也運用了 Factory Method(指定 View 的預設 Controller class)和 Decorator(為 View 加上捲動功能)。
1.3 描述 Design Pattern 的方式#
本書採用統一的模板描述每個 pattern,包含以下章節:
| 章節 | 說明 |
|---|---|
| Intent | pattern 的目的與要解決的問題 |
| Motivation | 具體情境說明問題與解法 |
| Applicability | 何時適用,如何辨識適用情境 |
| Structure | 以圖形表示 class 結構與物件互動 |
| Participants | 參與的 class/object 及其職責 |
| Collaborations | 參與者如何協作 |
| Consequences | 權衡與影響 |
| Implementation | 實作時的注意事項與語言相關議題 |
| Sample Code | C++ 或 Smalltalk 範例 |
| Known Uses | 至少兩個來自不同領域的實際應用 |
| Related Patterns | 相關 pattern 及其差異 |
1.4 Design Pattern 目錄#
本書收錄 23 個 Design Pattern,依功能可分為三大類:
- Creational:Abstract Factory、Builder、Factory Method、Prototype、Singleton
- Structural:Adapter、Bridge、Composite、Decorator、Facade、Flyweight、Proxy
- Behavioral:Chain of Responsibility、Command、Interpreter、Iterator、Mediator、Memento、Observer、State、Strategy、Template Method、Visitor
1.5 如何組織 Design Pattern 目錄#
Design Pattern 依兩個維度分類:
Purpose(目的):
- Creational — 處理物件建立過程
- Structural — 處理 class 或 object 的組合
- Behavioral — 描述 class 或 object 如何互動與分配職責
Scope(範圍):
- Class pattern — 透過 Inheritance 處理 class 間的關係,屬於靜態(compile-time)
- Object pattern — 處理 object 間的關係,屬於動態(run-time),大多數 pattern 屬此類
Pattern 之間也存在多種關聯:常一起使用(如 Composite + Iterator)、互為替代方案(如 Prototype vs Abstract Factory)、或結構相似但意圖不同(如 Composite vs Decorator)。

Figure 1.1: Design pattern relationships
1.6 Design Pattern 如何解決設計問題#
尋找適當的物件#
物件導向設計的困難在於將系統分解為物件,需要考慮 encapsulation、granularity、dependency、flexibility 等因素。Design Pattern 幫助辨識不那麼明顯的抽象,例如:
- Strategy — 將演算法表示為物件
- State — 將狀態表示為物件
決定物件粒度#
不同 pattern 處理不同粒度的問題:
| Pattern | 粒度處理 |
|---|---|
| Facade | 將整個子系統表示為單一物件 |
| Flyweight | 支援大量細粒度物件的共享 |
| Abstract Factory / Builder | 專門負責建立其他物件 |
| Command / Visitor | 將對物件的操作本身封裝為物件 |
指定物件 Interface#
- Interface 是物件所有 operation signature 的集合,定義了物件能接收的請求
- Type 是特定 interface 的名稱;一個物件可擁有多個 type
- Dynamic binding 讓請求在 run-time 才與具體實作關聯
- Polymorphism 讓擁有相同 interface 的物件可在 run-time 互相替換
Program to an interface, not an implementation. 不要將變數宣告為具體 class 的實例,而是只依賴 abstract class 所定義的 interface。這是本書 Design Pattern 的共通主題。
Class Inheritance vs Interface Inheritance#
- Class inheritance(class 繼承):定義物件的實作,是程式碼與表示的共享機制
- Interface inheritance(subtyping):定義物件何時可替代另一物件
許多語言(如 C++)不區分兩者,但實務上這個區分非常重要。許多 Design Pattern 依賴此區分,例如 Chain of Responsibility 中的物件必須共享 type 但不需共享實作。
Inheritance vs Composition#
- Inheritance(白箱重用):靜態、compile-time 定義,父類內部對子類可見。缺點是破壞封裝,父類變動會連帶影響子類
- Object Composition(黑箱重用):動態、run-time 組合,透過 interface 互動不破壞封裝,物件可在 run-time 替換
Favor object composition over class inheritance. 設計師傾向過度使用繼承。優先使用物件組合通常能讓設計更簡單、更易重用。
Delegation#
Delegation 是讓 composition 擁有如同 inheritance 般強大重用能力的手段。接收物件將操作委託給其 delegate 物件,並將自身傳入讓 delegate 能回頭引用。
- 優點:可在 run-time 動態組合行為
- 缺點:動態、高度參數化的軟體較難理解
- 使用 delegation 的 pattern:State、Strategy、Visitor(重度依賴);Mediator、Chain of Responsibility、Bridge(較輕度使用)
Parameterized Types(泛型)#
Parameterized Types(又稱 Generics / Templates)提供第三種組合行為的方式,讓你定義 type 時不需指定所有使用的型別。與 inheritance 和 composition 的差異在於:它無法在 run-time 改變。
為變化而設計#
Design Pattern 的核心價值在於讓系統能以特定方式應對變化。常見的重新設計原因與對應的 pattern:
| 重新設計原因 | 對應 Pattern |
|---|---|
| 明確指定 class 建立物件 | Abstract Factory、Factory Method、Prototype |
| 依賴特定操作 | Chain of Responsibility、Command |
| 平台依賴 | Abstract Factory、Bridge |
| 依賴物件表示或實作 | Abstract Factory、Bridge、Memento、Proxy |
| 演算法依賴 | Builder、Iterator、Strategy、Template Method、Visitor |
| 緊耦合 | Abstract Factory、Bridge、Chain of Responsibility、Command、Facade、Mediator、Observer |
| 透過 subclassing 擴充功能 | Bridge、Chain of Responsibility、Composite、Decorator、Observer、Strategy |
| 無法方便地修改 class | Adapter、Decorator、Visitor |
書中也討論了 Application、Toolkit、Framework 三種軟體層級。Framework 強調 design reuse(設計重用)而非僅 code reuse(程式碼重用),並帶來控制反轉(inversion of control)。成熟的 framework 通常整合了多個 Design Pattern。
1.7 如何選擇 Design Pattern#
找到合適 pattern 的幾種策略:
- 閱讀 Section 1.6 了解 pattern 如何解決各類設計問題
- 瀏覽每個 pattern 的 Intent 段落,找出與問題相關者
- 研究 pattern 之間的關聯圖(Figure 1.1),循線找到相關 pattern
- 依 purpose 分類(Creational / Structural / Behavioral)縮小範圍
- 檢視你面臨的重新設計原因,對應上述列表
- 思考設計中哪些部分需要可變,找出能封裝該變化的 pattern
1.8 如何使用 Design Pattern#
套用 Design Pattern 的步驟:
- 通讀一遍:特別注意 Applicability 與 Consequences,確認 pattern 適合你的問題
- 研究結構:理解 Structure、Participants、Collaborations 中的 class 與 object 關係
- 看範例程式:透過 Sample Code 學習實作方式
- 命名參與者:在應用情境中選擇有意義的名稱(例如用
SimpleLayoutStrategy而非抽象的ConcreteStrategy) - 定義 class:宣告 interface、建立繼承關係、定義 instance variable
- 定義操作名稱:依據職責與協作關係命名,保持一致的命名慣例
- 實作:參考 Implementation 段落的提示完成實作
Design Pattern 不應被不加思考地套用。許多 pattern 透過增加間接層來獲得彈性,這會使設計更複雜或犧牲效能。只有在確實需要該彈性時才應使用。