模板方法模式是一种行为设计模式,它定义了一个算法的骨架,将某些步骤延迟到子类中实现。通过模板方法,子类可以重定义算法的某些步骤,而不会改变算法的结构。
场景示例:茶(Tea)和咖啡(Coffee)的制作过程
制作茶和咖啡的过程有很多相似之处,但也有一些不同点。我们可以用模板方法模式来抽象出制作饮品的通用流程,并在子类中实现具体的操作。
制作茶和咖啡的步骤:
- 把水煮沸。
- 冲泡饮料(茶用茶叶,咖啡用咖啡粉)。
- 将饮料倒入杯子。
- 如果需要,可以添加配料(茶加柠檬,咖啡加糖和牛奶)。
代码实现:
1. 创建模板类 CaffeineBeverage
CaffeineBeverage
是一个抽象类,它包含了制作饮料的模板方法 prepareRecipe()
。这个方法定义了制作饮品的骨架,而其中某些步骤由子类实现。
java
public abstract class CaffeineBeverage {
// 模板方法,定义了制作饮料的骨架
public final void prepareRecipe() {
boilWater();
brew();
pourInCup();
if (customerWantsCondiments()) { // 钩子方法
addCondiments();
}
}
// 具体步骤:把水煮沸
private void boilWater() {
System.out.println("Boiling water");
}
// 具体步骤:将饮料倒入杯子
private void pourInCup() {
System.out.println("Pouring into cup");
}
// 抽象步骤:冲泡饮料
protected abstract void brew();
// 抽象步骤:添加配料
protected abstract void addCondiments();
// 钩子方法,子类可以覆盖此方法来改变算法的行为
protected boolean customerWantsCondiments() {
return true; // 默认添加配料
}
}
2. 实现具体类 Tea
Tea
类继承自 CaffeineBeverage
,并实现了冲泡和添加配料的具体逻辑。
java
public class Tea extends CaffeineBeverage {
@Override
protected void brew() {
System.out.println("Steeping the tea");
}
@Override
protected void addCondiments() {
System.out.println("Adding Lemon");
}
// 重写钩子方法,如果不需要配料
@Override
protected boolean customerWantsCondiments() {
return false; // 比如有时候顾客不想要加柠檬
}
}
3. 实现具体类 Coffee
Coffee
类同样继承自 CaffeineBeverage
,并实现了冲泡和添加配料的具体逻辑。
java
public class Coffee extends CaffeineBeverage {
@Override
protected void brew() {
System.out.println("Dripping coffee through filter");
}
@Override
protected void addCondiments() {
System.out.println("Adding Sugar and Milk");
}
}
4. 测试客户端
在客户端中,我们可以通过调用 prepareRecipe()
方法来制作茶和咖啡。
java
public class BeverageTest {
public static void main(String[] args) {
System.out.println("Making tea...");
CaffeineBeverage tea = new Tea();
tea.prepareRecipe();
System.out.println("\nMaking coffee...");
CaffeineBeverage coffee = new Coffee();
coffee.prepareRecipe();
}
}
输出结果
plaintext
Making tea...
Boiling water
Steeping the tea
Pouring into cup
Making coffee...
Boiling water
Dripping coffee through filter
Pouring into cup
Adding Sugar and Milk
代码解释
-
CaffeineBeverage
:这个抽象类定义了制作饮料的模板方法prepareRecipe()
,这个方法包含制作饮品的通用步骤。brew()
和addCondiments()
是抽象方法,由具体的子类实现。 -
Tea
和Coffee
类 :这两个类继承自CaffeineBeverage
并实现了冲泡和添加配料的具体逻辑。比如,Tea
中冲泡茶叶,Coffee
中使用滤器冲泡咖啡。 -
钩子方法 :
customerWantsCondiments()
是一个可选的钩子方法,子类可以覆盖它来决定是否添加配料。比如,在Tea
中,我们重写了该方法,返回false
,表示不需要配料。 -
模板方法 :
prepareRecipe()
是模板方法,它控制了制作饮料的整个流程,子类无法改变这个流程的结构,只能改变其中的部分实现。
优点
- 代码复用:公共的操作步骤在模板类中实现,避免代码重复。
- 灵活性:通过钩子方法可以让子类决定是否执行某些步骤,而不会影响整体的算法结构。
使用场景
- 适合具有统一流程结构、但某些步骤不同的场景。
- 需要对算法步骤进行扩展或修改时,避免重复代码。
通过模板方法模式,可以灵活地定义算法的通用框架,并将部分实现留给子类完成,增加了代码的可扩展性和灵活性。