策略模式和模板方法模式有什么区别?
简化版
策略模式通过组合切换不同算法,调用方可以运行时选择策略;模板方法模式通过继承固定算法骨架,把某些步骤延迟给子类实现。简单记:策略模式换整个算法,模板方法固定流程、替换步骤。
详细版
两者都能复用逻辑、封装变化,但解决角度不同。
策略模式:
- 依赖组合;
- 多个策略实现同一个接口;
- 可以在运行时切换;
- 适合“多套算法互相替换”。
模板方法模式:
- 依赖继承;
- 父类定义固定流程;
- 子类重写其中某些步骤;
- 适合“流程骨架稳定,局部步骤变化”。
比如不同支付方式整体流程差异较大,可以用策略模式;如果所有导入任务都遵循“读取文件、校验、转换、保存、通知”的固定流程,只是校验和转换细节不同,可以用模板方法模式。
完整版教学
一、先从代码结构看差异
策略模式的结构通常是:
Context -> Strategy 接口 -> 多个 ConcreteStrategy
它强调组合。上下文持有一个策略对象,把可变算法委托给策略。
模板方法模式的结构通常是:
AbstractClass 定义 templateMethod()
-> 子类覆盖 step1 / step2
它强调继承。父类控制整体流程,子类只能改父类允许它改的步骤。
二、策略模式是替换一整套行为
策略模式适合多种算法之间整体可替换。
以报价系统为例:
- 普通客户报价;
- VIP 客户报价;
- 大客户协议价;
- 活动促销价。
每种报价规则可能计算方式完全不同。主流程只需要拿到报价策略并调用:
QuoteStrategy strategy = factory.get(customerType);
return strategy.quote(order);
策略之间通常是平级关系,没有谁规定谁的执行步骤。
三、模板方法模式是固定流程骨架
模板方法适合流程顺序稳定、部分步骤变化的场景。
比如文件导入:
public final void importData() {
readFile();
validate();
transform();
save();
notifyResult();
}
不同文件类型可能有不同校验和转换逻辑,但整体流程不能乱。父类把骨架固定住,子类只实现变化步骤。
这类场景如果用策略模式也能做,但会弱化“流程顺序必须固定”的约束。
四、运行时切换能力不同
策略模式天然支持运行时切换。一个上下文可以根据参数选择不同策略,也可以在运行过程中替换策略对象。
模板方法模式的行为更多在类层次上确定。你创建了哪个子类,对应流程里的可变步骤就确定了。虽然也能通过多态选择不同子类,但它不像策略模式那样强调动态替换。
所以如果面试官问“哪个更灵活”,通常可以说:策略模式在运行时组合和替换方面更灵活;模板方法在流程约束和代码复用方面更强。
五、组合优先还是继承优先
现代工程里经常强调“组合优于继承”。策略模式符合这个思想,因为它把行为作为对象组合进来。
模板方法依赖继承,优点是流程复用直接,缺点是父子类耦合较强。父类改动可能影响所有子类,子类也容易被父类的钩子方法限制。
但这不代表模板方法不好。如果业务确实有稳定流程骨架,它非常合适。设计模式的选择应该看问题,不是看哪个更流行。
六、组合替换与继承骨架的取舍
有 4 套可整体替换算法时策略可注入 4 个实现;固定 5 步流程只允许其中 2 步变化时,模板方法更直接。
strategy: Context -> replace whole behavior; template: base skeleton -> override hooks
这个推演把模式带来的收益和成本放在同一条调用链上。设计评审时既要确认结果正确,也要确认额外层次没有改变原有契约。
七、边界、代价与验证
| 检查维度 | 应确认的内容 |
|---|---|
| 正确性 | 不要只背“组合对继承”,要结合变化粒度:整体算法替换还是固定骨架中的局部步骤。 |
| 适用边界 | 策略支持运行时组合且避免继承耦合;模板方法能强制复用流程顺序,但受单继承和覆写边界约束。 |
| 测试证据 | 覆盖正常路径、异常路径、空值或未知类型,并断言调用次数与顺序 |
| 运行成本 | 记录额外对象、调用层数、延迟、线程或内存开销,不用模式名称代替测量 |
模式落地后要用单元测试验证独立职责,用集成测试验证对象装配和真实调用入口。涉及并发、远程或异步时,还要补充竞态、超时、重复执行与资源释放测试。
易错点:不要只背“组合对继承”,要结合变化粒度:整体算法替换还是固定骨架中的局部步骤。
八、常见误区与追问
- 误区:模板方法也能换子类,所以和策略完全相同。 模板依赖继承并固定骨架,策略通过对象组合替换行为,生命周期和扩展方式不同。
- 误区:用了策略模式,系统里就不该再出现任何条件判断。 策略消除的是反复扩张的业务算法分支;选择策略、校验输入和兜底仍可能需要有限判断。
- 误区:示例代码能运行,就代表模式边界设计正确。 能运行只证明一条路径,仍要检查异常、并发、顺序、生命周期以及新增实现时是否修改稳定代码。
- 追问:两种模式可以一起使用吗? 可以;模板固定大流程,其中某一步再委托可替换策略。
- 追问:策略对象可以保存本次请求的可变状态吗? 容器单例策略通常不应保存请求状态,应把订单、用户等数据作为参数传入,否则并发调用会相互污染。
- 追问:怎样验证这套设计没有改变原有语义? 先做基线行为测试,再对新增层验证返回值、异常类型、调用次数和顺序;性能敏感处还要比较改造前后的量化指标。
九、加强记忆
策略模式和模板方法模式的区别记成“组合换算法,继承定流程”。策略模式适合多套算法运行时切换;模板方法适合流程骨架固定、局部步骤变化,并且希望由父类控制执行顺序的场景。