模板方法模式和回调机制有什么关系?
简化版
模板方法模式通过继承让父类固定流程、子类重写步骤;回调机制通过组合或函数参数把可变步骤传进去,让框架固定流程、调用回调完成变化。两者思想相近,都是“固定骨架 + 留扩展点”,区别在于扩展方式:模板方法偏继承,回调偏组合。Spring 的 JdbcTemplate 更像模板 + 回调的工程化变体。
详细版
模板方法写法:
abstract class DataProcessor {
public final void process() {
open();
doProcess();
close();
}
protected abstract void doProcess();
}
回调写法:
template.execute(connection -> {
// 使用连接执行业务
});
两者都由模板控制公共流程:打开资源、执行变化逻辑、关闭资源。不同点是模板方法让子类覆盖 doProcess,回调让调用方传入函数或对象。
记忆钩子:模板方法是“子类填空”,回调是“把填空题作为参数传进去”。
完整版教学
面试提示:模板方法和回调的区别要围绕“继承扩展”与“组合注入”讲,顺手补一句测试和灵活性差异会更完整。
一、两者共同点是固定流程和开放扩展点
不管是模板方法还是回调,都有这个结构:
固定步骤 A
可变步骤 B
固定步骤 C
差异只在可变步骤从哪里来。模板方法从子类来,回调从参数或组合对象来。
二、模板方法依赖继承
模板方法中,父类这样写:
public final void execute() {
before();
doExecute();
after();
}
protected abstract void doExecute();
子类提供变化部分:
class ExportJob extends AbstractJob {
protected void doExecute() {
exportFile();
}
}
优点是结构清晰,适合同一类对象形成稳定继承层次。
三、回调依赖组合或函数参数
回调方式:
class ExecuteTemplate {
public void execute(Callback callback) {
before();
callback.call();
after();
}
}
调用方传入变化逻辑,不需要继承:
template.execute(() -> exportFile());
优点是更灵活,避免继承层次膨胀。
四、JdbcTemplate 是典型模板加回调
Spring JdbcTemplate 固定流程:
获取连接 -> 创建 Statement -> 执行 SQL -> 映射结果 -> 释放资源
开发者传入 SQL、参数和 RowMapper:
jdbcTemplate.query(sql, (rs, rowNum) -> mapUser(rs));
框架负责资源和异常转换,回调负责结果映射。这体现了模板思想,但不是传统继承式模板方法。
五、什么时候选继承式模板
适合继承式模板:
| 场景 | 原因 |
|---|---|
| 子类是一类稳定类型 | 继承层次清楚 |
| 流程和扩展点长期稳定 | 父类契约稳定 |
| 子类需要多个相关步骤 | 继承能组织多方法 |
| 框架生命周期 | 父类统一调度 |
例如 AbstractImportJob、BaseController 某些受控场景。
六、什么时候选回调
适合回调:
- 只需要传入一个或少数变化点;
- 不想创建大量子类;
- 变化逻辑轻量;
- 希望运行时灵活组合;
- 需要函数式写法。
例如数据库操作、重试模板、锁模板、事务模板。
七、继承和回调可以结合
父类模板内部也可以使用回调,回调模板也可以被子类封装。不要把两者看成互斥关系。
关键是:公共流程谁控制?变化点如何注入?继承是否值得?
八、常见误区与追问
- 误区:模板方法只能通过继承实现。 GoF 模板方法偏继承,但工程中常用回调实现同样思想。
- 误区:回调和模板方法完全无关。 两者都体现固定骨架和扩展点。
- 误区:JdbcTemplate 就是纯 GoF 模板方法。 它更准确地说是模板思想加回调机制。
- 误区:能用继承就不用回调。 简单变化点用回调通常更轻、更灵活。
- 追问:回调相比继承有什么优势? 减少子类数量,运行时灵活传入行为,更符合组合优先。
- 追问:继承式模板有什么优势? 多步骤扩展、稳定家族类型和框架生命周期更清晰。
- 追问:如何判断选哪个? 看变化点数量、继承层次是否自然、是否需要运行时组合。
九、加强记忆
- 两者共同点是固定骨架和开放扩展点。
- 模板方法靠继承,回调靠组合或函数参数。
- JdbcTemplate 是模板思想加回调的经典例子。
- 多步骤稳定家族适合继承式模板。
- 单点轻量变化适合回调。
- 两者可结合,不必二选一。