模板方法模式适合哪些应用场景?
简化版
模板方法模式适合“流程固定、部分步骤变化”的场景,例如文件导入导出、批处理任务、报表生成、测试生命周期、框架扩展点、数据库访问模板、请求处理流程等。
详细版
判断一个场景是否适合模板方法模式,可以看三点:
- 多个子类是否共享相同流程;
- 流程顺序是否稳定且需要约束;
- 差异是否集中在少数步骤。
典型应用场景:
- 文件导入:读取、校验、解析、保存、记录结果;
- 报表导出:查询数据、生成文件、上传、返回链接;
- 批处理任务:准备环境、执行业务、记录结果、释放资源;
- 测试框架:准备、执行、清理;
- Web 请求处理:接收请求、分发、处理、返回;
- 框架生命周期:初始化、执行、销毁。
如果不同实现的整体流程差异很大,模板方法就不合适,可能应该用策略模式或流程编排。
完整版教学
一、文件导入导出是典型场景
文件导入通常有固定流程:
上传文件 -> 读取文件 -> 校验格式 -> 解析数据 -> 保存数据 -> 生成导入报告
Excel、CSV、JSON 的解析逻辑不同,但主流程大体一致。
这时父类可以定义导入模板,子类实现解析和格式校验。
这样可以避免每种文件类型都重复写保存、日志、异常处理等公共逻辑。
二、批处理任务也适合模板方法
很多定时任务都有类似结构:
加载配置 -> 加锁 -> 查询数据 -> 处理数据 -> 保存结果 -> 释放锁 -> 记录日志
不同任务只在“处理数据”这一步不同。
模板方法可以把加锁、释放锁、日志、异常处理等统一放在父类,子类只写具体任务逻辑。
这能减少线上问题,比如忘记释放锁、忘记记录任务结果。
三、报表生成和导出
报表导出流程通常也是固定的:
校验权限 -> 查询数据 -> 生成文件 -> 上传存储 -> 返回下载链接
不同报表的数据查询和文件格式可能不同,但权限校验、上传、返回链接等逻辑可以复用。
这种场景下,模板方法能让导出流程保持一致,后续新增报表类型也更容易。
四、框架和生命周期场景
框架经常使用模板方法思想。
例如:
- 测试框架控制 setup、test、teardown;
- Web 框架控制请求进入、处理、返回;
- 容器控制对象创建、初始化、销毁;
- 数据访问框架控制资源获取和释放。
框架的目标是“我来定流程,你来填业务”。这正是模板方法模式的精神。
五、不适合模板方法的场景
模板方法不适合这些情况:
- 不同实现流程差异很大;
- 流程顺序经常变化;
- 变化维度很多,需要自由组合;
- 子类需要同时继承其他父类;
- 父类必须放大量条件判断才能适配不同子类。
这些情况可以考虑策略模式、责任链模式、组合模式或流程引擎。
六、用流程稳定度筛选应用场景
10 类批处理任务若都遵循“读→校验→处理→写→通知”5 步,且只在第 2、3 步变化,就能复用 3 个稳定步骤。
batch template: read -> validate* -> process* -> write -> notify
这里真正需要保护的是父类掌握的流程不变量:客户端只能进入模板入口,子类只能改写约定好的步骤。评审时应逐步标出哪些行为固定、哪些行为必须实现、哪些行为只是可选钩子,避免父类和子类互相猜测。
七、继承边界与流程契约验证
| 检查维度 | 应确认的内容 |
|---|---|
| 机制正确性 | 适用性来自稳定流程和少数变化点,不是因为业务名字里出现“流程”。 |
| 适用边界 | 若任务需要任意增删、重排步骤或按配置拼装,模板方法的固定继承骨架不合适,管道更灵活。 |
| 测试证据 | 记录步骤进入与退出序列,覆盖默认钩子、覆写钩子、步骤异常和清理路径 |
| 工程代价 | 重点评估父类改动会影响多少子类、protected 扩展面有多大,以及新增变化是否迫使无关子类一起修改 |
易错点:适用性来自稳定流程和少数变化点,不是因为业务名字里出现“流程”。
八、常见误区与追问
- 误区:审批流天然适合模板方法。 审批节点和路由常动态变化,更可能需要责任链、状态机或工作流引擎。
- 误区:模板方法要求所有步骤都由子类覆写。 稳定步骤应在父类直接实现;只有必要变化点才做抽象步骤,可选变化点才做有默认实现的钩子。
- 追问:生命周期回调为什么常用模板思想? 框架需要掌握稳定生命周期,同时让用户在少数明确时机插入自定义行为。
- 追问:模板方法为什么常声明为 final? 为了防止子类改写算法骨架和步骤顺序;若框架有意允许重写,则必须明确不变量和扩展契约。
- 追问:模板方法最关键的回归测试是什么? 是父类契约测试:所有子类都必须满足固定步骤顺序、公共前后置行为和异常清理规则。
九、加强记忆
模板方法模式的适用场景记成“流程固定、步骤可变”。导入导出、批处理、报表、请求处理、测试生命周期、框架扩展点都很典型;如果流程本身差异大,就不要强行套模板。