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()
);
}
}
优缺点
优点:
- ✅ 封装不变部分,扩展可变部分
- ✅ 提取公共代码,便于维护
- ✅ 行为由父类控制,子类实现具体细节
缺点:
- ❌ 不同实现都需要定义一个子类,导致类数量增加
- ❌ 父类修改算法骨架,子类无法感知
适用场景
- 多个类有相同的方法并且逻辑相同 - 抽取到抽象类
- 需要控制子类扩展 - 算法骨架固定
- 需要复用一个算法的不同变体 - 子类实现不同步骤
这个模式在实际开发中非常常见,特别是在框架设计中,它完美体现了"开闭原则"——对扩展开放,对修改关闭。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播