• 泡茶?泡咖啡?

  我们用泡茶和泡咖啡两种行为来引入这一设计模式。

  思考一下“泡茶”的过程:

  煮水 -> 用沸水泡茶叶 -> 把茶倒进杯子 -> 放点柠檬之类的佐料。

  然后再看一下“泡咖啡”的过程:

  煮水 -> 用沸水泡咖啡 -> 把咖啡倒进杯子 -> 加牛奶和糖。

  如果我们用两个类去描述这两个过程,很明显会有很多重复的代码(例如 Step1 煮水,Step3 倒进杯子),也有很多相似的代码(Step2 冲泡,Step4 加佐料)。

  将冲泡的过程看做是一个算法,那么这个算法的主架构是一致的:

  煮水 -> 用沸水泡东西 -> 将泡完的东西倒进杯子 -> 加佐料。

  将主过程抽象出来,至于泡什么东西,加什么佐料,就交给子类去实现,这就是模板方法模式。

  • 模板方法模式:

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

  • UML:

  除了上述的四个步骤,这里加了个新的方法:customerWantsCondiments(),因为加佐料这个步骤不是必须的。

  • 模板方法的组成:

  从上面 UML 图,我们能够发现,在抽象类 BeverageDrive 中,一共存在4类方法:

  1. 模板方法:prepareRecipe(),这是算法的主体,在方法内部会调用其他的方法,一般来说是 public final 的。
  2. 抽象方法:brew() & addCondiments(),是算法步骤的“个性”,在 BeverageDrive 中声明为 protected abstract,由子类去实现。
  3. 具体方法:boilWater() & pourInCup(),是算法步骤的“共性”,一般是 private 的。
  4. 钩子方法:customerWantsCondiments,具有空的或是默认的实现。钩子的存在,可以让子类有能力对算法的不同点进行挂钩,选择权在子类手上,一般是 protected 的。
  • 代码:
public abstract class BeverageDrive {

    // Template method
public final void prepareRecipe() {
boilWater();
brew();
pourInCup();
if (customerWantsCondiments()) {
addCondiments();
}
} // Abstract method
protected abstract void brew(); protected abstract void addCondiments(); // Concrete method
private void boilWater() {
System.out.println("Boiling water");
} private void pourInCup() {
System.out.println("Pouring into cup");
} // Hook method
protected boolean customerWantsCondiments() {
return true;
}
}
public final class CoffeeBeverage extends BeverageDrive {

    @Override
public void brew() {
System.out.println("Dripping coffee through filter");
} @Override
public void addCondiments() {
System.out.println("Adding sugar and milk");
} @Override
public boolean customerWantsCondiments() {
return false;
}
}
public final class TeaBeverage extends BeverageDrive {

    @Override
public void brew() {
System.out.println("Steeping the tea");
} @Override
public void addCondiments() {
System.out.println("Adding lemon");
}
}
  • 好莱坞原则:

  好莱坞在寻找演员的时候有一个著名的原则:别打电话给我们,我们会打电话给你。

  这一点在 OO 设计上,被翻译为:别调用我,我会调用你。

  在好莱坞,演员属于低层组件,电影公司属于高层组件。每当电影公司需要演员的时候,都是电影公司打电话通知演员来面试。

  换句话说:高层组件对待低层组件的方式是:别调用我,我会调用你。

  当我们设计模板方法模式的时候,要时刻记得,让父类去调用子类,不要让子类调用父类方法。

  下面看一个不太好的设计:

public abstract class BadBehaviorBeverageDrive {

    protected void boilWater() {
System.out.println("Boiling water");
} protected void pourInCup() {
System.out.println("Pouring into cup");
} protected boolean customerWantsCondiments() {
return true;
}
}
public final class BadBehaviorTeaBeverage extends BadBehaviorBeverageDrive {

    public final void prepareRecipe() {
super.boilWater();
steepTeaBags();
super.pourInCup();
if (super.customerWantsCondiments()) {
addLemon();
}
} private void steepTeaBags() {
System.out.println("Steeping the tea");
} private void addLemon() {
System.out.println("Adding lemon");
}
}

  这个设计,一定意义上来说,达到了代码重用的功能,但是违反了好莱坞原则,不能算是一个合格的设计。

设计模式(二十二)模板方法模式 Template的更多相关文章

  1. 设计模式 ( 十九 ) 模板方法模式Template method(类行为型)

      设计模式 ( 十九 ) 模板方法模式Template method(类行为型) 1.概述 在面向对象开发过程中,通常我们会遇到这样的一个问题:我们知道一个算法所需的关键步骤,并确定了这些步骤的执行 ...

  2. C#设计模式之十四模板方法模式(Template Method)【行为型】

    一.引言 “结构型”的设计模式已经写完了,从今天我们开始讲“行为型”设计模式.现在我们开始讲[行为型]设计模式的第一个模式,该模式是[模板方法],英文名称是:Template Method Patte ...

  3. 模板方法模式 Template method 行为型 设计模式(二十六)

    模板方法模式 Template method 上图为网上百度的一份简历模板截图   相信大家都有求职的经历,那么必然需要简历,写简历的时候,很可能你会网上检索一份简历模板,使用此模板的格式,然后替换为 ...

  4. 二十四种设计模式:模板方法模式(Template Method Pattern)

    模板方法模式(Template Method Pattern) 介绍定义一个操作中的算法的骨架,而将一些步骤延迟到子类中.Template Method使得子类可以不改变一个算法的结构即可重定义该算法 ...

  5. Java设计模式(十二) 策略模式

    原创文章,同步发自作者个人博客,http://www.jasongj.com/design_pattern/strategy/ 策略模式介绍 策略模式定义 策略模式(Strategy Pattern) ...

  6. 备忘录模式 Memento 快照模式 标记Token模式 行为型 设计模式(二十二)

    备忘录模式 Memento   沿着脚印,走过你来时的路,回到原点.     苦海翻起爱恨   在世间难逃避命运   相亲竟不可接近   或我应该相信是缘份   一首<一生所爱>触动了多少 ...

  7. 桥接模式 桥梁模式 bridge 结构型 设计模式(十二)

      桥接模式Bridge   Bridge 意为桥梁,桥接模式的作用就像桥梁一样,用于把两件事物连接起来   意图 将抽象部分与他的实现部分进行分离,使得他们都可以独立的发展.  意图解析 依赖倒置原 ...

  8. Java 设计模式系列(二十)状态模式

    Java 设计模式系列(二十)状态模式 状态模式,又称状态对象模式(Pattern of Objects for States),状态模式是对象的行为模式.状态模式允许一个对象在其内部状态改变的时候改 ...

  9. 小菜学习设计模式(一)—模板方法(Template)模式

    前言 设计模式目录: 小菜学习设计模式(一)—模板方法(Template)模式 小菜学习设计模式(二)—单例(Singleton)模式 小菜学习设计模式(三)—工厂方法(Factory Method) ...

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

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

随机推荐

  1. Countup.js:vue-countup-v2(npm)数字滚动插件

    1.官方地址:http://inorganik.github.io/countUp.js/ 2.官方demo: 3.参数说明: params——start(开始数字).end(结束数字).decima ...

  2. [机器视觉] SIFT特征-尺度不变特征理解

    SIFT特征-尺度不变特征理解 简介 SIFT,即尺度不变特征变换(Scale-invariant feature transform,SIFT),是用于图像处理领域的一种描述.这种描述具有尺度不变性 ...

  3. SG函数入门&&HDU 1848

    SG函数 sg[i]为0表示i节点先手必败. 首先定义mex(minimal excludant)运算,这是施加于一个集合的运算,表示最小的不属于这个集合的非负整数.例如mex{0,1,2,4}=3. ...

  4. Trie入门讲解

    我们常常用Trie(也叫前缀树)来保存字符串集合.如下图所示就是一个Trie. 上图表示的字符串集合为$\{a,to,tea,ted,ten,i,in,inn \}$,每个单词的结束位置对应一个“单词 ...

  5. Connectivity

    6492: Connectivity 时间限制: 1 Sec  内存限制: 128 MB提交: 118  解决: 28[提交][状态][讨论版][命题人:admin] 题目描述 There are N ...

  6. 用Python计算最长公共子序列和最长公共子串

    如何用Python计算最长公共子序列和最长公共子串 1. 什么是最长公共子序列?什么是最长公共子串? 1.1. 最长公共子序列(Longest-Common-Subsequences,LCS) 最长公 ...

  7. java 自定义一个容器类

    public class ArrayList { public int index = 0; Object[] objects = new Object[2]; public void add(Obj ...

  8. python之函数的初识

    1. 面向过程编程的缺点 代码重复 代码可可读性不高 2. 函数的定义*** ​ 函数是以功能为导向,一个函数封装一个功能.登录,注册,文件的改的操 3.函数的作用*** ​ 函数减少代码的重复性,增 ...

  9. string 空值

    string str; string mystr = ""; 则 str == mystr;

  10. HTML5<article>元素

    HTML5<article>元素用来定义页面文档的独立内容. 实例: <article class="pageArticle"> <h2>art ...