Template Method 是一种行为设计模式,它在父类中定义了一个算法的框架,允许子类在不改变算法结构的情况下重写算法的特定步骤。
核心思想
-
固定算法骨架:将不变的部分(算法步骤)放到父类中实现
-
可变部分抽象:将可能变化的部分抽象为方法,由子类实现
-
好莱坞原则:"Don't call us, we'll call you" - 父类控制流程,子类提供实现
主要角色
-
AbstractClass(抽象类):定义模板方法和抽象步骤
-
ConcreteClass(具体子类):实现抽象步骤
使用Template Method模板方法模式模拟一个饮料制作系统。
场景描述
我们实现一个饮料制作系统,咖啡和茶的制作流程基本相同(煮沸水->冲泡->倒入杯子->加调料),但具体冲泡方式和调料不同。
首先定义一个抽象类
// 1. 抽象类(定义模板方法)
abstract class Beverage {
// 模板方法(final防止子类覆盖算法结构)
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. 具体子类:咖啡
class Coffee extends Beverage {
@Override
protected void brew() {
System.out.println("用沸水冲泡咖啡粉");
}
@Override
protected void addCondiments() {
System.out.println("加糖和牛奶");
}
}
// 3. 具体子类:茶
class Tea extends Beverage {
@Override
protected void brew() {
System.out.println("用沸水浸泡茶叶");
}
@Override
protected void addCondiments() {
System.out.println("加柠檬");
}
}
模拟这一个过程
// 4. 客户端
public class Main {
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();
}
}
输出结果
模式特点
-
模板方法:
-
必须是
final
方法,防止子类修改算法结构 -
包含固定步骤和抽象方法调用
-
-
钩子方法(可选):
// 在抽象类中添加钩子方法 protected boolean customerWantsCondiments() { return true; // 默认加调料 } // 修改模板方法 public final void prepareRecipe() { boilWater(); brew(); pourInCup(); if (customerWantsCondiments()) { addCondiments(); } } // 子类可以覆盖钩子方法 class Coffee extends Beverage { @Override protected boolean customerWantsCondiments() { return false; // 咖啡不加调料 } }
模式优势
-
代码复用:将公共代码放在父类中
-
扩展可控:子类只能改变特定步骤,不能改变流程
-
符合开闭原则:新增饮料类型只需添加子类
实际应用场景
-
框架设计(如Spring的JdbcTemplate)
-
算法骨架固定但部分步骤可变的情况
-
需要控制子类扩展点的场景
Spring中的模板方法示例:
public abstract class JdbcTemplate {
public final Object execute(String sql) {
Connection con = getConnection();
Statement stmt = con.createStatement();
ResultSet rs = stmt.executeQuery(sql);
Object result = doInStatement(rs); // 抽象方法
release(con, stmt, rs);
return result;
}
protected abstract Object doInStatement(ResultSet rs);
}
通过这个饮料制作的例子,你可以清晰看到模板方法模式如何固定流程框架,同时允许灵活变化具体实现。