模板方法模式的关键是用public final void execute()定义算法骨架,将不变逻辑固化、可变部分交由子类实现,禁止子类重写模板方法,严格区分抽象方法(强制实现)与钩子方法(可选覆盖),避免父类硬编码子类,遵循“好莱坞原则”。

在继承体系中设计通用模板方法,关键不是“写个方法再继承”,而是提前规划算法骨架、明确职责边界、控制扩展入口。核心在于用抽象类定义流程,把不变的逻辑固化,把可变的部分交给子类去填空。
模板方法必须声明为 final
这是最常被忽略但最关键的一点。模板方法代表的是整个算法的执行顺序和控制权,一旦允许子类重写,就等于把骨架交出去了——流程可能被跳过、打乱甚至替换。所以标准写法是:
- 用 public final void execute() 作为统一入口
- 内部只调用 protected abstract 方法(必须实现)或 protected 钩子方法(可选覆盖)
- 避免在模板方法里调用 public 方法,防止外部直接触发未完成的步骤
合理区分抽象方法和钩子方法
不是所有延迟实现都该用 abstract。语义不同,强制性也不同:
分析 Java Spring Boot 后端 Controller 代码,自动生成 Markdown 格式的接口文档。当用户说“生成 Java 接口文档”、“生成 API 文档”、“从 Spring 代码生成文档”时触发。
- 抽象方法:用于核心不可省略的步骤,比如参数校验、数据加载、结果封装。子类不实现,编译直接报错
- 钩子方法:用于辅助性、可选行为,比如日志记录、缓存清理、异步通知。提供空实现,子类按需重写
- 典型命名如 beforeProcess()、afterSuccess()、shouldRetry(),既清晰又支持流程干预
避免在父类中硬编码具体子类
模板方法存在的意义就是解耦流程与实现。如果在 abstract 类的 execute() 里写 new ConcreteExportToExcel(),那就彻底违背模式初衷:
立即学习“Java免费学习笔记(深入)”;
- 破坏了多态性,新格式要改父类代码,违反开闭原则
- 无法被 Spring 管理生命周期,AOP 增强失效
- 单元测试时无法 mock,只能走真实逻辑
- 正确做法是由客户端决定实例化哪个子类,再调用继承来的模板方法
子类只负责填充,不反向驱动
子类不该主动调用 super.templateMethod()。模板方法是父类给子类提供的“执行入口”,不是子类用来协调流程的工具:
- 子类职责是实现抽象方法、选择性覆盖钩子,而不是控制执行时机
- 如果发现子类需要反复调用父类模板方法,说明分层出了问题——可能本该是组合关系,而非继承
- 真正的协作应是“父类调用子类”,体现好莱坞原则:“Don’t call us, we’ll call you”

















