模板方法模式(Template)

  ——在一个方法中定义了一个算法的骨架,而将一些步骤延迟到子类中。模板方法使得子类可以在不改变算法结构的情况下,重新定义算法中的某些步骤。

  • 好莱坞原则:别调用(打电话给)我们,我们会调用(打电话给)你。
  • 要点:
  1. 模板方法的抽象类可以定义具体方法、抽象方法和钩子。抽象方法由子类实现。
  2. 钩子是一种方法,在抽象类中不做事,或只做默认的事,子类可以选择要不要覆盖它。
  3. 为了防止子类改变模板方法中的算法,可以将模板方法声明为final。
  4. 好莱坞原则告诉我们,将决策权放在高层模块中,以便决定如何以及何时调用低层模块。
  5. 策略模式和模板方法模式都封装算法,一个用组合,一个用继承。
  6. 工厂方法(由子类决定实例化哪个具体类)是模板方法(子类决定如何实现算法中的步骤)的一种特殊版本。

示例:

咖啡冲泡法

  1. 把水煮沸
  2. 用沸水冲泡咖啡
  3. 把咖啡倒进杯子
  4. 加糖和牛奶

茶冲泡法

  1. 把水煮沸
  2. 用沸水冲泡茶叶
  3. 把茶倒进杯子
  4. 加柠檬

茶和咖啡是如此得相似,似乎我们应该将共同的部分抽取出来,放进一个基类中。

 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 abstract class AbstractClass {
// 这就是模板方法。它被声明为final,以免子类改变这个算法的顺序。
final void templateMethod() {
// 模板方法定义了一连串的步骤,每个步骤由一个方法代表
primitiveOperation1();
primitiveOperation2();
concreteOperation();
} // 在这个范例中有两个原语操作,具体子类必须实现它们
abstract void primitiveOperation1();
abstract void primitiveOperation2(); // 这个抽象类有一个具体的操作。
void concreteOperation() {
// ...
}
}

接着需要处理咖啡和茶类,这两个类现在都是依赖超类来处理冲泡法,所以只需要自行处理冲泡和添加调料部分:

 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 CaffeineBeverageWithHook {
final void prepareRecipe() {
boilWater();
brew();
pourInCup();
// 我们加上了一个小小的条件语句,而该条件是否成立,
// 是由一个具体方法customerWantsCondiments()决定的。
// 如果顾客“想要”调料,只有这时我们才调用addCondiments()。
if (customerWantsCondiments()) {
addCondiments();
}
} abstract void addCondiments();
abstract void brew(); public void boilWater() {
System.out.println("Boiling water");
} public void pourInCup() {
System.out.println("Pouring into cup");
} // 我们在这里定义了一个方法,(通常)是空的缺省实现。这个方法只会返回true,不做别的事。
// 这就是一个钩子,子类可以覆盖这个方法,但不见得一定要这么做。
boolean customerWantsCondiments() {
return true;
}
}

用模板方法排序

  Java数组类的设计者提供给我们一个方便的模板方法用来排序。必须实现Comparable接口,提供这个接口所声明的compareTo()方法。

其他模板方法实例

  1. java.io的InputStream类有一个read()方法,是由子类实现的,而这个方法又会被read(byte b[], int off, int len)模板方法使用。
  2. Swing的JFrame继承了一个paint()方法。在默认状态下,paint()是不做事情的,因为它是一个“钩子”。通过覆盖paint(),可以将自己的代码插入JFrame的算法中,显示出想要的画面。
  3. applet是一个能在网页上面执行的小程序。任何applet必须继承自Applet类,而Applet类中提供了好些钩子。

《Head First 设计模式》之模板方法模式——冲泡咖啡和茶的更多相关文章

  1. 乐在其中设计模式(C#) - 模板方法模式(Template Method Pattern)

    原文:乐在其中设计模式(C#) - 模板方法模式(Template Method Pattern) [索引页][源码下载] 乐在其中设计模式(C#) - 模板方法模式(Template Method ...

  2. 折腾Java设计模式之模板方法模式

    博客原文地址:折腾Java设计模式之模板方法模式 模板方法模式 Define the skeleton of an algorithm in an operation, deferring some ...

  3. js设计模式——6.模板方法模式与职责链模式

    js设计模式——6.模板方法模式与职责链模式 职责链模式

  4. Head First设计模式之模板方法模式

    一.定义 在一个方法中定义一个算法的骨架,而将一些步骤延迟到子类中,使得子类可以不改变算法结构的情况下,重定义该算法中的某些特定步骤. 比较通俗的说法,子类决定如何实现算法中的某些步骤,比如两个一连串 ...

  5. [C++设计模式]template 模板方法模式

    模板法模式:定义一个操作中的算法骨架.而将一些步骤延迟到子类中. 依照<headfirst 设计模式>的样例.煮茶和煮咖啡的算法框架(流程)是一样的.仅仅是有些算法的实现是不一样的,有些是 ...

  6. 软件设计模式之模板方法模式(JAVA)

    什么是模板方法模式? 定义一个操作中算法的骨架,而将这些步骤延迟到子类中,模板方法使得子类可以不改变一个算法的结构即可重新定义该算法的某些特定步骤. 好抽象的概念啊,文绉绉的东西就是不讨人喜欢,下面我 ...

  7. java设计模式之模板方法模式

    模板方法模式 定义一个操作中的算法的骨架,而将一些步骤延迟到子类中. 模板方法使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤.通俗的说的就是有很多相同的步骤的,在某一些地方可能有一些差 ...

  8. Head First 设计模式 --8 模板方法模式 别找我,我会找你

    模板方法模式:在一个方法中定义一个算法的骨架,而将一些步骤延迟到子类中.模板方法使得子类可以在不改变算法结构的情况下,重新定义算法中的某些步骤.设计原则:1.封装变化2.多用组合少用集成3.针对接口变 ...

  9. C#设计模式(14)——模板方法模式(Template Method)

    一.引言 提到模板,大家肯定不免想到生活中的“简历模板”.“论文模板”.“Word中模版文件”等,在现实生活中,模板的概念就是——有一个规定的格式,然后每个人都可以根据自己的需求或情况去更新它,例如简 ...

随机推荐

  1. R中的统计模型

    R中的统计模型 这一部分假定读者已经对统计方法,特别是回归分析和方差分析有一定的了解.后面我们还会假定读者对广义线性模型和非线性模型也有所了解.R已经很好地定义了统计模型拟合中的一些前提条件,因此我们 ...

  2. 6、git和github

    参考:http://www.cnblogs.com/qianmojing/p/6484162.htmlhttp://www.jb51.net/article/70729.htmhttp://www.c ...

  3. storm定时器timer源码分析-timer.clj

    storm定时器与java.util.Timer定时器比较相似.java.util.Timer定时器实际上是个线程,定时调度所拥有的TimerTasks:storm定时器也有一个线程负责调度所拥有的& ...

  4. Java数组转置

    数组转置,就是将打印的数组的列和行进行位置对换. 我们就可以用两个for循环遍历数组,然后交换arr[i][j]与arr[j][i] public class Demo{ public static ...

  5. LOJ6235 区间素数个数(min_25筛)

    题目链接:LOJ 题目大意:看到题目名字应该都知道是啥了吧. $1\le N\le 10^{11}$. 阉割版 min_25 筛.发现答案实际上就是 min_25 筛中 $g(N,pl)$ 的值.(取 ...

  6. flask-sqlalchemy中 backref lazy的参数实例解释和选择

    官方文档:http://docs.sqlalchemy.org/en/rel_1_0/orm/basic_relationships.html#relationship-patterns 最近在学习到 ...

  7. Extensions for Vue

    Extensions for Vue Original post url:https://www.cnblogs.com/markjiang7m2/p/10833790.html If you are ...

  8. Maven项目骨架搭建

    1. 如何使用Maven的archetype快速生成一个新项目 2. Maven之自定义archetype生成项目骨架(一) 3. 使用maven3 创建自定义的archetype 4. 使用mave ...

  9. 洛谷P1072 Hankson 的趣味题

    P1072 Hankson 的趣味题 题目描述 Hanks 博士是 BT (Bio-Tech,生物技术) 领域的知名专家,他的儿子名叫 Hankson.现在,刚刚放学回家的 Hankson 正在思考一 ...

  10. Oracle表连接(转)

    表之间的连接 Join是一种试图将两个表结合在一起的谓词,一次只能连接2个表,表连接也可以被称为表关联.在后面的叙述中,我们将会使用”row source”来代替”表”,因为使用row source更 ...