GoF(Gang of Four)的《Design Patterns》將 23 種經典設計模式分為三大類(創建型、結構型、行為型)。軟體工程界與許多經典著作(如 Martin Fowler 的重構書籍、Refactoring.guru、以及各種架構指南)早已將每種模式歸納出明確的適用情境(Use Cases)與解決的問題。
以下為您系統化整理這 23 種設計模式的適用情境:
一、 創建型模式 (Creational Patterns)
主要用於處理物件的建立機制,將「物件的建立與使用」解耦。
| 設計模式 | 核心目的 | 適合情境 |
| Simple Factory (非 GoF 23式,但常與之並列) | 封裝物件建立邏輯 | 建立邏輯簡單、類型數量有限,呼叫端不想直接 new 具體類別時。 |
| Factory Method (工廠方法) | 子類別決定要實例化哪一個類別 | 類別無法預期必須建立的物件類別(或希望由子類別來決定具體型別),例如框架中的插件機制。 |
| Abstract Factory (抽象工廠) | 建立一系列相關或相依物件的介面 | 系統需要獨立於其產品的建立、組合和表示時,且產品家族需要一起使用(例如支援多種 UI 主題或資料庫介面)。 |
| Builder (建造者模式) | 分步驟建立複雜物件 | 物件包含許多繁複的屬性,且建構過程必須分步驟進行,或需要產生不同表示法的複雜物件(避免過長的建構子參數)。 |
| Prototype (原型模式) | 透過複製現有物件來建立新物件 | 建立物件的成本非常高(例如需要讀取資料庫或複雜運算),或動態決定執行時期物件型別時。 |
| Singleton (單例模式) | 確保一個類別只有一個實例,並提供全域存取點 | 系統只需要一個共用資源管理器(如連線池、設定檔讀取器、記錄器 Logger)。 (註:現代架構常搭配 DI 框架使用以降低耦合) |
二、 結構型模式 (Structural Patterns)
主要用於組合類別與物件,形成更大的結構。
| 設計模式 | 核心目的 | 適合情境 |
| Adapter (轉接器模式) | 轉換介面,讓不相容的類別協同運作 | 想使用一個現有的類別,但其介面(方法名稱、參數)與系統現行規範不符(例如整合第三方 SDK)。 |
| Bridge (橋接模式) | 將抽象與實作解耦,讓兩者可以獨立變化 | 系統有多個維度的變化(例如「形狀」與「顏色」),若使用繼承會導致子類別爆炸,改用組合來分離。 |
| Composite (組合模式) | 將物件組合成樹狀結構以表示「部分-整體」 | 客戶端需要一致地對待單一物件與物件組合(例如檔案系統中的檔案與資料夾)。 |
| Decorator (裝飾者模式) | 動態地將職責附加到物件上 | 需要在不修改原類別的前提下,動態、透明地擴充物件的功能(例如 Java I/O 串流包裝)。 |
| Facade (外觀模式) | 提供統一的高階介面來存取子系統 | 系統複雜、相依關係龐大,希望提供一個簡單、單一的進入點給客戶端使用。 |
| Flyweight (輕量級模式) | 運用共用技術有效地支援大量細粒度物件 | 系統中存在大量相同或相似的物件,導致記憶體消耗過大,透過共用狀態來節省記憶體(例如文字編輯器中的字型字元)。 |
| Proxy (代理模式) | 為其他物件提供一個替身以控制存取 | 無法或不希望直接存取目標物件時,透過代理來控制權限、延遲載入(Lazy Loading)、或加入快取/記錄。 |
三、 行為型模式 (Behavioral Patterns)
主要用於處理物件之間的演算法與職責分配。
| 設計模式 | 核心目的 | 適合情境 |
| Chain of Responsibility (責任鏈模式) | 將請求沿著處理者鏈傳遞直到被處理 | 有多個物件可以處理同一個請求,但具體由誰處理在執行時期才決定(例如 Web 伺服器的 Middleware 驗證管線)。 |
| Command (命令模式) | 將請求封裝成物件 | 需要將動作參數化、支援排隊執行(Queue)、撤銷/重做(Undo/Redo)、或記錄日誌。 |
| Interpreter (直譯器模式) | 定義語言的文法並建立直譯器 | 有一個簡單的語言或規則需要評估(例如正規表達式、特定業務規則 DSL),且其文法結構可以表示為抽象語法樹。 |
| Iterator (迭代器模式) | 順序存取聚合物件中的元素,不暴露其內部結構 | 需要提供多種走訪集合的方式,同時隱藏集合內部的底層資料結構(如陣列、樹、雜湊表)。 |
| Mediator (中介者模式) | 用一個中介物件來封裝一組物件的互動 | 多個物件之間呈現複雜的網狀相依(許多對許多),透過引入中介者將其轉為星狀相依(一對多),簡化通訊。 |
| Memento (備忘錄模式) | 在不破壞封裝性的前提下,擷取並保存物件內部狀態 | 需要實現資料的快照、還原、或 Undo 機制,但又不能暴露物件內部的實作細節。 |
| Observer (觀察者模式) | 定義物件間的一對多相依,當狀態改變時自動通知 | 當一個物件的狀態改變時,需要同步通知其他多個相依物件,且不希望這些物件之間產生緊密耦合(例如事件驅動架構、UI 資料繫結)。 |
| State (狀態模式) | 允許物件在其內部狀態改變時改變行為 | 物件的行為取決於其當前狀態,且程式碼中充滿了大量的 if-else 或 switch-case 來判斷狀態轉換。 |
| Strategy (策略模式) | 定義一系列演算法,並讓它們可以互相替換 | 同一個業務邏輯有多種不同的實作方式(例如不同的折扣計算、不同的排序或導航路徑演算法),且希望在執行時期動態切換。 |
| Template Method (樣版方法模式) | 在父類別中定義演算法骨架,將特定步驟延遲到子類別 | 多個類別擁有相似的執行流程,但部分細節步驟不同,透過繼承抽離共用邏輯,避免程式碼重複。 |
| Visitor (訪問者模式) | 在不改變類別的前提下定義新操作 | 一個穩定的物件結構(少變動的類別階層)需要對其執行許多截然不同且經常變動的操作。 |
💡 實務建議
在實際開發中,許多設計模式往往不是單獨出現的:
- MVC / MVVM 架構大量運用了 Observer(資料繫結)、Strategy(驗證器/排版)、Composite(視圖樹)。
- 當狀態邏輯變得複雜時,常會結合 State 與 Strategy。
- 當需要建立複雜且具有變異性的物件時,會結合 Builder 與 Abstract Factory。
如果要深入查閱特定模式的 UML 結構與程式碼範例(支援 Java、C++、Python、C# 等多種語言),推薦參考業界標準的 Refactoring.guru ,其情境對比與優缺點分析非常直觀。
沒有留言:
張貼留言