Java模板方法模式案例
什么是模板方法模式?
模板方法模式是一种行为设计模式,它在一个方法中定义算法的骨架,而将一些步骤延迟到子类中实现,使得子类可以在不改变算法结构的情况下,重新定义算法中的某些步骤。

模式结构
┌─────────────────┐
│ AbstractClass │
├─────────────────┤
│ +templateMethod()│───► 定义算法骨架
│ +step1() │
│ +step2() │
│ +step3() │
└─────────────────┘
▲
│
┌────────┴────────┐
│ ConcreteClass │
├─────────────────┤
│ +step1() │
│ +step2() │
│ +step3() │
└─────────────────┘
实际案例:咖啡和茶的制作
1 基础抽象类
public abstract class Beverage {
// 模板方法 - 定义制作饮料的算法骨架
public final void prepareRecipe() {
boilWater();
brew();
pourInCup();
addCondiments();
}
// 具体方法 - 所有子类共享的步骤
private void boilWater() {
System.out.println("煮沸水");
}
private void pourInCup() {
System.out.println("倒入杯中");
}
// 抽象方法 - 子类必须实现
protected abstract void brew();
protected abstract void addCondiments();
}
2 具体实现类 - 咖啡
public class Coffee extends Beverage {
@Override
protected void brew() {
System.out.println("冲泡咖啡粉");
}
@Override
protected void addCondiments() {
System.out.println("添加糖和牛奶");
}
}
3 具体实现类 - 茶
public class Tea extends Beverage {
@Override
protected void brew() {
System.out.println("浸泡茶叶");
}
@Override
protected void addCondiments() {
System.out.println("添加柠檬");
}
}
增强版 - 带钩子方法的模板模式
public abstract class BeverageWithHook {
// 模板方法
public final void prepareRecipe() {
boilWater();
brew();
pourInCup();
// 钩子方法 - 让子类决定是否执行
if (customerWantsCondiments()) {
addCondiments();
}
}
private void boilWater() {
System.out.println("煮沸水");
}
private void pourInCup() {
System.out.println("倒入杯中");
}
protected abstract void brew();
protected abstract void addCondiments();
// 钩子方法 - 默认返回true,子类可以覆盖
protected boolean customerWantsCondiments() {
return true;
}
}
// 咖啡实现
public class CoffeeWithHook extends BeverageWithHook {
@Override
protected void brew() {
System.out.println("冲泡咖啡粉");
}
@Override
protected void addCondiments() {
System.out.println("添加糖和牛奶");
}
// 覆盖钩子方法
@Override
protected boolean customerWantsCondiments() {
return askUser();
}
private boolean askUser() {
System.out.print("是否要添加调料?(y/n): ");
Scanner scanner = new Scanner(System.in);
String answer = scanner.nextLine();
return answer.toLowerCase().startsWith("y");
}
}
更复杂的案例 - 数据迁移框架
// 数据迁移模板
public abstract class DataMigration {
// 模板方法 - 定义迁移流程
public final void migrate() {
backup();
validateSource();
extractData();
transformData();
loadData();
cleanup();
}
protected void backup() {
System.out.println("执行数据备份...");
// 通用备份逻辑
}
protected void cleanup() {
System.out.println("清理临时资源...");
// 通用清理逻辑
}
protected abstract void validateSource();
protected abstract void extractData();
protected abstract void transformData();
protected abstract void loadData();
}
// MySQL到Oracle的迁移
public class MySqlToOracleMigration extends DataMigration {
@Override
protected void validateSource() {
System.out.println("验证MySQL数据完整性和约束...");
}
@Override
protected void extractData() {
System.out.println("从MySQL提取数据...");
// MySQL特定的提取逻辑
}
@Override
protected void transformData() {
System.out.println("转换数据类型:MySQL类型 -> Oracle类型...");
// 数据类型映射
}
@Override
protected void loadData() {
System.out.println("批量加载数据到Oracle...");
// Oracle批量插入逻辑
}
}
// 文件到MongoDB的迁移
public class FileToMongoMigration extends DataMigration {
@Override
protected void backup() {
// 覆盖默认备份
System.out.println("文件迁移不需要备份,跳过");
}
@Override
protected void validateSource() {
System.out.println("检查文件格式和编码...");
}
@Override
protected void extractData() {
System.out.println("读取文件内容...");
}
@Override
protected void transformData() {
System.out.println("转换为BSON文档格式...");
}
@Override
protected void loadData() {
System.out.println("写入MongoDB...");
}
}
测试代码
public class TemplateMethodDemo {
public static void main(String[] args) {
System.out.println("=== 咖啡制作 ===");
Beverage coffee = new Coffee();
coffee.prepareRecipe();
System.out.println("\n=== 茶制作 ===");
Beverage tea = new Tea();
tea.prepareRecipe();
System.out.println("\n=== 带钩子的咖啡制作 ===");
BeverageWithHook coffeeWithHook = new CoffeeWithHook();
coffeeWithHook.prepareRecipe();
System.out.println("\n=== 数据迁移 ===");
DataMigration migration = new MySqlToOracleMigration();
migration.migrate();
System.out.println("\n=== 文件迁移 ===");
DataMigration fileMigration = new FileToMongoMigration();
fileMigration.migrate();
}
}
输出结果
=== 咖啡制作 ===
煮沸水
冲泡咖啡粉
倒入杯中
添加糖和牛奶
=== 茶制作 ===
煮沸水
浸泡茶叶
倒入杯中
添加柠檬
=== 带钩子的咖啡制作 ===
煮沸水
冲泡咖啡粉
倒入杯中
是否要添加调料?(y/n): y
添加糖和牛奶
=== 数据迁移 ===
执行数据备份...
验证MySQL数据完整性和约束...
从MySQL提取数据...
转换数据类型:MySQL类型 -> Oracle类型...
批量加载数据到Oracle...
清理临时资源...
=== 文件迁移 ===
文件迁移不需要备份,跳过
检查文件格式和编码.....
转换为BSON文档格式...
写入MongoDB...
清理临时资源...
框架中的应用案例
1 Spring Framework中的JdbcTemplate
public class JdbcTemplateExample {
public class User {
private Long id;
private String name;
private String email;
// getters and setters...
}
public class UserRowMapper implements RowMapper<User> {
@Override
public User mapRow(ResultSet rs, int rowNum) throws SQLException {
User user = new User();
user.setId(rs.getLong("id"));
user.setName(rs.getString("name"));
user.setEmail(rs.getString("email"));
return user;
}
}
public void queryExample() {
// JdbcTemplate定义查询模板
String sql = "SELECT * FROM users WHERE id = ?";
// 不需要管理连接、声明、结果集等资源
User user = jdbcTemplate.queryForObject(
sql,
new Object[]{1L},
new UserRowMapper()
);
}
}
优缺点
优点:
- ✅ 封装不变部分,扩展可变部分
- ✅ 提取公共代码,便于维护
- ✅ 行为由父类控制,子类实现具体细节
缺点:
- ❌ 不同实现都需要定义一个子类,导致类数量增加
- ❌ 父类修改算法骨架,子类无法感知
适用场景
- 多个类有相同的方法并且逻辑相同 - 抽取到抽象类
- 需要控制子类扩展 - 算法骨架固定
- 需要复用一个算法的不同变体 - 子类实现不同步骤
这个模式在实际开发中非常常见,特别是在框架设计中,它完美体现了"开闭原则"——对扩展开放,对修改关闭。