软件设计

策略 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 反而更易读。

尤其模板方法受继承限制;如果重视灵活性,优先考虑策略模式(组合)通常更稳妥。


面试时可以这样回答

问:策略模式和模板方法最大的区别是什么?

策略通过组合(委托)在运行时替换整个算法;模板方法通过继承固定骨架,只重写部分步骤。策略更灵活,模板方法更擅长控制流程。

问:命令模式和策略的区别在哪里?

策略专注于选择方法;命令将请求本身封装成对象,从而支持撤销、排队和日志记录等操作。两者分别关注算法选择与请求管理。


即使三种模式看起来相似,只要从分离什么、为何分离出发,就能清楚区分。

策略是方法,模板方法是流程中的空缺,命令是请求本身。记住这三个词,以后就不会再混淆。祝你学习愉快!

延伸阅读