一、模板方法引入:泡茶与冲咖啡
-
泡茶
- 烧水
- 泡茶
- 倒入杯子
- 加入柠檬
-
冲咖啡
- 烧水
- 冲咖啡
- 倒入杯子
- 加入牛奶和糖
二、模板方法,TemplateMethod
2.1 Intent 意图
-
Define the skeleton of an algorithm in an operation, deferring some steps to lets subclasses redefine certain steps of an algorithm without changing the algorithm’s structure. 在操作中定义算法的骨架,延迟一些步骤,让子类在不改变算法结构的情况下重新定义算法的某些步骤。
-
“Hook”: Control subclasses extensions(“钩子”:控制子类扩展)
- You can define a template method that calls “hook” operations at specific points, thereby permitting extensions only at those points. 可以定义一个在特定点上调用“钩子”操作的模板方法,并只允许在这些点上进行扩展。
2.2 Applicability 适用性
- To implement the invariant parts of an algorithm once and leave it up to subclasses to implement the behavior that can vary. 一次实现算法的不变部分,并将其留给子类来实现可能发生变化的行为.
- When common behavior among subclasses should be factored and localized in a common class to avoid code duplication. 当子类之间的公共行为应该在一个公共类中被分解和本地化,以避免代码重复时.
- Control subclasses extensions.
2.3 类图
2.4 模板方法类实现要点
- 模板方法类为抽象类
- 模板方法 final 修饰
- 最小化原始操作:抽象方法与公用方法
- An important goal in designing template methods is to minimize the number of primitive operations that a subclass must override to flesh out the algorithm. 设计模板方法的一个重要目标是最小化子类必须覆盖的原始操作的数量
2.5 应用实例
HttpServlet in JavaEE:service()
2.6 泡茶与冲咖啡
- 饮品类
public abstract class Beverage {
final void prepareBeverage() {
boilWater();
brew();
pourInCup();
if (wantCondiments()) {
addCondiments();
}
}
// Hock:冲泡
abstract void brew();
// Hock:加入调味品
abstract void addCondiments();
private void boilWater() {
System.out.println("Begin boil water! ...... Done!");
}
private void pourInCup() {
System.out.println("Pour in cup!");
}
// Hook:默认需要调味品,子类可重写
boolean wantCondiments() {
return true;
}
}
- 咖啡
public class CoffeeBeverage extends Beverage {
@Override
protected void brew() {
System.out.println("Brew coffee!");
}
@Override
protected void addCondiments() {
System.out.println("Add milk and sugar to coffee!");
}
}
- 茶
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
public class TeaBeverage extends Beverage {
@Override
protected void brew() {
System.out.println("Brew tea!");
}
@Override
protected void addCondiments() {
System.out.println("Add lemon to tea");
}
@Override
boolean wantCondiments() {
BufferedReader bf = new BufferedReader(new InputStreamReader(System.in));
System.out.println("Would you like to add lemon to tea? Please Enter yes or no(default no)!");
String ans = null;
try {
ans = bf.readLine();
} catch (IOException e) {
System.out.println("Error input!");
}
if (ans == null || "no".equalsIgnoreCase(ans)) {
return false;
}
return "yes".equalsIgnoreCase(ans);
}
}
- Demo for test
public class TemplateDemo {
public static void main(String[] args) {
Beverage coffee = new CoffeeBeverage();
coffee.prepareBeverage();
System.out.println("\n");
Beverage tea = new TeaBeverage();
tea.prepareBeverage();
}
}
- Output