模板方法模式的关键是父类用public final模板方法锁定流程,子类仅实现protected abstract可变逻辑和可选钩子方法。

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


















