设计模式详解------模板方法模式
一、模式概述
1. 模式定义
模板方法模式(Template Method Pattern) 是一种行为型设计模式 。
它定义一个操作中的算法骨架(固定流程) ,将某些步骤延迟到子类中实现,使得子类可以不改变算法结构,即可重新定义算法的某些特定步骤。
简单理解:
- 父类定流程骨架
- 子类填具体实现
- 流程不变,实现可变
2. 核心思想
- 父类提供固定模板方法,规定执行顺序与步骤
- 抽象方法交给子类实现
- 复用公共逻辑,避免代码重复
- 符合开闭原则 + 单一职责
3. 主要角色
- 抽象模板类(AbstractClass)
- 定义模板方法(final,防止子类重写流程)
- 定义抽象方法(子类必须实现)
- 提供通用方法(公共逻辑)
- 具体子类(ConcreteClass)
- 实现父类的抽象方法
- 完成步骤的具体逻辑
- 客户端(Client)
- 使用子类对象,调用模板方法
二、适用场景
- 多个子类有共同流程,但部分步骤实现不同
- 希望统一控制流程,只开放部分步骤扩展
- 复杂算法抽取公共部分,减少重复代码
- 框架设计中,用于规定扩展点(钩子方法)
典型业务场景:
- 订单创建流程(验参 → 查库存 → 计算金额 → 落库 → 通知)
- 数据同步流程(拉取 → 解析 → 转换 → 入库)
- 游戏开局流程(加载 → 初始化 → 开始 → 结算)
- Spring、MyBatis 等框架大量使用模板模式
三、实战代码实现(模拟订单流程)
场景说明
不同类型订单(普通订单、秒杀订单)流程一致,但部分逻辑不同:
- 校验参数(通用)
- 处理库存(不同)
- 计算价格(不同)
- 创建订单(通用)
- 发送通知(通用)
1. 抽象模板类(定义流程骨架)
java
/**
* 抽象订单模板类
*/
public abstract class AbstractOrderService {
/**
* 模板方法:固定下单流程
* final 防止子类篡改流程
*/
public final void createOrder() {
checkParam(); // 1. 参数校验(通用)
handleStock(); // 2. 库存处理(子类实现)
calculatePrice(); // 3. 价格计算(子类实现)
saveOrder(); // 4. 保存订单(通用)
sendNotify(); // 5. 发送通知(通用)
}
// 通用方法:父类实现
protected void checkParam() {
System.out.println("参数校验通过");
}
// 抽象方法:子类必须实现
protected abstract void handleStock();
protected abstract void calculatePrice();
// 通用方法
protected void saveOrder() {
System.out.println("订单已保存到数据库");
}
protected void sendNotify() {
System.out.println("下单成功通知已发送");
}
}
2. 具体子类:普通订单
java
/**
* 普通订单实现
*/
public class NormalOrderService extends AbstractOrderService {
@Override
protected void handleStock() {
System.out.println("普通商品:锁定库存");
}
@Override
protected void calculatePrice() {
System.out.println("普通价格计算:原价");
}
}
3. 具体子类:秒杀订单
java
/**
* 秒杀订单实现
*/
public class SeckillOrderService extends AbstractOrderService {
@Override
protected void handleStock() {
System.out.println("秒杀商品:Redis预扣库存 + 异步扣减");
}
@Override
protected void calculatePrice() {
System.out.println("秒杀价格计算:活动价 + 优惠叠加");
}
}
4. 客户端调用
java
public class Client {
public static void main(String[] args) {
System.out.println("===== 普通订单 =====");
AbstractOrderService normal = new NormalOrderService();
normal.createOrder();
System.out.println("\n===== 秒杀订单 =====");
AbstractOrderService seckill = new SeckillOrderService();
seckill.createOrder();
}
}
5. 运行结果
===== 普通订单 =====
参数校验通过
普通商品:锁定库存
普通价格计算:原价
订单已保存到数据库
下单成功通知已发送
===== 秒杀订单 =====
参数校验通过
秒杀商品:Redis预扣库存 + 异步扣减
秒杀价格计算:活动价 + 优惠叠加
订单已保存到数据库
下单成功通知已发送
四、钩子方法(Hook)扩展
钩子方法让子类可选性影响流程,增强灵活性。
在抽象类中添加:
java
// 钩子方法:默认返回true,子类可覆盖
protected boolean isNeedNotify() {
return true;
}
修改模板方法:
java
public final void createOrder() {
checkParam();
handleStock();
calculatePrice();
saveOrder();
// 根据钩子决定是否执行
if (isNeedNotify()) {
sendNotify();
}
}
子类可以重写钩子方法关闭通知:
java
@Override
protected boolean isNeedNotify() {
return false;
}
五、模板方法模式优缺点
优点
- 代码复用:公共逻辑统一在父类
- 流程可控:父类固定流程,子类无法破坏结构
- 扩展方便:新增实现只需加子类,符合开闭原则
- 便于维护:统一规范,减少重复逻辑
缺点
- 类数量可能增多(每个实现一个子类)
- 父类若设计不合理,子类实现会很复杂
- 流程固定,过度复杂的流程不适合
六、经典框架应用(面试高频)
1. Spring JdbcTemplate
execute固定流程:获取连接 → 执行语句 → 释放资源- 子类/回调实现 SQL 逻辑
2. MyBatis BaseExecutor
- 数据库操作流程固定,不同执行器(Simple/Reuse/Batch)只替换部分逻辑
3. HttpServlet
service()方法分发doGet/doPost,是典型模板方法
4. Spring 生命周期
Bean 初始化流程:实例化 → 依赖注入 → 初始化 → 销毁
七、模板方法 VS 策略模式(面试必问)
| 对比项 | 模板方法模式 | 策略模式 |
|---|---|---|
| 核心思想 | 父类定流程,子类填步骤 | 一组可互换算法,自由切换 |
| 实现方式 | 继承 | 组合/接口 |
| 控制力度 | 流程固定,不可修改 | 整个算法可替换 |
| 耦合度 | 较高(继承) | 低(组合优于继承) |
一句话区分:
- 模板方法:流程不变,步骤变
- 策略模式:算法整体互换
八、总结
- 模板方法 = 流程骨架 + 可变步骤
- 父类用
final固定模板方法,保证流程不被破坏 - 抽象方法交给子类实现,公共方法父类统一实现
- 适合流程固定、实现多变的业务场景
- 框架底层大量使用,是代码复用与规范扩展的利器
一句话记忆:父类定骨架,子类填细节;流程不改动,扩展更轻松!