初识设计模式 chapter 08-模板方法模式
来源:互联网 发布:淘宝转化率10%算正常吗 编辑:程序博客网 时间:2024/04/28 06:54
初识设计模式 chapter 08-模板方法模式
1 引言
直到目前,我们的议题都绕着封装转,我们已经封装了对象创建、方法调用、复杂接口、鸭子、披萨。接下来呢?我们将要深入封装算法块,好让子类可以在任何时候都可以将自己挂接进运算里。我们甚至会在本章学到一个受到好莱坞影响而启发的设计原则。
2 正文
2.1 多来点咖啡因吧
有些人没有咖啡就活不下去,有些人则离不开茶。两者的共同成分是什么,当然是咖啡因啦。
让我们扮演“代码师傅“,写一些代码来创建咖啡和茶。
下面是咖啡:
public class Coffee { /* * 这是我们的咖啡冲泡方法,直接取自训练手册。 * 每个步骤都被实现在分离的方法中。 * 这里每个方法都实现了算法中的一个步骤:煮沸水、冲泡咖啡、把咖啡倒进杯子、加糖和加奶。 */void prepareRecipe() {boilWater();brewCoffeeGrinds();pourInCup();addSugarAndMilk();} public void boilWater() {System.out.println("Boiling water");} public void brewCoffeeGrinds() {System.out.println("Dripping Coffee through filter");} public void pourInCup() {System.out.println("Pouring into cup");} public void addSugarAndMilk() {System.out.println("Adding Sugar and Milk");}}
下面是茶
public class Tea { /* * 这看起来和前一页的咖啡的实现很像,其中第2和第4个步骤不一样,但基本上是相同的冲泡法。 */void prepareRecipe() {boilWater();steepTeaBag();pourInCup();addLemon();} public void boilWater() {System.out.println("Boiling water");} public void steepTeaBag() {System.out.println("Steeping the tea");} public void addLemon() {System.out.println("Adding Lemon");} public void pourInCup() {System.out.println("Pouring into cup");}}
我们发现了重复的代码,这是好现象。这表示我们需要清理一下设计了。在这里,既然茶和咖啡是如此的相似,似乎我们应该将共同的部分抽出来,放进一个基类中。
现在我们有了新的prepareRecipe()方法,但是需要让它能够符合代码。要想这么做,我们先从CaffeineBeverage(咖啡因饮料:茶和咖啡)超类开始。
public abstract class CaffeineBeverage {/* * 现在,用同一个prepareRecipe()方法来处理茶和咖啡。 * prepareRecipe()被声明为final,因为我们不希望子类覆盖这个方法。 * 我们将步骤2和步骤4泛化为brew()和addCondiments()方法。 */final void prepareRecipe() {boilWater();brew();pourInCup();addCondiments();} /* * 因为咖啡和茶处理这些方法的做法不同,所以这两个方法必须被声明为抽象,由子类来实现具体方法。 */abstract void brew(); abstract void addCondiments(); void boilWater() {System.out.println("Boiling water");} void pourInCup() {System.out.println("Pouring into cup");}}
最后,我们需要处理咖啡和茶类了。这两个类现在都是依赖超类(咖啡因饮料)来处理冲泡法,所以只需要自行处理冲泡和添加调料部分。
2.2 认识模板方法
prepareRecipe()是我们的模板方法。为什么?
因为:
1、毕竟它是一个方法。
2、它用作一个算法的模板,在这个例子中,算法是用来制作咖啡因饮料的。
在这个模板中,算法内的每一个步骤都被一个方法代表了。某些方法是由这个类(超类)来处理的,某些方法则是由子类来处理。
模板方法模式:在一个方法中定义一个算法的骨架,而将一些步骤延迟到子类中。模板方法使得子类可以在不改变算法结构的情况下,重新定义算法中的某些步骤。
2.3 对模板方法进行挂钩
钩子是一种被声明在抽象类中的方法,但只有空的或者默认的实现。钩子的存在,可以让子类有能力对算法的不同点进行挂钩。要不要挂钩,由子类自行决定。
钩子有好几种用途,让我们先看其中一个,稍后再看其他几个:
public abstract class CaffeineBeverageWithHook { /* * 我们加上了一个小小的条件语句,而该条件是否成立,是由一个具体方法customerWantsCondiments()决定的。 * 如果顾客“想要”调料,只有这时我们才调用addCondiments()。 */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");} /* * 我们再这里定义了一个方法,(通常)是空的缺省实现。这个方法只会返回true,不做别的事情。 * 这就是钩子,子类可以覆盖这个方法,但不见得一定要这么做。 */boolean customerWantsCondiments() {return true;}}
2.4 好莱坞原则
好莱坞原则:别调用(打电话给)我们,我们会调用(打电话给)你。
好莱坞原则可以给我们一种防止“依赖腐败“的方法。当高层组件依赖低层组件,而低层组件又依赖高层组件,而高层组件又依赖边侧组件,依赖腐败就发生了。在这种情况下,没有人可以轻易地搞定系统是如何设计的。
在好莱坞原则之下,我们允许低层组件讲自己挂钩到系统上,但是高层组件决定什么时候和怎么样使用这些低层组件。换句话说,高层组件对待低层组件的方式是”别调用我们,我们会调用你“。
2.5 用模板方法来排序
实现compareTo()方法即可。
3 本章小结
模板方法从字面意思就很好理解,把握住新学的好莱坞原则,避免依赖腐败,这个就是本章的精髓。
1 0
- 初识设计模式 chapter 08-模板方法模式
- 初识设计模式 chapter 01-策略模式
- 初识设计模式 chapter 02-观察者模式
- 初识设计模式 chapter 04-工厂模式
- 初识设计模式 chapter 06-命令模式
- 初识设计模式 chapter 10-状态模式
- 初识设计模式 chapter 11-代理模式
- Chapter 9 模板方法模式
- 初识设计模式 chapter 07-适配器模式与外观模式
- 初识设计模式 chapter 03-装饰者模式
- 初识设计模式 chapter 05-单件模式
- 初识设计模式 chapter 09-迭代器与组合模式
- 设计模式:模板方法模式
- 设计模式 - 模板方法模式
- 设计模式:模板方法模式
- 设计模式 模板方法模式
- 设计模式--模板方法模式
- 设计模式-【模板方法模式】
- 段位结构体与补码、大小端
- 明星粉丝经济“叫好不叫座”?变现需找准“窍门儿”
- 第6周作业
- Ubuntu, Red Hat设置开机进入shell界面
- BGP 学习第一课
- 初识设计模式 chapter 08-模板方法模式
- DataGridView控件使用大全
- 数据结构与算法[LeetCode]—Container With Most Water
- 字符集之NLS_LANG
- 白话详解JavaScript原型
- list双向链表容器
- DataGridView分页功能的实现
- linux配置oracle客户端,sqlplus、sqlldr、exp、imp --- 转
- 。第7周作业——JMF(Java多媒体框架)的应用之音频播放与视频播放