模板方法模式是通过继承控制流程+开放定制点的结构化设计手段,用抽象类定义算法骨架,将可变步骤声明为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() 是经典案例?
因为它暴露了模板方法模式的真实价值:框架作者控制协议处理主干,业务开发者只专注语义。
立即学习“Java免费学习笔记(深入)”;
电子手机配件网站源码1.0
电子手机配件网站源码是一个响应式的织梦网站模板,软件兼容主流浏览器,且可以在PC端和手机端中进行浏览。模板包含安装说明,并包含测试数据。本模板基于DEDECms 5.7 UTF-8设计,需要GBK版本的请自己转换。模板安装方法:1、下载最新的织梦dedecms5.7 UTF-8版本。2、解压下载的织梦安装包,得到docs和uploads两个文件夹,请将uploads里面的所有文件和文件夹上传到你的
下载
-
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 方法都难。









