跳轉到

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())
這體現 OCP——用「包裝」而非「改原始類別」來擴展功能。

行為型模式(物件如何互動)#

策略模式(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 熟稔模式但易過度設計,人要判斷「適不適用、值不值得」

想一想#

  1. 你寫過的程式碼中,哪些地方其實可以用「策略模式」或「觀察者模式」改善?試著套用看看。
  2. 為什麼「硬套模式」會造成過度設計?用 KISS 原則說明。
  3. 讓 AI 為你的程式碼「推薦適合的設計模式」,然後逐個評估它的建議是否真的必要。