模板方法(Template Method)
模板方法模式——在一个方法中定义了一个算法的骨架,而将一些步骤延迟到子类中。模板方法使得子类可以在不改变算法结构的情况下,重新定义算法中的某些步骤。
原则
好莱坞原则:别调用(打电话给)我们,我们会调用(打电话给)你。
(封装算法块)
类图
Code
origin
// 这是我们的咖啡类,用来煮咖啡
public class Coffee {
// 这是我们的咖啡冲泡法
void prepareRecipe() {
boilWater();
brewCoffeeGrinds();
pourInCup();
addSugerAndMilk();
}
// 煮沸水
private void boilWater() {
System.out.println("Boiling water");
}
// 冲泡咖啡
private void brewCoffeeGrinds() {
System.out.println("Dripping coffee through filter");
}
// 把咖啡倒进杯子
private void pourInCup() {
System.out.println("Pouring into cup");
}
// 加糖和奶
private void addSugerAndMilk() {
System.out.println("Adding Sugar and Milk");
}
}
// 这是我们的茶类,用来煮茶
public class Tea {
void prepareRecipe() {
boilWater();
steepTeaBag();
pourInCup();
addLemon();
}
// 煮沸水。这个方法和咖啡类完全一样
private void boilWater() {
System.out.println("Boiling water");
}
// 冲泡茶叶
private void steepTeaBag() {
System.out.println("Steeping the tea");
}
// 把茶倒进杯子。这个方法和咖啡类完全一样
private void pourInCup() {
System.out.println("Pouring into cup");
}
// 加柠檬
private void addLemon() {
System.out.println("Adding Lemon");
}
}
改进
public abstract class CaffeineBeverage {
// 现在,用同一个prepareRecipe()方法来处理茶和咖啡。
// prepareRecipe()方法被声明为final,因为我们不希望子类覆盖这个方法
// 我们将第2步和第4步泛化成为brew()和addCondiments()
final void prepareRecipe() {
boilWater();
brew();
pourInCup();
addCondiments();
}
// 因为咖啡和茶处理这些方法的做法不同,所以这两个方法必须被声明为抽象,
// 剩余的东西留给子类去操心
abstract void addCondiments();
abstract void brew();
public void boilWater() {
System.out.println("Boiling water");
}
public void pourInCup() {
System.out.println("Pouring into cup");
}
}
// 自行处理冲泡和添加调料部分:
public class Coffee extends CaffeineBeverage {
@Override
void brew() {
System.out.println("Dripping coffee through filter");
}
@Override
void addCondiments() {
System.out.println("Adding Sugar and Milk");
}
}
public class Tea extends CaffeineBeverage {
@Override
void brew() {
System.out.println("Steeping the tea");
}
@Override
void addCondiments() {
System.out.println("Adding Lemon");
}
}
模板方法
// 这就是我们的抽象类。它被声明为抽象,用来作为基类,其子类必须实现其操作
public abstract class AbstractClass {
// 这就是模板方法。它被声明为final,以免子类改变这个算法的顺序。
final void templateMethod() {
// 模板方法定义了一连串的步骤,每个步骤由一个方法代表
primitiveOperation1();
primitiveOperation2();
concreteOperation();
}
// 在这个范例中有两个原语操作,具体子类必须实现它们
abstract void primitiveOperation1();
abstract void primitiveOperation2();
// 这个抽象类有一个具体的操作。
void concreteOperation() {
// ...
}
}
钩子
public abstract class AbstractClass {
final void templateMethod() {
primitiveOperation1();
primitiveOperation2();
concreteOperation();
// 我们加进一个新方法调用
hook();
}
// 这两个方法还是和以前一样,定义成抽象,由具体的子类实现。
abstract void primitiveOperation1();
abstract void primitiveOperation2();
// 这个具体的方法被定义在抽象类中。
// 将它声明为final,这样一来子类就无法覆盖它。
// 它可以被模板方法直接使用,或者被子类使用。
final void concreteOperation() {
// ...
}
// 我们也可以有“默认不做事的方法”,我们称这种方法为“hook”(钩子)。
// 子类可以视情况决定要不要覆盖它们。在下面,我们就会知道钩子的实际用途
void hook() {}
}
Reference
http://cashow.github.io/head-first-design-patterns-notes-template-method-pattern.html