以下内容出自:<<24种设计模式介绍与6大设计原则>>

  周三,9:00,我刚刚坐到位置,打开电脑准备开始干活。

  “小三,小三,叫一下其它同事,到会议室,开会”老大跑过来吼,带着淫笑。还不等大家坐稳,老大就开讲了,
  “告诉大家一个好消息,昨天终于把牛叉模型公司的口子打开了,要我们做悍马模型,虽然是第一个车辆模型,但是我们有能力,有信心做好,我们一定要…(中间省略20 分钟的讲话,如果你听过领导人的讲话,这个你应该能够续上)”
  动员工作做完了,那就开始压任务了,

“这次时间是非常紧张的,只有一个星期的时间,小三,你负责在一个星期的时间把这批10 万车模(注:车模是车辆模型的意思,不是香车美女那个车模)建设完成…”
“一个星期?这个…,是真做不完,要做分析,做模板,做测试,还要考虑扩展性、稳定性、健壮性等,时间实在是太少了”还没等老大说完,我就急了,再不急我的小命就折在上面了!
“那这样,你只做实现,不考虑使用设计模式,扩展性等都不用考虑”老大又把我压回去了。
“不考虑设计模式?那…”
哎,领导已经布置任务了,那就开始死命的做吧,命苦不能怨政府,点背不能怪社会呀,然后就开始准备动手做,在做之前先介绍一下我们公司的背景,我们公司是做模型生产的,做过桥梁模型、建筑模型、机械模型,甚至是一些政府、军事的机密模型,这个不能说,就是把真实的实物按照一定的比例缩小或放大,用于试验、分析、量化或者是销售等等,上面提到的牛叉模型公司专门销售车辆模型的公司,自己不生产,我们公司是第一次从牛叉模型公司接单,那我怎么着也要把活干好,可时间很紧张呀,怎么办?既然领导都说了,不考虑扩展性,那好办,我先设计个类图:

  非常简单的实现,你要悍马模型,我就给你悍马模型,先写个抽象类,然后两个不同型号的模型实现类,那我们把这个程序实现出来:
HummerModel 抽象类的程序清单如下:

package cn.mjorcen.template_pattern.service;

/**
* @author cbf4Life cbf4life@126.com I'm glad to share my knowledge with you
* all. Hummer Model是悍马车辆模型的意思,不是悍马美女车模
*/
public abstract class HummerModel {
/*
* 首先,这个模型要能够被发动起来,别管是手摇发动,还是电力发动,反正 是要能够发动起来,那这个实现要在实现类里了
*/
public abstract void start(); // 能发动,那还要能停下来,那才是真本事
public abstract void stop(); // 喇叭会出声音,是滴滴叫,还是哔哔叫
public abstract void alarm(); // 引擎会轰隆隆的响,不响那是假的
public abstract void engineBoom(); // 那模型应该会跑吧,别管是人推的,还是电力驱动,总之要会跑
public abstract void run();
}

H1 型号悍马的定义如下:

package cn.mjorcen.template_pattern.service.impl;

import cn.mjorcen.template_pattern.service.HummerModel;

/**
* @author cbf4Life cbf4life@126.com I'm glad to share my knowledge with you
* all. 悍马车是每个越野者的最爱,其中H1最接近军用系列
*/
public class HummerH1Model extends HummerModel {
@Override
public void alarm() {
System.out.println("悍马H1鸣笛...");
} @Override
public void engineBoom() {
System.out.println("悍马H1引擎声音是这样在...");
} @Override
public void start() {
System.out.println("悍马H1发动...");
} @Override
public void stop() {
System.out.println("悍马H1停车...");
} /*
* 这个方法是很有意思的,它要跑,那肯定要启动,停止了等,也就是要调其他方法
*/
@Override
public void run() {
// 先发动汽车
this.start();
// 引擎开始轰鸣
this.engineBoom();
// 然后就开始跑了,跑的过程中遇到一条狗挡路,就按喇叭
this.alarm();
// 到达目的地就停车
this.stop();
}
}

然后看悍马H2 型号的实现:

package cn.mjorcen.template_pattern.service.impl;

import cn.mjorcen.template_pattern.service.HummerModel;

/**
* @author cbf4Life cbf4life@126.com I'm glad to share my knowledge with you
* all. H1和H2有什么差别,还真不知道,真没接触过悍马
*/
public class HummerH2Model extends HummerModel {
@Override
public void alarm() {
System.out.println("悍马H2鸣笛...");
} @Override
public void engineBoom() {
System.out.println("悍马H2引擎声音是这样在...");
} @Override
public void start() {
System.out.println("悍马H2发动...");
} @Override
public void stop() {
System.out.println("悍马H1停车...");
} /*
* H2要跑,那肯定要启动,停止了等,也就是要调其他方法
*/
@Override
public void run() {
// 先发动汽车
this.start();
// 引擎开始轰鸣
this.engineBoom();
// 然后就开始跑了,跑的过程中遇到一条狗挡路,就按喇叭
this.alarm();
// 到达目的地就停车
this.stop();
}
}

  然后程序写到这里,你就看到问题了,run 方法的实现应该在抽象类上,不应该在实现类上,好,我们
修改一下类图和实现:

就把run 方法放到了抽象类中,那代码也相应的改变一下,先看HummerModel.java:

package cn.mjorcen.template_pattern.service.impl;

/**
* @author cbf4Life cbf4life@126.com I'm glad to share my knowledge with you
* all. Hummer Model是悍马车辆模型的意思,不是悍马美女车模
*/
public abstract class HummerModel {
/*
* 首先,这个模型要能够被发动起来,别管是手摇发动,还是电力发动,反正 是要能够发动起来,那这个实现要在实现类里了
*/
public abstract void start(); // 能发动,那还要能停下来,那才是真本事
public abstract void stop(); // 喇叭会出声音,是滴滴叫,还是哔哔叫
public abstract void alarm(); // 引擎会轰隆隆的响,不响那是假的
public abstract void engineBoom(); // 那模型应该会跑吧,别管是人退的,还是电力驱动,总之要会跑
public void run() {
// 先发动汽车
this.start();
// 引擎开始轰鸣
this.engineBoom();
// 然后就开始跑了,跑的过程中遇到一条狗挡路,就按喇叭
this.alarm();
// 到达目的地就停车
this.stop();
}
}

下面是HummerH1Model.java 程序清单:

package cn.mjorcen.template_pattern.service.impl;

/**
* @author cbf4Life cbf4life@126.com I'm glad to share my knowledge with you
* all. 悍马车是每个越野者的最爱,其中H1最接近军用系列
*/
public class HummerH1Model extends HummerModel {
@Override
public void alarm() {
System.out.println("悍马H1鸣笛...");
} @Override
public void engineBoom() {
System.out.println("悍马H1引擎声音是这样在...");
} @Override
public void start() {
System.out.println("悍马H1发动...");
} @Override
public void stop() {
System.out.println("悍马H1停车...");
}
}

下面是HummerH2Model.java 的程序清单:

package cn.mjorcen.template_pattern.service.impl;

/**
* @author cbf4Life cbf4life@126.com I'm glad to share my knowledge with you
* all. H1和H2有什么差别,还真不知道,真没接触过悍马
*/
public class HummerH2Model extends HummerModel {
@Override
public void alarm() {
System.out.println("悍马H2鸣笛...");
} @Override
public void engineBoom() {
System.out.println("悍马H2引擎声音是这样在...");
} @Override
public void start() {
System.out.println("悍马H2发动...");
} @Override
public void stop() {
System.out.println("悍马H2停车...");
}
}

  类图修改完毕了,程序也该好了,提交给老大,老大一看,挺好,就开始生产了,并提交给客户使用
了,那客户是如何使用的呢?类图上增加一个Client 类,就是客户,我们这个是用main 函数来代替他使
用,类图如下:

   
然后看增加的Client.java 程序,非常的简单:

package cn.mjorcen.template_pattern;

import cn.mjorcen.template_pattern.service.impl.HummerH1Model;
import cn.mjorcen.template_pattern.service.impl.HummerH2Model;
import cn.mjorcen.template_pattern.service.impl.HummerModel; /**
* @author cbf4Life cbf4life@126.com I'm glad to share my knowledge with you
* all. 客户开始使用这个模型
*/
public class Client {
public static void main(String[] args) {
// 客户开着H1型号,出去遛弯了
HummerModel h1 = new HummerH1Model();
h1.run(); // 汽车跑起来了;
// 客户开H2型号,出去玩耍了
HummerModel h2 = new HummerH2Model();
h2.run();
}
}

  非常非常的简单,那如果我告诉这就是模板方法模式你会不会很不屑呢?就这模式,太简单了,我一
直在使用呀,是的,你经常在使用,但你不知道这是模板方法模式,那些所谓的高手就可以很牛X 的说“用
模板方法模式就可以实现…”,你还要很崇拜的看着,哇,牛人,模板方法模式是什么呀?
然后我们继续回顾我们这个模型,回头一想,不对呀,需求分析的有点问题,客户要关心模型的启动,
停止,鸣笛,引擎声音吗?他只要在run 的过程中,听到或看都成了呀,暴露那么多的方法干啥?好了,
我们重新修改一下类图:

  把抽象类上的四个方法设置为protected 访问权限,好了,既然客户不关心这几个方法,而且这四个
方法都是由子类来实现的,那就设置成protected 模式。咦~,那还有个缺陷,run 方法既然子类都不修改,
那是不是可以设置成final 类型呢?是滴是滴,类图如下:

  好了,这才是模板方法模式,就是这个样子,我们只要修改抽象类代码就可以了,HummerModel.java
程序清单如下:

package cn.mjorcen.template_pattern.service.impl;

/**
* @author cbf4Life cbf4life@126.com I'm glad to share my knowledge with you
* all. Hummer Model是悍马车辆模型的意思,不是悍马美女车模
*/
public abstract class HummerModel {
/*
* 首先,这个模型要能够被发动起来,别管是手摇发动,还是电力发动,反正 是要能够发动起来,那这个实现要在实现类里了
*/
protected abstract void start(); // 能发动,那还要能停下来,那才是真本事
protected abstract void stop(); // 喇叭会出声音,是滴滴叫,还是哔哔叫
protected abstract void alarm(); // 引擎会轰隆隆的响,不响那是假的
protected abstract void engineBoom(); // 那模型应该会跑吧,别管是人退的,还是电力驱动,总之要会跑
final public void run() {
// 先发动汽车
this.start();
// 引擎开始轰鸣
this.engineBoom();
// 然后就开始跑了,跑的过程中遇到一条狗挡路,就按喇叭
this.alarm();
// 到达目的地就停车
this.stop();
}
}

  其他的子类都不用修改(如果要修改,就是把四个方法的访问权限由public 修改protected),大家请
看这个run 方法,他定义了调用其他方法的顺序,并且子类是不能修改的,这个叫做模板方法;start、stop、
alarm、engineBoom 这四个方法是子类必须实现的,而且这四个方法的修改对应了不同的类,这个叫做基本
方法,基本方法又分为三种:在抽象类中实现了的基本方法叫做具体方法;在抽象类中没有实现,在子类
中实现了叫做抽象方法,我们这四个基本方法都是抽象方法,由子类来实现的;还有一种叫做钩子方法,
这个等会讲。
  到目前为止,这两个模型都稳定的运行,突然有一天,老大又找到了我,“客户提出新要求了,那个喇叭想让它响就响,你看你设计的模型,车子一启动,喇叭就狂响,赶快修改一下”,确实是设计缺陷,呵呵,不过是我故意的,那我们怎么修改呢?看修改后的类图:

  增加一个方法,isAlarm(),喇嘛要不要响,这就是钩子方法(Hook Method),那我们只要修改一下抽
象类就可以了:

  那我们总结一下模板方法模式,模板方法模式就是在模板方法中按照一个的规则和顺序调用基本方法,
具体到我们上面那个例子就是run 方法按照规定的顺序(先调用start,然后再调用engineBoom,再调用
alarm,最后调用stop)调用本类的其他方法,并且由isAlarm 方法的返回值确定run 中的执行顺序变更,
通用类图如下:

  其中TemplateMethod 就是模板方法,operation1 和operation2 就是基本方法,模板方法是通过汇总或排序基本方法而产生的结果集。模板方法在一些开源框架中应用很多,它提供了一个抽象类,然后开源框架写了一堆子类,在《XXX In Action》中就说明了,如果你需要扩展功能,可以继承了这个抽象类,然后修改protected 方法,再然后就是调用一个类似execute 方法,就完成你的扩展开发,确实是一种简单的模式。

  初级程序员在写程序的时候经常会问高手“父类怎么调用子类的方法”,这个问题很有普遍性,反正我是被问过好几回,那么父类是否可以调用子类的方法呢?我的回答是能,但强烈的、极度的不建议,怎么做呢?

第 9 章 模板方法模式【Template Method Pattern】的更多相关文章

  1. 设计模式 - 模板方法模式(template method pattern) JFrame 具体解释

    模板方法模式(template method pattern) JFrame 具体解释 本文地址: http://blog.csdn.net/caroline_wendy 參考模板方法模式(templ ...

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

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

  3. 设计模式 - 模板方法模式(template method pattern) 排序(sort) 具体解释

    模板方法模式(template method pattern) 排序(sort) 具体解释 本文地址: http://blog.csdn.net/caroline_wendy 參考模板方法模式(tem ...

  4. 设计模式 - 模板方法模式(template method pattern) 具体解释

    模板方法模式(template method pattern) 详细解释 本文地址: http://blog.csdn.net/caroline_wendy 模板方法模式(template metho ...

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

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

  6. 模板方法模式(Template Method Pattern)——复杂流程步骤的设计

    模式概述 在现实生活中,很多事情都包含几个实现步骤,例如请客吃饭,无论吃什么,一般都包含点单.吃东西.买单等几个步骤,通常情况下这几个步骤的次序是:点单 --> 吃东西 --> 买单. 在 ...

  7. 设计模式(九): 从醋溜土豆丝和清炒苦瓜中来学习"模板方法模式"(Template Method Pattern)

    今天是五.四青年节,祝大家节日快乐.看着今天这标题就有食欲,夏天到了,醋溜土豆丝和清炒苦瓜适合夏天吃,好吃不上火.这两道菜大部分人都应该吃过,特别是醋溜土豆丝,作为“鲁菜”的代表作之一更是为大众所熟知 ...

  8. 模板方法模式(Template Method Pattern)

    模板方法模式是一种基于继承的代码复用技术,定义一个操作中的算法的骨架,而将步骤延迟到子类中.模板方法使得子类可以不改变一个算法的结构即可重定义算法的某些特定步骤. 模式中的角色 抽象类(Abstrac ...

  9. 使用 C# (.NET Core) 实现模板方法模式 (Template Method Pattern)

    本文的概念内容来自深入浅出设计模式一书. 项目需求 有一家咖啡店, 供应咖啡和茶, 它们的工序如下: 咖啡: 茶: 可以看到咖啡和茶的制作工序是差不多的, 都是有4步, 其中有两步它们两个是一样的, ...

  10. 使用C# (.NET Core) 实现模板方法模式 (Template Method Pattern)

    本文的概念内容来自深入浅出设计模式一书. 项目需求 有一家咖啡店, 供应咖啡和茶, 它们的工序如下: 咖啡: 茶: 可以看到咖啡和茶的制作工序是差不多的, 都是有4步, 其中有两步它们两个是一样的, ...

随机推荐

  1. Android 读取手机短信

    获取android手机短信需要在AndroidManifest.xml加权限: <uses-permission android:name="android.permission.RE ...

  2. oracle学习----特殊的连接方式

    1.笛卡儿积 merge join cartesion SQL> select ename,dname from emp,dept; 已选择56行. 执行计划------------------ ...

  3. arcmap10如果判断一个面是否含洞

    使用字段计算器,使用python !Shape.isMultipart!结果为true就是,false不是

  4. Android学习之Intent传递数据

    Intent在Activity中的作用主要是有两个: 1.启动目标Activity 2.传递数据 Intent在传递数据时分两种情况:向下一个Activity传递数据和从下一个Activity返回数据 ...

  5. C++ 全排列函数 nyoj 366

    C++ STL中提供了std::next_permutation与std::prev_permutation可以获取数字或者是字符的全排列,其中std::next_permutation提供升序.st ...

  6. JS设置打印页面并调用本地打印机打印页面

    <script type="text/javascript"> var hkey_key; var hkey_root = "HKEY_CURRENT_USE ...

  7. maven是什么?(转自oracle官网)

    Maven 是一个项目管理和构建自动化工具.但是对于我们程序员来说,我们最关心的是它的项目构建功能.所以这里我们介绍的就是怎样用 maven 来满足我们项目的日常需要.Maven 使用惯例优于配置的原 ...

  8. C#微信公众号开发 -- (七)自定义菜单事件之VIEW及网页(OAuth2.0)授权

    通俗来讲VIEW其实就是我们在C#中常用的a标签,可以直接在自定义菜单URL的属性里面写上需要跳转的链接,也即为单纯的跳转. 但更多的情况下,我们是想通过VIEW来进入指定的页面并进行操作. 举一个简 ...

  9. spring学习笔记之spring框架本质

    Spring框架的本质是,开发者在Spring配置文件中使用XML元素进行配置,实际驱动Spring执行相应的代码: 使用<bean.../>元素,实际启动Spring执行无参或有参构造函 ...

  10. C#微信开发之旅--基本信息的回复

    上一篇说到配置和验证<C#微信开发之旅--准备阶段> 下面来实现一下简单的信息回复. 也就是接收XML,返回XML 可以去看下微信开发文档的说明:http://mp.weixin.qq.c ...