模板方法模式中,抽象类用public final模板方法锁定算法骨架,protected abstract方法强制子类实现可变环节,钩子方法支持条件扩展。

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











