模板方法模式:定义算法的骨架
摘要
模板方法模式(Template Method Pattern)是行为型设计模式中的"算法架构师",它在父类中定义算法的骨架,将具体步骤延迟到子类实现。本文将深入探讨模板方法模式的核心概念、实现方式、应用场景及高级变体,通过丰富的Java代码示例展示如何构建可扩展的算法框架,并分析其与策略模式、工厂方法模式的区别与适用场景。
一、模板方法模式核心思想
模板方法模式的核心是定义算法骨架,延迟具体步骤实现,具有以下关键特征:
- 算法框架固定:在父类中定义不可变的算法流程
- 步骤延迟实现:具体步骤由子类实现
- 钩子方法支持:提供可选扩展点控制流程
- 避免重复代码:公共行为在父类中实现
适用场景:
- 多个算法有相同流程但不同实现细节
- 需要控制子类扩展点
- 重构重复代码到父类
- 框架设计中的生命周期控制
二、模板方法模式结构解析
UML类图示意
[AbstractClass] <|-- [ConcreteClass]
[AbstractClass] : +templateMethod()
[AbstractClass] : +primitiveOperation1()
[AbstractClass] : +primitiveOperation2()
[ConcreteClass] : +primitiveOperation1()
[ConcreteClass] : +primitiveOperation2()
核心组件角色
角色 |
职责 |
典型实现 |
AbstractClass |
抽象类 |
定义模板方法和基本方法 |
ConcreteClass |
具体子类 |
实现抽象类中的抽象方法 |
Template Method |
模板方法 |
定义算法骨架 |
Primitive Method |
基本方法 |
抽象方法或具体方法 |
三、基础实现:数据导出案例
// 抽象模板类
abstract class DataExporter {// 模板方法(final防止子类覆盖)public final void exportData() {connectToDataSource();retrieveData();processData();if (needFormatting()) {formatData();}saveData();disconnect();}// 具体方法(已有默认实现)private void connectToDataSource() {System.out.println("Connecting to data source...");}private void disconnect() {System.out.println("Disconnecting from data source...");}// 抽象方法(必须由子类实现)protected abstract void retrieveData();protected abstract void processData();protected abstract void saveData();// 钩子方法(可选覆盖)protected boolean needFormatting() {return false;}protected void formatData() {// 默认空实现}
}// 具体实现:CSV导出
class CsvExporter extends DataExporter {@Overrideprotected void retrieveData() {System.out.println("Retrieving data for CSV export");}@Overrideprotected void processData() {System.out.println("Processing data for CSV format");}@Overrideprotected void saveData() {System.out.println("Saving data to CSV file");}@Overrideprotected boolean needFormatting() {return true;}@Overrideprotected void formatData() {System.out.println("Formatting data with CSV specifications");}
}// 具体实现:PDF导出
class PdfExporter extends DataExporter {@Overrideprotected void retrieveData() {System.out.println("Retrieving data for PDF export");}@Overrideprotected void processData() {System.out.println("Processing data for PDF layout");}@Overrideprotected void saveData() {System.out.println("Saving data to PDF document");}
}// 客户端使用
public class ExportClient {public static void main(String[] args) {DataExporter csvExporter = new CsvExporter();csvExporter.exportData();System.out.println("\n---\n");DataExporter pdfExporter = new PdfExporter();pdfExporter.exportData();}
}
四、高级应用:框架生命周期控制
1. Spring框架中的模板方法
// Spring的JdbcTemplate是模板方法的经典实现
public class JdbcTemplate {public <T> T query(String sql, ResultSetExtractor<T> rse) {// 模板方法流程:// 1. 获取连接// 2. 创建语句// 3. 执行查询// 4. 处理结果集(由rse实现)// 5. 关闭资源}
}// 使用示例
public class EmployeeDao {private JdbcTemplate jdbcTemplate;public Employee getEmployeeById(long id) {return jdbcTemplate.query("SELECT * FROM employees WHERE id = ?",new Object[]{id},(rs, rowNum) -> {Employee emp = new Employee();emp.setId(rs.getLong("id"));emp.setName(rs.getString("name"));emp.setDepartment(rs.getString("department"));return emp;});}
}
2. Hibernate DAO模板
public class HibernateTemplate {public <T> T execute(HibernateCallback<T> action) {// 模板方法流程:// 1. 获取Session// 2. 开启事务// 3. 执行回调// 4. 提交事务// 5. 异常处理// 6. 关闭Session}
}// 使用示例
List<User> users = hibernateTemplate.execute(session -> session.createQuery("FROM User", User.class).list()
);
五、模板方法模式优缺点分析
优点:
优点 |
说明 |
代码复用 |
公共代码在父类中实现 |
扩展性好 |
新增子类不影响现有代码 |
控制反转 |
父类控制算法流程 |
符合开闭原则 |
对扩展开放,对修改关闭 |
缺点:
缺点 |
说明 |
类数量增加 |
每个实现需要一个子类 |
设计复杂度 |
需要合理设计抽象方法 |
继承限制 |
只能通过继承扩展 |
父类变化影响 |
父类修改影响所有子类 |
六、模板方法模式与其他模式对比
模板方法 vs 策略模式
维度 |
模板方法模式 |
策略模式 |
实现方式 |
继承 |
组合 |
算法控制 |
父类控制流程 |
客户端选择策略 |
扩展性 |
通过子类扩展 |
通过新策略扩展 |
适用场景 |
算法骨架固定 |
算法整体可变 |
模板方法 vs 工厂方法模式
维度 |
模板方法模式 |
工厂方法模式 |
目的 |
定义算法骨架 |
创建对象 |
关注点 |
算法步骤 |
对象创建 |
方法类型 |
模板方法包含多个步骤 |
工厂方法只负责创建 |
典型应用 |
框架生命周期 |
对象创建解耦 |
七、模板方法模式最佳实践
1. 钩子方法高级应用
abstract class Game {// 模板方法final void play() {initialize();startPlay();if (allowCheats()) {enableCheats();}endPlay();showScore();}abstract void initialize();abstract void startPlay();abstract void endPlay();// 钩子方法boolean allowCheats() {return false; // 默认不允许作弊}void enableCheats() {// 默认空实现}void showScore() {System.out.println("Showing default score display");}
}class ChessGame extends Game {void initialize() {System.out.println("Setting up chess board");}void startPlay() {System.out.println("Starting chess game");}void endPlay() {System.out.println("Checkmate! Game over");}// 覆盖钩子方法boolean allowCheats() {return true; // 国际象棋允许特定"作弊"}void enableCheats() {System.out.println("Enabling chess engine assistance");}void showScore() {System.out.println("Displaying chess rating points");}
}
2. 模板方法模式与函数式接口结合
class FunctionalTemplate {public void executeTemplate(Runnable preProcess,Runnable mainProcess,Runnable postProcess) {preProcess.run();try {mainProcess.run();} finally {postProcess.run();}}
}// 使用示例
FunctionalTemplate template = new FunctionalTemplate();
template.executeTemplate(() -> System.out.println("Setup resources"),() -> System.out.println("Core business logic"),() -> System.out.println("Cleanup resources")
);
八、模板方法模式在开源框架中的应用
JUnit测试框架
public abstract class TestCase {public void runBare() throws Throwable {setUp();try {runTest();} finally {tearDown();}}protected void setUp() throws Exception {}protected void tearDown() throws Exception {}protected void runTest() throws Throwable {// 反射调用测试方法}
}
Java AWT中的模板方法
public abstract class Component {public void paint(Graphics g) {if (peer != null) {peer.paint(g);}}// 其他模板方法...
}
九、高级应用:分布式事务模板
abstract class DistributedTransactionTemplate {public final void executeTransaction() {try {beginTransaction();executeBusinessLogic();commitTransaction();} catch (Exception e) {rollbackTransaction();handleError(e);} finally {cleanupResources();}}private void beginTransaction() {System.out.println("Starting distributed transaction");}private void commitTransaction() {System.out.println("Committing transaction");}private void rollbackTransaction() {System.out.println("Rolling back transaction");}private void cleanupResources() {System.out.println("Cleaning up resources");}protected abstract void executeBusinessLogic() throws Exception;protected void handleError(Exception e) {System.err.println("Transaction failed: " + e.getMessage());}
}// 具体实现
class OrderProcessingTransaction extends DistributedTransactionTemplate {protected void executeBusinessLogic() throws Exception {System.out.println("Processing order business logic");// 复杂的业务逻辑if (Math.random() > 0.5) {throw new Exception("Simulated business error");}}@Overrideprotected void handleError(Exception e) {super.handleError(e);notifyAdmin(e);}private void notifyAdmin(Exception e) {System.out.println("Notifying admin about failure");}
}
十、模板方法模式未来发展趋势
新兴应用方向:
- 云原生应用:跨服务事务模板
- 微服务编排:服务调用流程模板
- Serverless架构:函数执行模板
- AI工作流:机器学习流程模板
- 区块链智能合约:交易处理模板
响应式模板方法
// Reactor中的模板方法应用
Mono<Void> reactiveTemplate = Mono.fromRunnable(this::preProcess).then(Mono.defer(this::mainProcess)).doOnError(this::handleError).then(Mono.fromRunnable(this::postProcess));reactiveTemplate.subscribe();
总结
模板方法模式是构建可复用算法框架的基石,特别适合需要固定流程但允许步骤变化的场景。其核心价值体现在:
- 算法复用:公共流程在父类中实现
- 扩展灵活:子类可定制特定步骤
- 控制反转:父类控制流程,子类实现细节
- 框架基础:为复杂系统提供标准生命周期
现代应用关键点:
- 合理设计抽象方法:平衡父类控制和子类自由
- 钩子方法运用:提供灵活扩展点
- 避免过度抽象:防止过度设计导致复杂度增加
- 与函数式编程结合:使用Lambda简化实现
- 异常处理:完善模板中的错误处理机制
模板方法模式正在与响应式编程、云原生架构等现代技术结合,演进出更强大的流程控制能力。掌握模板方法模式的精髓,将帮助开发者构建出更加健壮、可扩展的系统架构,特别是在框架设计和复杂流程管理领域。