1. 模版方法模式的核心思想与应用场景
模版方法模式是23种经典设计模式中行为型模式的一种,它定义了算法骨架,将某些步骤延迟到子类中实现。这种模式在框架设计中尤为常见,比如Spring框架中的JdbcTemplate就大量运用了这个模式。
我在实际开发中发现,模版方法模式特别适合以下场景:
- 当多个类有相同算法结构,但某些具体步骤实现不同时
- 需要控制子类扩展点,避免子类随意修改算法流程时
- 框架需要提供标准处理流程,但允许部分步骤自定义时
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 模版方法模式的UML结构与实现要点
2.1 标准UML类图解析
模版方法模式通常包含以下角色:
- AbstractClass(抽象类):定义算法骨架和抽象方法
- ConcreteClass(具体子类):实现父类定义的抽象方法
java复制// 抽象类示例
public abstract class AbstractClass {
// 模版方法,定义算法骨架
public final void templateMethod() {
step1();
step2();
step3();
}
// 具体方法
private void step1() {
System.out.println("执行步骤1");
}
// 抽象方法,由子类实现
protected abstract void step2();
// 钩子方法(可选)
protected void step3() {
System.out.println("默认步骤3");
}
}
2.2 实现时的关键注意事项
- 模版方法应该声明为final,防止子类重写算法结构
- 抽象方法数量不宜过多,通常3-5个比较合适
- 可以使用钩子方法(Hook Method)提供额外扩展点
- 注意方法的访问控制(private/protected/public)
3. 模版方法模式在Java中的典型应用
3.1 JdbcTemplate的实现原理
Spring的JdbcTemplate是模版方法模式的经典实现:
- 定义获取连接、执行SQL、处理异常等固定流程
- 将结果集处理等可变部分通过回调接口开放
java复制// 使用示例
jdbcTemplate.query("SELECT * FROM users", (rs, rowNum) -> {
User user = new User();
user.setId(rs.getInt("id"));
user.setName(rs.getString("name"));
return user;
});
3.2 Servlet中的生命周期方法
Servlet规范中的init()、service()、destroy()方法也采用了类似模版方法的思想:
- 容器控制Servlet的生命周期流程
- 开发者只需重写需要自定义的方法
4. 模版方法模式的最佳实践与常见误区
4.1 最佳实践建议
- 合理划分固定步骤和可变步骤
- 使用钩子方法提供灵活扩展
- 考虑与策略模式结合使用
- 适当使用回调接口替代抽象方法
4.2 常见问题排查
- 流程控制失效:检查模版方法是否声明为final
- 扩展性不足:考虑增加钩子方法
- 子类过于复杂:可能需要拆分多个模版类
- 性能问题:避免在模版方法中做耗时操作
5. 模版方法模式与其他设计模式的关系
5.1 与策略模式的区别
- 模版方法:控制算法流程,子类实现部分步骤
- 策略模式:完全替换整个算法实现
5.2 与工厂方法模式的配合
工厂方法模式经常作为模版方法模式的一个步骤出现,两者可以很好地协同工作。
6. 实际项目中的模版方法模式案例
6.1 支付流程处理
一个典型的支付流程模版:
- 验证参数(固定)
- 检查余额(固定)
- 执行支付(可变,不同支付方式不同实现)
- 记录日志(固定)
java复制public abstract class PaymentProcessor {
public final void processPayment(PaymentRequest request) {
validateParams(request);
checkBalance(request);
doPayment(request); // 抽象方法
logPayment(request);
}
// 其他具体方法...
}
6.2 报表生成系统
报表生成通常包含:
- 获取数据
- 处理数据
- 生成报表
- 导出报表
其中数据处理和报表生成的具体实现可以交给子类完成。
7. 模版方法模式的优缺点分析
7.1 主要优点
- 代码复用:将公共代码放在父类
- 扩展可控:只允许修改特定步骤
- 反向控制:符合好莱坞原则(Don't call us, we'll call you)
7.2 潜在缺点
- 可能产生过多子类
- 算法流程修改困难
- 继承的固有缺点(如Java单继承限制)
8. 模版方法模式的演进与变体
8.1 使用回调对象替代继承
现代Java开发中,更倾向于使用回调接口而非继承:
java复制public class Template {
public void execute(Callback callback) {
step1();
callback.doStep();
step2();
}
}
8.2 结合Lambda表达式
Java 8之后,可以用Lambda简化模版方法的实现:
java复制public void process(Consumer<Context> step) {
init();
step.accept(context);
cleanup();
}
9. 设计模版方法时的经验技巧
- 命名要体现"模版"特征,如XXXTemplate、XXXProcessor
- 文档中明确说明哪些方法可以/必须被重写
- 考虑提供默认实现减少子类负担
- 使用设计模式组合解决复杂问题
我在实际项目中总结的一个技巧是:当发现多个类中有相似的流程控制代码时,就是考虑使用模版方法模式的好时机。但要注意不要过度设计,简单的流程复制可能比引入模版方法更合适。
