以下内容出自:<<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 接收短信

    启动程序时启动一个service,在service里注册接收短信的广播,当手机收到短信里,打印出短信内容跟电话号码. package com.lmy.SmsListener; import andro ...

  2. Qt树形控件QTreeView使用1——节点的添加删除操作 复选框的设置

    QtreeView是ui中最常用的控件,Qt中QTreeWidget比QTreeView更简单,但没有QTreeView那么灵活(QTreeWidget封装的和MFC的CTreeCtrl很类似,没有m ...

  3. CCLabelTTF 如何支持换行符和换行

    参考自http://www.cocos2d-x.org/wiki/How_does_CCLabelTTF_support_line_breaks_and_wrapping 环境: cocos2d-x ...

  4. Enable SPI 1.0 and 1.1 with device tre overlays on BeagleBone

    For most people the above image means absolutely nothing, but for that one guy that has been searchi ...

  5. 一个现代化的JSON库Moshi针对Android和Java

    Moshi 是一个现代化的JSON库针对Android和Java.它可以很容易地解析JSON成Java对象: String json = ...; Moshi moshi = new Moshi.Bu ...

  6. hibernate缓存技术

    1.缓存 2.Hibernate 缓存作用:为了提高查询效率. 3.第一次操作某个对象的时候,把操作的对象数据存储到缓存中,然后下一次在对同一个对象操作的时候,就不会在连接数据库. 4.Hiberna ...

  7. hibernate----hibernate的基础设置

    本次学习的内容是hibernate的基础设置 具体内容为: 一.准备工作 1.新建java工程 2.自动引入相关库(自动生成SessionFactory) 3.将数据库驱动拿进来 4.添加hibern ...

  8. TCP三次握手/四次握手

    TCP连接三次握手 首先Client端发送连接请求报文,Server段接受连接后回复ACK报文,并为这次连接分配资源.Client端接收到ACK报文后也向Server段发生ACK报文,并分配资源,这样 ...

  9. 一、Maven环境搭建(windows 环境)

    所需工具 : JDK 1.7    java 环境 Maven 3.3.9  下载最新版本 Windows 7 注 Maven 3.2 要求 JDK 1.6 或以上版本, 而 Maven 3.0/3. ...

  10. Java中正确使用hashCode() 和equals() 、==

    在java编程中,经常会遇到两个对象中某个属性的比较,常常会用到的方法有: == .equals().但是两者使用起来有什么区别呢? 一.== java中的==是比较两个对象在JVM中的地址.比较好理 ...