• 泡茶?泡咖啡?

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

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

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

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

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

  如果我们用两个类去描述这两个过程,很明显会有很多重复的代码(例如 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. 对比java和python对比

    对比java和python 对比java和python 2011年04月18日 1.难易度而言.python远远简单于java. 2.开发速度.Python远优于java 3.运行速度.java远优于 ...

  2. vue 中根据地址名称获取实际经纬度方法

    <div id="container" class="map" style="margin-top:30px; width: 1200px;he ...

  3. C08 C语言预处理命令

    目录 宏定义 文件包含 条件编译 预处理命令 C语言的预处理:在编译之前进行的处理,不进行编译. C语言的预处理功能有: 宏定义 文件包含 条件编译 预处理命令以符号“#”开头.. 宏定义 不带参数的 ...

  4. Java中的Static修饰符

    static(静态.修饰符):static修饰成员变量时:static修饰成员变量时,那么该成员变量的数据就是一个共享的数据. 静态成员变量的访问方式:方式一: 使用对象进行访问. 对象.属性名 方式 ...

  5. stataic 变量

    static 是静态变量的的类型说明符 静态变量属于静态存储方式,(外部变量也是静态存储方式) 静态的局部变量 静态局部变量属于静态存储方式,它具有以下特点: (1)静态局部变量在函数内定义 它的生存 ...

  6. C# 调用腾讯地图WebService API获取距离(一对多)

    官方文档地址:https://lbs.qq.com/webservice_v1/guide-distance.html 代码: /// <summary> /// 获取距离最近的点的经纬度 ...

  7. 【转】vxworks的default boot line说明

    boot程序的主要功能是引导vxworks 内核,所以boot程序需要知道vxworks的内核存放在何处,通过什么手段去获取.在vxworks缺省的boot程序里有一条内建的default boot ...

  8. redis学习笔记(3)

    redis学习笔记第三部分 --redis持久化介绍,事务,主从复制 三,redis的持久化 RDB(Redis DataBase)AOF(Append Only File) RDB:在指定的时间间隔 ...

  9. linux :没有找到 ifconfig netstat

    linux :没有找到 ifconfig netstat ubuntu sudo apt install net-tools -y centos yum install net-tools

  10. python入门:从安装python开始

    python简介: Python (英国发音:/ˈpaɪθən/ 美国发音:/ˈpaɪθɑːn/), 是一种面向对象的解释型计算机程序设计语言,由荷兰人Guido van Rossum于1989年发明 ...