设计模式(二十二)模板方法模式 Template
- 泡茶?泡咖啡?
我们用泡茶和泡咖啡两种行为来引入这一设计模式。
思考一下“泡茶”的过程:
煮水 -> 用沸水泡茶叶 -> 把茶倒进杯子 -> 放点柠檬之类的佐料。
然后再看一下“泡咖啡”的过程:
煮水 -> 用沸水泡咖啡 -> 把咖啡倒进杯子 -> 加牛奶和糖。
如果我们用两个类去描述这两个过程,很明显会有很多重复的代码(例如 Step1 煮水,Step3 倒进杯子),也有很多相似的代码(Step2 冲泡,Step4 加佐料)。
将冲泡的过程看做是一个算法,那么这个算法的主架构是一致的:
煮水 -> 用沸水泡东西 -> 将泡完的东西倒进杯子 -> 加佐料。
将主过程抽象出来,至于泡什么东西,加什么佐料,就交给子类去实现,这就是模板方法模式。
- 模板方法模式:
在一个方法中定义一个算法的骨架,而将一些步骤延迟到子类中。模板方法使得子类可以在不改变算法结构的情况下,重新定义算法中的某些步骤。
- UML:

除了上述的四个步骤,这里加了个新的方法:customerWantsCondiments(),因为加佐料这个步骤不是必须的。
- 模板方法的组成:
从上面 UML 图,我们能够发现,在抽象类 BeverageDrive 中,一共存在4类方法:
- 模板方法:prepareRecipe(),这是算法的主体,在方法内部会调用其他的方法,一般来说是 public final 的。
- 抽象方法:brew() & addCondiments(),是算法步骤的“个性”,在 BeverageDrive 中声明为 protected abstract,由子类去实现。
- 具体方法:boilWater() & pourInCup(),是算法步骤的“共性”,一般是 private 的。
- 钩子方法: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的更多相关文章
- 设计模式 ( 十九 ) 模板方法模式Template method(类行为型)
设计模式 ( 十九 ) 模板方法模式Template method(类行为型) 1.概述 在面向对象开发过程中,通常我们会遇到这样的一个问题:我们知道一个算法所需的关键步骤,并确定了这些步骤的执行 ...
- C#设计模式之十四模板方法模式(Template Method)【行为型】
一.引言 “结构型”的设计模式已经写完了,从今天我们开始讲“行为型”设计模式.现在我们开始讲[行为型]设计模式的第一个模式,该模式是[模板方法],英文名称是:Template Method Patte ...
- 模板方法模式 Template method 行为型 设计模式(二十六)
模板方法模式 Template method 上图为网上百度的一份简历模板截图 相信大家都有求职的经历,那么必然需要简历,写简历的时候,很可能你会网上检索一份简历模板,使用此模板的格式,然后替换为 ...
- 二十四种设计模式:模板方法模式(Template Method Pattern)
模板方法模式(Template Method Pattern) 介绍定义一个操作中的算法的骨架,而将一些步骤延迟到子类中.Template Method使得子类可以不改变一个算法的结构即可重定义该算法 ...
- Java设计模式(十二) 策略模式
原创文章,同步发自作者个人博客,http://www.jasongj.com/design_pattern/strategy/ 策略模式介绍 策略模式定义 策略模式(Strategy Pattern) ...
- 备忘录模式 Memento 快照模式 标记Token模式 行为型 设计模式(二十二)
备忘录模式 Memento 沿着脚印,走过你来时的路,回到原点. 苦海翻起爱恨 在世间难逃避命运 相亲竟不可接近 或我应该相信是缘份 一首<一生所爱>触动了多少 ...
- 桥接模式 桥梁模式 bridge 结构型 设计模式(十二)
桥接模式Bridge Bridge 意为桥梁,桥接模式的作用就像桥梁一样,用于把两件事物连接起来 意图 将抽象部分与他的实现部分进行分离,使得他们都可以独立的发展. 意图解析 依赖倒置原 ...
- Java 设计模式系列(二十)状态模式
Java 设计模式系列(二十)状态模式 状态模式,又称状态对象模式(Pattern of Objects for States),状态模式是对象的行为模式.状态模式允许一个对象在其内部状态改变的时候改 ...
- 小菜学习设计模式(一)—模板方法(Template)模式
前言 设计模式目录: 小菜学习设计模式(一)—模板方法(Template)模式 小菜学习设计模式(二)—单例(Singleton)模式 小菜学习设计模式(三)—工厂方法(Factory Method) ...
- 乐在其中设计模式(C#) - 模板方法模式(Template Method Pattern)
原文:乐在其中设计模式(C#) - 模板方法模式(Template Method Pattern) [索引页][源码下载] 乐在其中设计模式(C#) - 模板方法模式(Template Method ...
随机推荐
- Countup.js:vue-countup-v2(npm)数字滚动插件
1.官方地址:http://inorganik.github.io/countUp.js/ 2.官方demo: 3.参数说明: params——start(开始数字).end(结束数字).decima ...
- [机器视觉] SIFT特征-尺度不变特征理解
SIFT特征-尺度不变特征理解 简介 SIFT,即尺度不变特征变换(Scale-invariant feature transform,SIFT),是用于图像处理领域的一种描述.这种描述具有尺度不变性 ...
- SG函数入门&&HDU 1848
SG函数 sg[i]为0表示i节点先手必败. 首先定义mex(minimal excludant)运算,这是施加于一个集合的运算,表示最小的不属于这个集合的非负整数.例如mex{0,1,2,4}=3. ...
- Trie入门讲解
我们常常用Trie(也叫前缀树)来保存字符串集合.如下图所示就是一个Trie. 上图表示的字符串集合为$\{a,to,tea,ted,ten,i,in,inn \}$,每个单词的结束位置对应一个“单词 ...
- Connectivity
6492: Connectivity 时间限制: 1 Sec 内存限制: 128 MB提交: 118 解决: 28[提交][状态][讨论版][命题人:admin] 题目描述 There are N ...
- 用Python计算最长公共子序列和最长公共子串
如何用Python计算最长公共子序列和最长公共子串 1. 什么是最长公共子序列?什么是最长公共子串? 1.1. 最长公共子序列(Longest-Common-Subsequences,LCS) 最长公 ...
- java 自定义一个容器类
public class ArrayList { public int index = 0; Object[] objects = new Object[2]; public void add(Obj ...
- python之函数的初识
1. 面向过程编程的缺点 代码重复 代码可可读性不高 2. 函数的定义*** 函数是以功能为导向,一个函数封装一个功能.登录,注册,文件的改的操 3.函数的作用*** 函数减少代码的重复性,增 ...
- string 空值
string str; string mystr = ""; 则 str == mystr;
- HTML5<article>元素
HTML5<article>元素用来定义页面文档的独立内容. 实例: <article class="pageArticle"> <h2>art ...