模板方法模式的核心是用abstract类封装固定流程,将可变部分声明为protected abstract方法,模板方法(如execute())必须public final以锁死顺序;稳定环节直接写入该final方法,可变逻辑抽为abstract方法,柔性扩展通过带默认实现的钩子方法(如shouldtriggerreview)实现。

核心是用抽象类封装固定流程,把可变部分声明为 abstract 方法,再用 final 修饰模板方法锁死执行顺序。
模板方法必须加 final
算法骨架的生命线是那个对外暴露的入口方法,比如 execute() 或 process()。它要声明为 public final,否则子类一旦重写,整个流程就失控了。这不是建议,是强制要求。Java 靠语法约束,不能只靠命名约定或文档提醒。
- 所有稳定环节——参数校验、事务开启、日志记录、结果封装——都直接写进这个 final 方法里,按真实执行顺序调用
- 避免在模板方法中调用 this 的非 final 方法,防止子类过早介入引发意外行为
- IDE 中可给该方法加 @Deprecated 注解,并注明 “DO NOT OVERRIDE”,强化提示
可变步骤抽成 abstract 方法
哪些逻辑会因场景不同而变化?比如库存扣减方式、价格计算规则、数据源选择——这些就是“填空题”。在抽象类中统一声明为 protected abstract,子类必须实现,一个都不能少。
- 命名要直白,比如 loadDataSource()、calculateDiscount()、sendNotification()
- 返回类型尽量用 void 或简单类型;若后续步骤强依赖其结果,就让它返回明确值,别留空或 null
- 禁止子类在实现 abstract 方法时反向调用模板方法,否则会触发无限递归和 StackOverflowError
柔性扩展靠钩子方法
有些环节不是“必须有”,而是“可能需要”。比如“是否触发风控审核”“是否额外记录审计日志”,这种带条件的步骤,别塞 if 判断进模板方法,而是做成钩子方法。
- 定义为 protected,带默认空实现,比如 shouldTriggerReview() 默认返回 false
- 命名建议以 should、is、before、after 开头,语义清晰
- 钩子里只做轻量决策或副作用操作(如打点、发消息),别放耗时 IO 或复杂计算
子类只做最小必要实现
子类继承后,任务非常明确:只覆盖 abstract 方法,按需重写钩子,其余全部复用。不需要关心其他子类怎么写,也不用重复写校验或清理逻辑。
- 例如秒杀订单子类只实现 handleStock()(Redis 原子扣减)和 calculatePrice()(取预设价)
- 普通订单子类则实现 MySQL 加锁扣减 + 折扣率计算,两套逻辑完全隔离,客户端调用无感知
- 如果子类需要大幅修改流程顺序,说明这个“骨架”已不通用,应考虑用策略模式或职责链替代
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











