Template Method(模式方法) 行为型 类 1
Intent_意图2
在一个方法中定义一个算法的骨架 ,而将一些步骤延迟到子类中。模板方法使得子类可以在不改变算法结构的情况下,重新定义算法中的某些步骤
Motivation_动机3
确保算法的结构保持不变,同时由子类提供部分实现
Applicability_适用性4
在算法结构部分通用的情况
Structure_结构5
Participants_参与者6
- AbstractTemplate(抽象模板) 负责定义算法的基本结构
- ConcreteTemplate(具体模板) 实现AbstractTemplate中定义的抽象方法和钩子方法
Collaborations_协作7
- AbstractTemplate定义一个算法结构以及组成步骤,由一个模板方法和若干个基本方法构成
-> 模板方法:定义了算法的结构,按某种顺序调用其包含的基本方法
-> 基本方法:整个算法中的一个步骤,包含以下类型
抽象方法 在AbstractTemplate中声明,由ConcreteTemplate实现
具体方法 在AbstractTemplate中已经实现,在ConcreteTemplate中可以继承或重写
钩子方法 在AbstractTemplate中已经实现,包括用于判断的逻辑方法和需要ConcreteTemplate重写的空方法两种
Comsequences_结果8
- 优点
封装不变部分,扩展可变部分
提供公共部分代码,便于维护
行为由父类控制,子类实现 - 缺点
不同的实现需要增加一个新的子类 - 用途
有多个子类共有的方法,且逻辑相同
重复的、复杂的,可考虑作为模板的逻辑结构
Implementation/Sample Code_实现/范例代码910
Implementation
AbstractTemplate
public abstract class AbstractTemplate {
public void templateMethod() {
abstractMethod();
hookMethod();
concreteMethod();
}
protected void abstractMethod();
protected void hookMethod();
private void concreteMethod() {
// TODO
}
}
ConcreteTemplate
public class ConcreteTemplate extends AbstractTemplate {
@Override
public void abstractMethod() {
// TODO
}
@Override
public void hookMethod() {
// TODO
}
}
Sample Code
AbstractTemplate
public abstract class CaffeineBeverageWithHook {
void prepareRecipe() {
boilWater();
brew();
pourInCup();
if (customerWantsCondiments()) {
addCondiments();
}
}
abstract void brew();
abstract void addCondiments();
void boilWater() {
System.out.println("Boiling water");
}
void pourInCup() {
System.out.println("Pouring into cup");
}
// Hook 子类可以覆盖这个方法,但不见得一定要这么做
boolean customerWantsCondiments() {
return true;
}
}
ConcreteTemplate
public class CoffeeWithHook extends CaffeineBeverageWithHook {
@Override
void brew() {
System.out.println("Dripping Coffee through filter");
}
@Override
void addCondiments() {
System.out.println("Adding Sugar and Milk");
}
@Override
public boolean customerWantsCondiments() {
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.out.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 customerWantsCondiments() {
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.out.println("IO error trying to read your answer");
}
if (answer == null) {
return "no";
}
return answer;
}
}
Client
public class BeverageTestDrive {
public static void main(String[] args) {
TeaWithHook teaHook = new TeaWithHook();
CoffeeWithHook coffeeHook = new CoffeeWithHook();
System.out.println("\nMaking tea...");
teaHook.prepareRecipe();
System.out.println("\nMaking coffee...");
coffeeHook.prepareRecipe();
}
}
Result
Making tea...
Boiling water
Steeping the tea
Pouring into cup
Would you like lemon with your tea (y/n)?
y
Adding Lemon
Making coffee...
Boiling water
Dripping Coffee through filter
Pouring into cup
Would you like milk and sugar with your coffee (y/n)?
n
Known Uses_已知应用11
Related Patterns_相关模式12
模式分类归属 ↩︎
意图:描述该模式的作用,以及该模式的定义 ↩︎
动机:给出了问题以及如何解决这个问题的具体场景 ↩︎
适用性:描述模式可以被应用在什么场合 ↩︎
结构:提供了图示,显示出参与此模式的类之间的关系 ↩︎
参与者:描述在此设计中所涉及到的类和对象在模式中的责任和角色 ↩︎
协作 :告诉参与者如何在此模式中合作 ↩︎
结果:描述采用此模式之后可能产生的效果,好的与不好的 ↩︎
实现:提供了在实现该模式时需要使用的技巧,以及应该小心面对的问题 ↩︎
范例代码:提供代码的片段 ↩︎
已知应用:用来描述已经在真实系统中发现的模式例子 ↩︎
相关模式:描述了此模式和其他模式之间的关系 ↩︎