模板方法模式通过抽象类定义算法骨架,将固定流程封装为final模板方法,可变步骤声明为abstract方法,子类仅实现差异化逻辑,确保流程一致性与扩展性。

直接用抽象类定义算法骨架,把固定流程写进 final 模板方法,把会变的步骤声明为 abstract 方法,子类只管实现这些方法,不碰流程本身。
明确划分“不变”与“可变”部分
动手前先梳理整个业务流程,找出哪些环节逻辑稳定、所有子类都一样,哪些环节因场景不同必须差异化处理。
- 稳定部分(如参数校验、日志记录、事务开启/提交、结果封装)——放进抽象父类里作为具体方法
- 可变部分(如库存扣减策略、价格计算规则、通知渠道选择)——声明为 abstract 方法,强制子类覆盖
- 有条件执行的环节(如“超500元需总监审批”)——可用钩子方法(带默认空实现的 protected 方法),子类按需重写
抽象父类要控制流程入口且防篡改
模板方法必须是 public final,确保子类无法改变调用顺序或跳过某步。内部按真实执行顺序依次调用各步骤方法。
- 例如下单流程:checkParam() → handleStock() → calculatePrice() → saveOrder() → sendNotify()
- 其中 checkParam() 和 saveOrder() 是父类已实现的具体方法;handleStock() 和 calculatePrice() 是 abstract 方法
- 这样任何子类调用 createOrder(),都走同一路径,仅替换两个关键动作的实现
子类只需专注自身逻辑,不感知整体流程
每个具体子类继承抽象类后,只实现自己负责的 abstract 方法,其他全部复用。不需要重写模板方法,也不需要关心其他子类怎么实现。
- 秒杀订单子类:handleStock() 写成“查 Redis 库存并原子扣减”,calculatePrice() 写成“取预设秒杀价”
- 普通订单子类:handleStock() 写成“查 MySQL 库存并加锁更新”,calculatePrice() 写成“按商品原价 × 折扣率计算”
- 客户端代码完全无感:new SeckillOrderService().createOrder() 和 new NormalOrderService().createOrder() 调用的是同一个模板方法
配合钩子方法支持柔性扩展
有些步骤不是“必须重写”,而是“可能需要干预”。这时用钩子方法比抽象方法更合适。
- 在抽象类中定义 protected boolean isNeedExtraReview() { return false; },模板方法里根据返回值决定是否插入额外审批环节
- 高风险部门子类可重写该方法返回 true,并同时实现 extraReview() 方法
- 其他子类保持默认,不写任何代码,流程自动跳过该环节

















