在Java中模板方法模式是什么_JavaTemplateMethod设计概念说明

模板方法模式是通过继承控制流程+开放定制点的结构化设计手段,用抽象类定义算法骨架,将可变步骤声明为protected abstract方法,不变逻辑固化在final模板方法中,并通过钩子方法支持可选扩展。

模板方法模式不是“语法糖”,而是一种通过继承控制流程+开放定制点的结构化设计手段。它用抽象类定义算法骨架,把可变步骤声明为 abstract 方法,强制子类实现;把不变逻辑(如日志、校验、资源收尾)固化在 final 模板方法中——这是它和普通继承最本质的区别。

怎么写一个真正可用的模板方法?

关键不在“能跑”,而在“不被误改”和“易扩展”。必须做到三点:

  • templateMethod() 必须声明为 final,否则子类重写会破坏流程一致性
  • 可变步骤统一用 protected abstract 声明,避免 public 暴露给外部调用
  • 非核心但可能调整的步骤(如日志开关、超时配置)做成 protected 钩子方法,默认空实现,子类按需覆盖
public abstract class DataProcessor {
    // ✅ 模板方法锁定流程
    public final void execute() {
        validate();
        prepare();
        doProcess(); // 子类必须实现
        cleanup();
        logResult(); // 钩子方法,可选覆盖
    }
private void validate() { /* 通用校验 */ }
private void prepare() { /* 初始化连接等 */ }
private void cleanup() { /* 关闭资源 */ }

protected abstract void doProcess(); // ❗核心差异点

protected void logResult() { // ?钩子:默认不打日志
    System.out.println("Processing completed.");
}

}

为什么 HttpServlet.service() 是经典案例?

因为它暴露了模板方法模式的真实价值:框架作者控制协议处理主干,业务开发者只专注语义。

  • service()final 模板方法,内部判断 GET/POST/PUT 后分发到对应 doXxx()
  • doGet()doPost()protected abstract 方法,由你实现
  • 你不能重写 service(),但可以新增 doOptions() 并在子类里手动调用——这就

    是“不改骨架,扩新支路”

常见踩坑:抽象类加新抽象方法=全量子类编译失败

这是模板方法模式最痛的反模式。一旦你在抽象类中新增一个 abstract 方法,所有子类立刻报错。

  • ✅ 正确做法:新增功能用钩子方法(protected + 默认空实现)
  • ✅ 或者拆出新抽象类,让老子类继续继承旧类,新子类继承新类
  • ❌ 错误直觉:“反正都要改,不如直接加 abstract 方法”——这等于把扩展成本转嫁给所有下游

Spring MVC 的 AbstractController 怎么规避继承僵化?

它没用纯模板方法,而是混合策略:把真正可变的部分抽成接口回调(如 handleRequestInternal()),其余流程用模板方法封装。这样既保骨架稳定,又避免子类爆炸。

  • 你只需实现一个方法,而不是一堆 prepareXxx()afterXxx()
  • 框架内部用 if (logger.isDebugEnabled()) 这类钩子控制行为,不依赖子类重写
  • 真正需要定制的环节(如参数绑定、视图解析)交给独立组件,而非塞进继承链

抽象类不是“父类”,是“契约容器”。它不提供能力,而是定义谁在什么时机做什么事。模板方法模式的复杂点从来不在写法,而在于:什么时候该用继承约束流程,什么时候该用组合解耦变化——这个判断,比写十个 abstract 方法都难。