# 什么是模板方法模式?一般用在什么场景?
8 min read
Table of Contents
什么是模板方法模式?一般用在什么场景?
模板方法模式面试标准答案
【核心定义】
模板方法模式是一种行为设计模式,它在父类中定义一个算法的骨架(模板方法),将某些步骤的具体实现延迟到子类中,使得子类可以在不改变算法结构的情况下重新定义算法的某些特定步骤。
【关键要点】
- 算法骨架固定:父类定义算法的执行流程(模板方法),这个流程是固定的、不可被子类重写(通常声明为final)
- 步骤可定制:算法中的某些步骤被声明为抽象方法或钩子方法,由子类提供具体实现
- 好莱坞原则:“不要调用我们,我们会调用你” - 父类控制调用流程,子类被动提供实现
- 代码复用最大化:将公共的算法逻辑提取到父类,避免代码重复
【深度推导/细节】
模板方法的结构拆解
public abstract class AbstractClass { // 模板方法 - 定义算法骨架(final防止子类修改流程) public final void templateMethod() { step1(); // 必须实现的步骤 step2(); // 可选的钩子方法 if (hook()) { // 条件判断钩子 step3(); } step4(); // 默认实现的步骤 }
// 抽象方法 - 子类必须实现 protected abstract void step1();
// 钩子方法 - 子类可选择重写 protected void step2() { /* 默认实现 */ } protected boolean hook() { return true; }
// 具体方法 - 子类直接继承 private void step4() { /* 具体实现 */ }}设计合理性分析
- final关键字的作用:确保算法骨架不被破坏,维护设计的一致性
- protected访问权限:允许子类访问必要的方法,同时对外隐藏实现细节
- 钩子方法的灵活性:提供扩展点,让子类可以影响父类的行为
【关联/对比】
与其他模式的对比
-
vs 策略模式
- 模板方法:基于继承,控制算法流程,部分步骤可变
- 策略模式:基于组合,整个算法可替换,更灵活但结构更松散
-
vs 工厂方法模式
- 模板方法:关注算法步骤的定制
- 工厂方法:是模板方法的一种特殊形式,专注于对象创建
-
vs 建造者模式
- 模板方法:固定流程,变化的是步骤实现
- 建造者模式:固定部件,变化的是组装顺序
【典型应用场景】
1. 框架设计场景
- Spring框架:JdbcTemplate、RestTemplate等模板类
- Servlet生命周期:HttpServlet的service()方法调用doGet()/doPost()
- JUnit测试框架:setUp() → testXXX() → tearDown()的固定流程
2. 业务处理场景
// 订单处理模板public abstract class OrderProcessor { public final void processOrder(Order order) { validateOrder(order); // 验证订单 calculatePrice(order); // 计算价格 applyDiscount(order); // 应用折扣(钩子方法) generateInvoice(order); // 生成发票 notifyCustomer(order); // 通知客户 }
protected abstract void applyDiscount(Order order);}3. 算法实现场景
- 数据解析:解析头部 → 解析数据体 → 验证 → 输出结果
- 文件处理:打开文件 → 读取数据 → 处理数据 → 关闭文件
- 工作流引擎:任务初始化 → 执行 → 验证 → 清理
【设计优势与考量】
优势
- 代码复用性:公共代码在父类中只写一次
- 扩展性:通过子类扩展新的实现,符合开闭原则
- 反向控制:父类控制调用流程,降低耦合
- 标准化:确保所有子类遵循相同的算法结构
使用考量
- 继承的局限性:Java单继承限制,一个类只能使用一种模板
- 过度设计风险:简单场景使用会增加复杂度
- 理解成本:对新手来说,流程控制不够直观
『面试官追问』
可能的问题及回答要点:
-
Q:模板方法模式与策略模式如何选择?
- A:如果需要固定算法流程,只变化部分步骤 → 模板方法
- 如果需要完全替换整个算法 → 策略模式
- 考虑继承vs组合的权衡
-
Q:钩子方法的作用是什么?
- A:提供额外的扩展点,让子类可以:
- 影响模板方法的执行流程(通过返回boolean)
- 提供可选的功能实现
- 在特定步骤前后添加额外逻辑
- A:提供额外的扩展点,让子类可以:
-
Q:为什么模板方法要声明为final?
- A:防止子类重写算法骨架,确保:
- 所有子类遵循相同的执行顺序
- 框架设计者的意图不被破坏
- 代码的可维护性和一致性
- A:防止子类重写算法骨架,确保:
-
Q:在实际项目中,你如何避免模板方法模式的滥用?
- A:遵循以下原则:
- 只有当多个类有显著相同的算法流程时才使用
- 变化的步骤数量适中(通常3-6个)
- 考虑使用组合+策略模式作为替代方案
- 保持模板类的职责单一
- A:遵循以下原则:
-
Q:模板方法模式如何支持开闭原则?
- A:通过以下方式:
- 对扩展开放:可以创建新的子类来提供不同的步骤实现
- 对修改封闭:模板方法的流程是固定的,不需要修改父类
- 新增功能只需添加新的子类,不影响现有代码
- A:通过以下方式:
实际应用示例:
// Spring的JdbcTemplate是经典应用public class JdbcTemplate { public <T> T execute(ConnectionCallback<T> action) { Connection con = null; try { con = dataSource.getConnection(); // 模板方法:获取连接 → 执行回调 → 处理异常 → 释放资源 return action.doInConnection(con); } catch (SQLException ex) { // 统一的异常处理 throw new DataAccessException("SQL执行失败", ex); } finally { // 统一的资源释放 DataSourceUtils.releaseConnection(con, dataSource); } }}总结要点:模板方法模式通过固定算法骨架、延迟步骤实现的方式,在框架设计和业务处理中实现了代码复用和流程标准化。使用时需权衡继承的优缺点,合理设计抽象方法和钩子方法,确保模式的适用性。