模板方法模式定义了一个算法的骨架, 并允许子类在不改变算法结构的情况下重新定义算法的某些步骤. 通过这种方式, 实现了代码的复用与拓展

模板方法模式结构

  • 抽象类: 定义了算法的骨架, 包含一个模板方法. 这个模板方法定义了算法的步骤, 并且某些步骤可以调用抽象方法或钩子方法, 允许子类自行实现
  • 具体类: 继承自抽象类, 实现抽象方法或钩子方法, 以完成算法的具体步骤

模板方法模式实现

以下是一个简单的模板方法模式实现. 我们以制作咖啡和茶为例, 以饮料类作为抽象类, 而咖啡和茶作为具体类

abstract class Beverage {
// 模板方法, 定义了算法步骤
public final void perpareBeverage() {
boilWater();
brew();
pourInCup();
if (customerWantCondiments()) {
addCondiments();
}
}

// 具体方法
private void boilWater() {
System.out.println("Boiling water.");
}

// 抽象方法
abstract void brew();

// 具体方法
private void pourInCup() {
System.out.println("Pouring into cup.");
}

// 钩子方法
boolean customerWantCondiments() {
return true;
}

// 抽象方法
abstract void addCondiments();
}

class Tea extends Beverage {
void brew() {
System.out.println("Steeping the tea.");
}

void addCondiments() {
System.out.println("Adding lemon.");
}
}

class Coffee extends Beverage {
void brew() {
System.out.println("Dripping coffee through filter.");
}

void addCondiments() {
System.out.println("Adding Sugar and milk.");
}

// 覆盖钩子方法
@Override
boolean customerWantCondiments() {
return false;
}
}

public class Client {
public static void main(String[] args) {
Beverage tea = new Tea();
tea.prepareBeverage();
System.out.println();
Beverage coffee = new Coffee();
coffee.prepareBeverage();
}
}

优点:

  • 提高代码复用性: 将相同部分代码放在父类, 不同代码放入不同子类
  • 实现反转控制: 通过一个父类调用子类的操作, 通过对子类的具体实现拓展不同的行为, 实现了反向控制, 符合开闭原则

缺点:

  • 对每个不同的实现都要实现一个子类, 会使得类个数增加
  • 父类中的抽象方法由子类实现, 子类执行的结果会影响父类的结果, 这导致一种反向的控制结构, 提高了代码阅读难度