4.3 設計模式的實用指南#
什麼是設計模式#
設計模式(Design Pattern) 是一套「針對常見設計問題的可重用解決方案」。它不是可以直接複製的程式碼,而是「解決這類問題的成熟思路與結構」。
設計模式源於建築學家 Christopher Alexander 的概念,在軟體界由《設計模式》(Design Patterns, 1994,四人幫 GoF)一書發揚光大。它的核心精神是:
當你遇到一個「大家都遇過」的設計問題,與其從零發明新解,不如使用前人反覆驗證過的成熟方案。
就像食譜不只教你「做這道菜」,更教你「這類菜該怎麼做」——設計模式教你「這類問題該怎麼設計」。
一個重要的提醒:先理解問題,而非套用模式#
在深入之前,必須鄭重提醒:設計模式是「解決問題的良藥」,不是「華麗的裝飾」。 最常見的誤用,是到處硬套模式,把原本簡單的程式碼弄得很複雜——這正是 3.4 節「過度設計」與「KISS」原則要對抗的。
正確的心態是:先有理解清楚的問題,才去找有沒有合適的模式;沒有《不必》的模式,就不要硬套。 設計模式是用來「回應真實需求」的,不是用來「炫耀技術」的。
常見的設計模式#
GoF 把 23 個模式分成三大類:建立型(Creational)、結構型(Structural)、行為型(Behavioral)。本節介紹幾個最實用、最常遇到的,並說明它們解決什麼問題。
建立型模式(如何建立物件)#
單例模式(Singleton):保證一個類別只有一個實例,並提供全域存取點。適用於「全系統只需要一個」的物件(例如設定檔、連線池)。
class Config:
_instance = None
def __new__(cls):
if cls._instance is None:
cls._instance = super().__new__(cls)
return cls._instance
⚠️ 單例被濫用會變成「全域狀態」的壞味道(隱藏依賴、難測試),要謹慎。
工廠模式(Factory):把「建立哪種物件」的決策封裝起來,用戶端不必直接 new 具體類別。這呼應 3.4 節的 DIP——用戶端依賴抽象介面,而非具體實作。
例如「折扣策略」工廠:依會員類型回傳對應的折扣物件,新增類型時只需加一個分支,用戶端不改。
結構型模式(如何組合物件)#
介面卡模式(Adapter):把一個介面轉換成用戶端期望的另一個介面,讓「不相容」的類別能協作。常見於整合第三方函式庫——把對方 API 包一層,轉成自家系統的介面。
裝飾者模式(Decorator):動態地為物件「附加額外職責」,而不修改原類別。例如為「報告產生器」加上「壓縮」與「加密」功能:
class EncryptedReport(HtmlReport): # 或委託包裝
def generate(self):
return encrypt(super().generate())
行為型模式(物件如何互動)#
策略模式(Strategy):把一族可互換的演算法封裝起來,讓用戶端能在執行時切換。「折扣計算」是經典例子——多種折扣策略,執行時依情境選用。它在前面 3.4 節 OCP 的例子里已出現。
觀察者模式(Observer):定義「一對多」的相依關係——當一個物件狀態改變時,所有依賴它的物件都被通知並自動更新。它正是「事件驅動架構」(3.2 節)的設計模式化身。
class Subject:
def __init__(self):
self._observers = []
def attach(self, o): self._observers.append(o)
def notify(self, event):
for o in self._observers: o.update(event)
狀態模式(State):當一個物件的行為隨其內部狀態而變(如訂單的待付款/已付款/已取消),狀態模式把每個狀態封裝成一個類別,讓狀態轉移更清晰、易於擴展(呼應 2.4 節的「狀態機審查」)。
觀念模式 vs 實作模式#
除了 GoF 的「程式碼層次」模式,還有更高層的「架構/觀念模式」,例如:
- MVC(Model-View-Controller):把資料(Model)、顯示(View)、控制(Controller)分離,是 Web/UI 框架的基礎
- Repository(倉庫):把資料存取抽象化,讓業務邏輯不直接碰資料庫(呼應 DIP)
- DI/DI 容器(依賴注入):把依賴從「程式碼內 new 出來」改成「外部注入」,提高可測性與鬆耦合(見 3.4 節 DIP)
做軟體設計時,模式是有層次的:從「單一函式」到「物件的協作」到「整個架構」,都有對應的模式語彙。
設計模式與設計原則的關係#
設計模式與設計原則(3.4 節的 SOLID)是一體兩面:
- 原則是「為什麼這樣好」的指導思想(例如開閉原則)
- 模式是「具體怎麼做」的成熟方案(例如策略模式如何實現開閉原則)
原則給你方向,模式給你地圖。 理解了原則,你才能真正理解「為什麼這個模式要在這種情境用」;只背模式而不懂原則,就很容易誤用與過度設計。
AI 時代的設計模式#
AI 非常熟悉 GoF 設計模式,這既是好事也是壞事:
- 好處:你可以請 AI「用策略模式重構這個折扣邏輯」或「這個狀態轉移適合用狀態模式嗎?」,它基本能正確套用
- 風險:AI 有「模式潔癖」傾向——它會主動搬出各種模式,即使問題根本不需要,造成過度設計(違反 KISS)
因此,使用 AI 協助設計模式時,你要特別警惕兩個問題: 1. 這個問題真的需要這個模式嗎?(還是可以用幾個 if 就解決?) 2. AI 套用的模式是否讓程式碼變得更難懂、更難維護?
務實建議:把 AI 當成「模式建議顧問」,但由你來判斷「適不適用、值不值得」。記得 KISS——最簡單、能解決問題的方案,往往就是最佳方案。
本章小結#
- 設計模式是可重用的成熟設計方案,分建立型、結構型、行為型三類
- 心態先於技巧:先理解問題,再找模式;不需要就不要硬套
- 常用模式:單例、工廠、介面卡、裝飾者、策略、觀察者、狀態,以及 MVC/Repository/DI 等觀念模式
- 原則給方向、模式給地圖,兩者相輔相成
- AI 時代:AI 熟稔模式但易過度設計,人要判斷「適不適用、值不值得」
想一想#
- 你寫過的程式碼中,哪些地方其實可以用「策略模式」或「觀察者模式」改善?試著套用看看。
- 為什麼「硬套模式」會造成過度設計?用 KISS 原則說明。
- 讓 AI 為你的程式碼「推薦適合的設計模式」,然後逐個評估它的建議是否真的必要。