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