设计模式(二十二)模板方法模式 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 ...
随机推荐
- UVA 624 CD(01背包,要记录路径)
题意: 有n张CD(n<=20),每张能播放的时长不同.给定一个时长限制t,挑出部分的CD使得总播放时间最长.顺便输出路径! 思路: 重点在输出路径,否则这题很普通.那就要用二维数组记录每个CD ...
- 远程桌面连接(mstsc)无法断开的解决方案
某2008 r2有二个系统账户,同时允许两个tcp连接,但每个用户仅同时允许一人登录.不知何因,关闭远程桌面连接的窗口后,再次连接就瞬间提示无法被连接.查看了事件查看器,信息为被注销,这是因为设置了“ ...
- 一些常用的HTML标签
由于本人目前没有系统学习,日常碰见哪个有用就记下来. pre标签 可定义预格式化的文本,在pre元素中的文本会保留空格和换行符.比如我们展示源代码的时候,只要放一个pre标签,然后把代码直接复制.粘贴 ...
- MyLinkedList
/** * 节点类 * @author JP * */ class Node { Object value;//节点元素值 Node pre;//上一个节点 Node next;//下一个节点 pub ...
- python_95_类变量的作用及析构函数
参考:http://www.cnblogs.com/alex3714/articles/5188179.html #类变量的用途:大家共有的属性,节省内存 class Person(): cn='Ch ...
- springboot autoconfig
springboot自动配置的核心思想是:springboot通过spring.factories能把main方法所在类路径以外的bean自动加载 springboot starter验证 我在spr ...
- Unity学习之路——C#相关
1.C#数组数组定义 int[] number; float[] score; string[] names;动态初始化,借助new运算符为数组元素分配空间int[] Array = new int[ ...
- 概括的描述一下Spring注册流程
Spring经过大神们的构思.编码,日积月累而来,所以,对其代码的理解也不是一朝一夕就能快速完成的.源码学习是枯燥的,需要坚持!坚持!坚持!当然也需要技巧,第一遍学习的时候,不用关注全部细节,不重要的 ...
- DELL PowerEdge R620安装Windows server(你想将windows安装在何处”找不到任何本地磁盘,“找不到驱动器”)已解决!
你可能碰到过DELL服务器上安装Windows server系列系统时无法识别或找不到硬盘的问题,对于DELL PowerEdge11-14代机器的,大家可以采用DELL的Lifecycle cont ...
- leetcode-16-greedyAlgorithm
455. Assign Cookies 解题思路: 先将两个数组按升序排序,然后从后往前遍历,当s[j] >= g[i]的时候,就把s[j]分给g[i],i,j都向前移动,count+1;否则向 ...