钩子方法是父类中用protected修饰的空方法或带默认实现的方法,用于在模板方法关键节点提供可选增强点。需命名明确、嵌入流程骨架、避免构造器调用和未捕获异常。

在父类中预留扩展钩子方法,核心是主动暴露安全、可控、低耦合的插入点,让子类能定制行为而不破坏主流程。关键不在“能不能重写”,而在“该在哪留、怎么留、怎么用”。
用 protected 空方法或默认实现作为钩子
这是最常用也最稳妥的方式。钩子方法必须是 protected(保证子类可访问,又避免外部误调),有明确语义,且不强制子类实现。
- 声明为
protected void onInit() { }或protected boolean shouldRetry() { return false; } - 配合注释说明用途,例如:
// 子类可在此执行资源预热,不影响主流程 - 避免用
abstract——那不是钩子,是强制契约;钩子的本质是“可选增强”
把钩子嵌入模板方法的关键节点
钩子不是孤立存在的,要放在父类定义好的流程骨架里,才有意义。比如一个数据处理模板:
-
beforeProcess():在验证前执行,适合做参数预处理 -
afterProcess():在保存后触发,适合发通知或清理临时资源 -
shouldLog():返回布尔值,控制分支逻辑,比直接重写整个日志逻辑更轻量
这些方法被 final process() 调用,子类只管填空,流程权始终在父类手里。
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
避免常见设计陷阱
钩子设计失效,往往是因为踩了这几个坑:
- 把核心方法(如
execute())设为public且未加final,导致子类随意重写,破坏事务边界或状态校验 - 钩子方法命名模糊,比如叫
handle(),子类无法判断何时该覆盖、覆盖后是否影响上下文 - 在父类构造器中调用钩子方法——此时子类字段尚未初始化,极易 NPE
- 钩子方法内部抛出未声明异常,却没在模板方法中兜底,导致流程中断不可控
第三方库中钩子的参考范式
成熟框架的钩子设计值得借鉴:
- Spring Batch 的
Tasklet提供beforeStep()和afterStep() - Logback 的
AppenderBase有start()和stop()钩子 - 它们共同特点是:方法名直指时机、签名简单、文档明确、不参与核心责任
照着这个思路设计,你的父类就自然具备演进能力,升级时子类几乎不用动。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










