模板方法
模板方法模式是软件设计模式中行为型模式的一种,它通过继承来实现代码复用和流程控制,是一种非常实用且常见的设计模式。
核心思想
定义一个算法的骨架(模板),而将一些步骤延迟到子类中实现。
- 父类(抽象类)中定义了一个完整的、固定的执行流程。
- 这个流程中的某些具体步骤是抽象的,由子类去实现。
- 子类可以在不改变算法整体结构的情况下,重新定义(重写)这些步骤。
换句话说这就像一个“烹饪食谱模板”:
- 食谱规定了步骤:准备食材 → 烹饪 → 装盘 → 上菜。
- 但“烹饪”这一步,可以是“炒”、“煮”、“烤”,由不同的厨师(子类)决定。
主要角色
角色 | 说明 |
---|---|
1. 抽象类(Abstract Class) | 定义算法的骨架(模板方法),包含抽象方法和具体方法。模板方法通常是 final 的,防止被子类修改。 |
2. 模板方法(Template Method) | 在抽象类中定义的 final 方法,它描述了算法的框架,调用其他抽象方法或具体方法。 |
3. 抽象方法(Abstract Methods) | 在抽象类中声明但没有实现的方法,必须由子类实现。代表算法中可变的部分。 |
4. 具体方法(Concrete Methods) | 在抽象类中已经实现的方法,子类可以直接继承使用。代表算法中通用的、不变的部分。 |
5. 钩子方法(Hook Methods) | 在抽象类中实现的空方法或默认实现的方法,子类可以选择性地覆盖。用于“挂钩”到流程中,控制流程或添加可选行为。 |
6. 具体子类(Concrete Class) | 继承抽象类,并实现其中的抽象方法。可以覆盖钩子方法。 |
适用场景
- 多个子类有相同的算法结构,只是某些步骤不同。
- 把公共行为提取到父类,避免代码重复。
- 控制子类的扩展,只允许在特定点进行定制。
- 一次性实现算法的不变部分,并留出可变部分给子类实现。
例子:
java
public abstract class CaffeineBeverage {
// 模板方法:定义了制作热饮的完整流程
// 用 final 修饰,防止子类修改流程
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; // 默认加调料
}
}
java
// 制作咖啡
public class Coffee extends CaffeineBeverage {
@Override
protected void brew() {
System.out.println("用沸水冲泡咖啡");
}
@Override
protected void addCondiments() {
System.out.println("加入糖和牛奶");
}
}
// 制作茶
public class Tea extends CaffeineBeverage {
@Override
protected void brew() {
System.out.println("用沸水浸泡茶叶");
}
@Override
protected void addCondiments() {
System.out.println("加入柠檬");
}
// 覆盖钩子方法:茶不加调料
@Override
protected boolean customerWantsCondiments() {
return false;
}
}
java
public class Client {
public static void main(String[] args) {
CaffeineBeverage coffee = new Coffee();
coffee.prepareRecipe();
// 输出:
// 将水煮沸
// 用沸水冲泡咖啡
// 倒入杯中
// 加入糖和牛奶
System.out.println("--------");
CaffeineBeverage tea = new Tea();
tea.prepareRecipe();
// 输出:
// 将水煮沸
// 用沸水浸泡茶叶
// 倒入杯中
// (没有加调料,因为钩子返回 false)
}
}