模板方法模式:定义算法的骨架
摘要
模板方法模式(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 {
@Override
protected void retrieveData() {
System.out.println("Retrieving data for CSV export");
}
@Override
protected void processData() {
System.out.println("Processing data for CSV format");
}
@Override
protected void saveData() {
System.out.println("Saving data to CSV file");
}
@Override
protected boolean needFormatting() {
return true;
}
@Override
protected void formatData() {
System.out.println("Formatting data with CSV specifications");
}
}
// 具体实现:PDF导出
class PdfExporter extends DataExporter {
@Override
protected void retrieveData() {
System.out.println("Retrieving data for PDF export");
}
@Override
protected void processData() {
System.out.println("Processing data for PDF layout");
}
@Override
protected 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");
}
}
@Override
protected 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简化实现
- 异常处理:完善模板中的错误处理机制
模板方法模式正在与响应式编程、云原生架构等现代技术结合,演进出更强大的流程控制能力。掌握模板方法模式的精髓,将帮助开发者构建出更加健壮、可扩展的系统架构,特别是在框架设计和复杂流程管理领域。