模板方法通过final方法固定流程骨架,抽象方法强制子类实现差异逻辑,钩子方法提供可选扩展点。其核心是分离不变流程与可变行为,确保子类只能定制“怎么做”而不能更改“执行顺序”。

在 Java 抽象类中,通过定义 模板方法(Template Method) 来固定业务骨架,核心是:把流程中不变的部分(即执行顺序和公共逻辑)写在抽象类的 final 方法 中,而将可变、需子类定制的部分声明为 抽象方法 或 钩子方法(hook),由子类实现或重写。
明确模板方法的结构设计
模板方法本质是一个“流程控制中枢”,它本身不完成具体业务,只负责按序调用各步骤。典型结构如下:
- 定义一个
final的公共方法(如execute()),封装完整流程(例如:校验 → 处理 → 保存 → 发通知) - 流程中的每一步,如果是必须子类实现的,声明为 abstract(如
doProcess()) - 如果是可选扩展点,定义为默认空实现的 protected 方法(即钩子,如
beforeSave()),子类按需重写 - 公共工具逻辑(如日志、异常包装、事务开启)直接在模板方法内编写,避免子类重复
用 abstract + final 组合锁定骨架
关键在于用 final 封装调用顺序,用 abstract 强制子类提供差异逻辑。例如:
public abstract class OrderProcessor {
// 模板方法:流程不可变,子类不能重写
public final void processOrder() {
validate();
doProcess();
save();
notifyUser();
afterProcess(); // 钩子,可为空实现
}
<pre class="brush:php;toolbar:false;">private void validate() { /* 通用校验 */ }
private void save() { /* 通用持久化 */ }
private void notifyUser() { /* 通用通知 */ }
// 子类必须实现的具体行为
protected abstract void doProcess();
// 钩子方法:子类可选择性重写
protected void afterProcess() {}}
立即学习“Java免费学习笔记(深入)”;
这样,任何子类(如 PromotionOrderProcessor、VipOrderProcessor)都只能改“怎么做”,不能改“先做什么、后做什么”。
配合钩子方法提升扩展灵活性
纯抽象方法要求子类必须实现,但实际中有些环节是“可插拔”的。这时用钩子方法更自然:
- 钩子方法默认是空的
protected方法,不加abstract - 子类只在需要时才重写,比如仅 VIP 订单需额外积分计算,就在其子类里重写
afterProcess() - 模板方法内部统一调用钩子,无需判断是否实现——因为默认啥也不做,安全无副作用
注意常见陷阱
写模板方法时容易忽略的细节:
- 模板方法本身必须是
public或protected,且通常加final,防止子类破坏流程 - 不要在抽象方法中调用子类可能重写的非 final 方法(可能导致初始化问题或循环调用)
- 避免在模板方法中暴露过多参数,必要时用
protected final字段或getter提供上下文数据 - 如果流程分支复杂(如“是否跳过某步”),可用钩子返回布尔值控制,而不是让子类直接操作流程逻辑
不复杂但容易忽略:模板方法的价值不在代码量,而在把“什么不变”和“什么可变”清晰分离,让后续新增子类时,只聚焦业务差异,不用再想流程对不对。


















