軟體設計

策略 vs 範本方法 vs 命令的差異

學習設計模式時,你是否也遇過這種情況?

閱讀 4 分鐘
策略 vs 範本方法 vs 命令的差異 封面圖

學習設計模式時,你是否也遇過這種情況?

「策略模式和範本方法有什麼不同?命令又為什麼出現在這裡?」

三種模式都有替換行為的感覺,很容易一直混淆。

先說重點。

策略會整套替換演算法,

範本方法固定骨架,只替換部分步驟,

命令則把「要執行的行為」封裝成物件,稍後再執行。

掌握這一句,就等於完成一半。今天就用程式碼徹底分清這三兄弟。


三種模式,一眼看懂差異

先用表格整理整體概念。

分類 策略模式 範本方法 命令模式
核心 整套替換演算法 固定骨架,替換部分步驟 將行為封裝成物件
重複使用方式 組合(委派) 繼承 組合(委派)
替換時機 執行階段 編譯時期(繼承) 執行階段
主要關注點 「如何計算」 「順序相同,細節不同時」 「何時、執行什麼」

三種模式容易混淆,原因就在這裡。

因為它們的目的都是分離會變動的部分。

但分離方式與目的不同。我們逐一拆解。


策略模式會整套替換演算法

策略模式將多種完成同一工作的方式各自建立為獨立物件,並在需要時替換。

以付款方式為例就很貼切。

刷卡、KakaoPay、銀行轉帳:目的(付款)相同,但方法不同。

策略模式就是這樣整套替換的結構
策略模式就是這樣整套替換的結構
protocol PayStrategy {
    func pay(_ amount: Int) -> String
}
struct CardPay: PayStrategy {
    func pay(_ amount: Int) -> String { "刷卡付款 \(amount)" }
}
struct KakaoPay: PayStrategy {
    func pay(_ amount: Int) -> String { "使用 KakaoPay 付款 \(amount)" }
}

var strategy: PayStrategy = CardPay()
print(strategy.pay(10000))
// 輸出:刷卡付款 10000

重點是,執行階段將 strategy 變數改成 KakaoPay(),行為就會整套替換。

重點在於透過組合(composition)委派,而不是使用繼承。

實際撰寫付款策略程式碼後,委派結構就很直觀了
實際撰寫付款策略程式碼後,委派結構就很直觀了

範本方法保留骨架,只替換部分內容

範本方法的思路稍有不同。

整體流程順序固定,其中幾個步驟由子類別填入。

想像煮泡麵:煮水 → 加入食材 → 完成。順序相同,只有「加入食材」不同。

class Ramen {
    func cook() {           // 這就是範本方法
        boilWater()
        addIngredients()    // 只在子類別替換這個步驟
        print("完成!")
    }
    func boilWater() { print("煮水") }
    func addIngredients() { print("基本食材") }
}
class CheeseRamen: Ramen {
    override func addIngredients() { print("加入起司") }
}
CheeseRamen().cook()
// 輸出:煮水 / 加入起司 / 完成!

它與策略模式的關鍵差異,是使用繼承,且只替換部分步驟。

流程(cook)的主導權掌握在父類別手中。


命令模式封裝要執行的行為

命令的關注點與前兩者完全不同。

它關心的不是如何計算,而是將行為建立為物件,以便稍後執行、取消或排入佇列。

想像遙控器按鈕就很容易。按鈕保存「開燈」這個命令,按下時才執行。

protocol Command { func execute() }
struct LightOn: Command {
    func execute() { print("開燈") }
}

let button: Command = LightOn()
button.execute()   // 由我決定執行時機
// 輸出:開燈

由於將請求封裝成物件,因此很自然就能加入復原(undo)、記錄日誌、工作佇列等功能。

簡單說,策略是選擇方法的模式;命令是儲存並處理請求的模式。


何時使用,何時避免

在實務上,我會依照以下標準選擇。

  • 策略模式:同一目的有多種演算法,且需在執行階段切換時(排序方式、折扣政策、付款方式)
  • 範本方法:處理順序固定,只有部分步驟不同時(資料剖析流程、遊戲回合進行)
  • 命令:需要延後、取消、重做或排入佇列時(復原、工作排程器)

相反地,也有應該避免的訊號。

如果只有兩三個分支,未來也不會增加,就別硬套模式。單純的 if 反而更易讀。

尤其範本方法受限於繼承;若重視彈性,優先考慮策略模式(組合)通常更安全。


面試時可以這樣回答

問:策略模式與範本方法最大的差異是什麼?

策略透過組合(委派)在執行階段替換整套演算法;範本方法則透過繼承固定骨架,只覆寫部分步驟。彈性方面策略較強,流程控制則是範本方法較強。

問:命令模式與策略的差異在哪裡?

策略專注於選擇採用哪種方法;命令則將請求本身封裝成物件,支援復原、排隊、記錄等額外操作。兩者分別關注演算法選擇與請求管理。


即使三種模式看似相近,只要依照分離什麼、為什麼分離,就能清楚區分。

策略是方法,範本方法是順序中的空缺,命令是請求本身。記住這三個詞,以後就不會再混淆。祝你今天也學習愉快!

延伸閱讀