设计模式之禅-模板方法模式

1.悍马车模型抽象类

public abstract class HummerModel {

/*

* 首先,这个模型要能够被发动起来,别管是手摇发动,还是电力发动,反正

* 是要能够发动起来,那这个实现要在实现类里了

*/

public abstract void start();

//能发动,那还要能停下来

public abstract void stop();

//喇叭会出声音

public abstract void alarm();

//引擎会轰隆隆的响

public abstract void engineBoom();

//那模型应该会跑吧,别管是人推的,还是电力驱动,总之要会跑

public abstract void run();

}

2.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();

}

}

3.看悍马 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 方法的实现应该在抽象类上,不应该在实现类上

4.修改类图

5.修改HummerModel

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();

}

}

6.悍马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停车...");

}

}

7.悍马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停车...");

}

}

8.使用悍马模型


public class Client {

public static void main(String[] args) {

//客户开着H1型号,出去遛弯了

HummerModel h1 = new HummerH1Model();

h1.run(); //汽车跑起来了;

//客户开H2型号,出去玩耍了

HummerModel h2 = new HummerH2Model();

h2.run();

}

}

悍马H1发动...

悍马H1引擎声音是这样在...

悍马H1鸣笛...

悍马H1停车...

悍马H2发动...

悍马H2引擎声音是这样在...

悍马H2鸣笛...

悍马H2停车...

9.客户要关心模型的启动,停止,鸣笛,引擎声音吗?他只要在 run 的过程中,听到或看都成了呀,暴露那么多的方法干啥?好了,我们重新修改一下类图:


把抽象类上的四个方法设置为 protected 访问权限,好了,既然客户不关心这几个方法,而且这四个

方法都是由子类来实现的,那就设置成 protected 模式。

还有个缺陷,run 方法既然子类都不修改,那是不是可以设置成 final 类型呢?类图如下:


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();

}

}

这个 run 方法,他定义了调用其他方法的顺序,并且子类是不能修改的,这个叫做模板方法。start、stop、alarm、engineBoom 这四个方法是子类必须实现的,而且这四个方法的修改对应了不同的类,这个叫做基本方法,基本方法又分为三种:在抽象类中实现了的基本方法叫做具体方法;在抽象类中没有实现,在子类中实现了叫做抽象方法。

10.现在车子一run,喇叭就会一直响,想自由控制喇叭,应该怎么修改


增加一个方法,isAlarm(),喇嘛要不要响,这就是钩子方法(Hook Method)

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();

//喇嘛想让它响就响,不想让它响就不响

if(this.isAlarm()){

this.alarm();

}

//到达目的地就停车

this.stop();

}

//钩子方法,默认喇叭是会响的

protected boolean isAlarm(){

return true;

}

}

钩子方法模式是由抽象类来实现的,子类可以重写的

11.H2 型号的悍马是不会叫的,喇叭是个摆设

public class HummerH2Model extends HummerModel {

@Override

protected void alarm() {

System.out.println("悍马H2鸣笛...");

}

@Override

protected void engineBoom() {

System.out.println("悍马H2引擎声音是这样在...");

}

@Override

protected void start() {

System.out.println("悍马H2发动...");

}

@Override

protected void stop() {

System.out.println("悍马H2停车...");

}

//默认没有喇叭的

@Override

protected boolean isAlarm() {

return false;

}

}

H2的悍马run起来是这样的

public class Client {

public static void main(String[] args) {

HummerH2Model h2 = new HummerH2Model();

h2.run(); //H2型号的悍马跑起来

}

}

悍马H2发动...

悍马H2引擎声音是这样在...

悍马H2停车...

12.H1 又有所不同了,它的喇叭要不要响是由客户来决定

public class HummerH1Model extends HummerModel {

private boolean alarmFlag = true; //是否要响喇叭

@Override

protected void alarm() {

System.out.println("悍马H1鸣笛...");

}

@Override

protected void engineBoom() {

System.out.println("悍马H1引擎声音是这样在...");

}

@Override

protected void start() {

System.out.println("悍马H1发动...");

}

@Override

protected void stop() {

System.out.println("悍马H1停车...");

}

@Override

protected boolean isAlarm() {

return this.alarmFlag;

}

//要不要响喇叭,是有客户的来决定的

public void setAlarm(boolean isAlarm){

this.alarmFlag = isAlarm;

}

}

H1悍马run是这样的

public class Client {

public static void main(String[] args) {

//客户开着H1型号,出去遛弯了

HummerH1Model h1 = new HummerH1Model();

h1.setAlarm(true);

h1.run(); //汽车跑起来了;

}

}

悍马H1发动...

悍马H1引擎声音是这样在...

悍马H1鸣笛...

悍马 H1 停车...

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

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

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,558评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,002评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,036评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,024评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,144评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,255评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,295评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,068评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,478评论 1 305
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,789评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,965评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,649评论 4 336
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,267评论 3 318
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,982评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,223评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,800评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,847评论 2 351

推荐阅读更多精彩内容

  • 周三,9:00,我刚刚坐到位置,打开电脑准备开始干活。“小三,小三,叫一下其它同事,到会议室,开会”老大跑过来吼,...
    辽A丶孙悟空阅读 354评论 0 13
  • 模板方法模式:定义一个操作中的算法骨架,而将一些步骤延迟到子类,模板方法使得子类可以不改变一个算法即可定义算法的某...
    超级大鸡腿阅读 252评论 0 0
  • 1.模板方法模式简介 定义一个操作中算法的骨架,而将这些步骤延迟到子类中,模板方法使得子类可以不改变一个算法的结构...
    起个名字好纠结阅读 914评论 0 5
  • 第二章 模板方法模式 在模板模式(Template Pattern)中,一个抽象类公开定义了执行它的方法的方式/模...
    会Coding的猪崽阅读 146评论 0 1
  • 久违的晴天,家长会。 家长大会开好到教室时,离放学已经没多少时间了。班主任说已经安排了三个家长分享经验。 放学铃声...
    飘雪儿5阅读 7,517评论 16 22