模版方法模式在一个方法中定义一个算法的骨架,而将一些步骤延迟到子类中。模版方法使得子类可以在不改变算法结构的情况下,重新定义算法中的某些步骤。
我们以咖啡和茶为例,举例如何将咖啡和茶的冲泡代码整合到一个模版方法中。
首先这是咖啡和茶的原本实现方式:
public class Coffee {
public void prepareRecipe() {
boilWafer();
brewCoffeeGrinds();
pourInCup();
addSugarAndMilk();
}
public void boilWafer() {
System.out.println("Boiling wafer");
}
public void brewCoffeeGrinds() {
System.out.println("Dripping Coffee through filter");
}
public void pourInCup() {
System.out.println("Pouring into cup");
}
public void addSugarAndMilk() {
System.out.println("Adding Sugar and Milk");
}
}
public class Tea {
public void prepareRecipe() {
boilWafer();
steepTeaBag();
pourInCup();
addLemon();
}
public void boilWafer() {
System.out.println("Boiling wafer");
}
public void steepTeaBag() {
System.out.println("Steeping the tea");
}
public void addLemon() {
System.out.println("Adding Lemon");
}
public void pourInCup() {
System.out.println("Pouring into cup");
}
}
可以看出咖啡和茶的冲泡方式都是类似的,第一步都是烧开水,然后冲泡料包,紧接着将饮品倒入杯中,最后加入调料。所以我们将这个共性的冲泡流程抽象成模版,形成第二版设计方案:
首先编写出冲泡饮料的模版方法代码:
public abstract class CaffeineBeverage {
final void prepareRecipe() {
boilWafer();
brew();
pourInCup();
addCondiments();
}
abstract void brew();
abstract void addCondiments();
void boilWafer() {
System.out.println("Boiling wafer");
}
void pourInCup() {
System.out.println("Pouring into cup");
}
}
然后所有类似的饮品都实现模版方法的抽象类:
public class Coffee extends CaffeineBeverage {
@Override
void brew() {
System.out.println("Dripping Coffe 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 {
public final void templateMethod() {
primitiveOperation1();
primitiveOperation2();
concreteOperation();
}
public abstract void primitiveOperation1();
public abstract void primitiveOperation2();
public void concreteOperation() {
}
}
我们可以在模版方法中加入一些用法来增加模版方法模式的弹性:
public abstract class CaffeineBeverageWithHook {
final void prepareRecipe() {
boilWafer();
brew();
pourInCup();
if (customerWantsConditions()) {
addCondiments();
}
}
abstract void brew();
abstract void addCondiments();
void boilWafer() {
System.out.println("Boiling wafer");
}
void pourInCup() {
System.out.println("Pouring into cup");
}
boolean customerWantsConditions() {
return true;
}
}
public class CoffeeWithHook extends CaffeineBeverageWithHook {
@Override
void brew() {
System.out.println("Dripping Coffe through filter");
}
@Override
void addCondiments() {
System.out.println("Adding Sugar and Milk");
}
@Override
public boolean customerWantsConditions() {
String answer = getUserInput();
if (answer.toLowerCase().startsWith("y")) {
return true;
} else {
return false;
}
}
private String getUserInput() {
String answer = null;
System.out.println("Would you like milk and sugar with your coffee (y/n)?");
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
try {
answer = in.readLine();
} catch (IOException ioe) {
System.err.println("IO error trying to read your answer");
}
if (answer == null) {
return "no";
}
return answer;
}
}
public class TeaWithHook extends CaffeineBeverageWithHook {
@Override
void brew() {
System.out.println("Steeping the tea");
}
@Override
void addCondiments() {
System.out.println("Adding Lemon");
}
@Override
public boolean customerWantsConditions() {
String answer = getUserInput();
if (answer.toLowerCase().startsWith("y")) {
return true;
} else {
return false;
}
}
private String getUserInput() {
String answer = null;
System.out.println("Would you like lemon with your tea (y/n)?");
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
try {
answer = in.readLine();
} catch (IOException ioe) {
System.err.println("IO error trying to read your answer");
}
if (answer == null) {
return "no";
}
return answer;
}
}
这里使用了一个设计原则,即好莱坞原则:我们允许低层组件挂钩高层组件,但是不能调用高层组件,但是高层组件能调用低层组件,能决定什么时候和怎样使用这些低层组件。这个原则主要想方法依赖腐败,即高层组件和低层组件之间复杂的互相依赖关系。
发表回复