模板方法是什么
在基类里定义算法骨架,把可变步骤交给子类实现:流程顺序与固定步骤由基类掌控,子类只填差异部分。它用继承约束扩展点——子类能被改变的部分被限定在几个抽象方法或钩子里。现代语言里,回调与函数式参数是它更轻量的替代形态,不必为了一处差异引入继承层次。
基本信息
| 意图 | 固定骨架 + 可变步骤 |
|---|---|
| 机制 | 抽象步骤 + 钩子(hook,有默认实现) |
| 约束 | 骨架方法声明为 final,防止子类整体覆写 |
| 替代 | 策略模式、回调函数、函数式参数 |
典型使用场景
- 数据处理:打开、解析、分析、关闭的顺序固定,解析方式因格式而变
- 框架回调:基类负责生命周期,子类实现钩子
- 测试基类:统一的搭建与销毁流程,用例只写断言部分
- 导出流程:查询、转换、写出三步固定,格式与模板可变
- 算法族:同一流程的多种参数化实现,顺序不应由调用方控制
Java 示例
Java 示例
abstract class DataMiner {
// 骨架:流程固定,子类不能整体覆写
final void mine(String path) {
byte[] raw = open(path); // 固定步骤
parse(raw); // 抽象步骤:子类必须实现
analyze(); // 钩子:有默认行为
close(); // 固定步骤
}
private byte[] open(String path) { /* 读写与资源管理留在基类 */ }
protected abstract void parse(byte[] raw);
protected void analyze() { }
private void close() { }
}扩展点类型
| 类型 | 子类义务 | 设计建议 |
|---|---|---|
| 抽象步骤 | 必须实现 | 数量越少越好,避免子类负担过重 |
| 钩子方法 | 可选覆写,有默认行为 | 默认实现要保守、不能有副作用 |
| 保护方法 | 供子类复用的工具 | 不要暴露内部可变状态 |
| 骨架方法 | 不可覆写 | 声明 final 并写清楚顺序含义 |
钩子方法的默认实现要安全:默认什么都不做,或给出最保守的行为。如果默认行为会写数据或发通知,子类作者不覆写它就会产生意外副作用。
只有一处差异时不必用继承:把可变部分作为策略对象或函数参数传入,能让流程与差异都保持可组合,也避免了「为一个变化点建一个类层次」的代价。