您当前的位置: 首页 > 

宝哥大数据

暂无认证

  • 1浏览

    0关注

    1029博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文

23种设计模式12---模板方法模式

宝哥大数据 发布时间:2017-04-03 07:43:59 ,浏览量:1

模板方法模式 业务需求:汽车厂造悍马

假设我们是一个汽车公司,现在有客户来了,要求我们造悍马! 既然上级下来命令那就造呗,但是造悍马你得告诉我们汽车有什么功能啊,客户说了:“能启动车,能停止车,能响,能跑。”好,功能出来了,开始造汽车了。类图如下: 这里写图片描述

一、抽象模板模型 在抽象类中,我们定义了悍马模型都必须具有的特质:能够发动、停止,喇叭会响,引擎可以轰鸣,而且还可以停止
package com.chb.l.TemplateDesignPattern;
/**
一辆车的功能
    start
    engineboom
    run
    alarm
    stop
 */
public abstract class HummerModel {
    /**
     * 启动
     */
    public abstract void start();
    /**
     * 引擎轰鸣
     */
    public abstract void engineBoom();
    /**
     * 行驶
     */
    public abstract void run();
    /**
     * 遇到情况鸣笛
     */
    public abstract void alarm();
    /**
     * 停车
     */
    public abstract void stop();
}
二、高级定制嘛,每种型号的肯定有所不同 2.1、H320悍马
package com.chb.l.TemplateDesignPattern;
/**
 230系列车型
 */
public class Hummer320 extends HummerModel{

    @Override
    public void start() {
        System.out.print("H320发动。。。");
    }

    @Override
    public void engineBoom() {
        System.out.print("H320引擎发出轰鸣声 轰轰轰。。。");
    }

    @Override
    public void run() {
        this.start();
        this.engineBoom();
        System.out.print("跑起来了,");
        this.alarm();
        this.stop();
    }

    @Override
    public void alarm() {
        System.out.print("H320:妈的,嘀嘀嘀。。。好狗不挡道,快让开");
    }

    @Override
    public void stop() {
        System.out.println("H320:前方遇到紧急情况,滋滋滋...,总算停下来了。");
    }

}
2.2、H523悍马
package com.chb.l.TemplateDesignPattern;
/**
 230系列车型
 */
public class Hummer523 extends HummerModel{

    @Override
    public void start() {
        System.out.print("H523发动。。。");
    }

    @Override
    public void engineBoom() {
        System.out.print("H523引擎发出轰鸣声 轰轰轰。。。");
    }

    @Override
    public void run() {
        this.start();
        this.engineBoom();
        System.out.print("跑起来了,");
        this.alarm();
        this.stop();
    }

    @Override
    public void alarm() {
        System.out.print("H523:妈的,嘀嘀嘀。。。好狗不挡道,快让开");
    }

    @Override
    public void stop() {
        System.out.println("H523:前方遇到紧急情况,滋滋滋...,总算停下来了。");
    }

}
查看两种型号悍马,我们可以发现,两者具有一个共性方法run(), 那么这个共性方法应该出现在抽象类中,而不是实现类中,抽象是所有子类的共性封装 共性方法
    @Override
    public void run() {
        this.start();
        this.engineBoom();
        System.out.print("跑起来了,");
        this.alarm();
        this.stop();
    }
注意 在软件开发过程中,如果相同的一段代码复制过两次,就需要对设计产生怀疑, 架构师要明确地说明为什么相同的逻辑要出现两次或更多次,我们将共性方法抽取到抽象类中
package com.chb.l.TemplateDesignPattern;
/**
一辆车的功能
    start
    engineboom
    run
    alarm
    stop
 */
public abstract class HummerModel {
    /**
     * 启动
     */
    public abstract void start();
    /**
     * 引擎轰鸣
     */
    public abstract void engineBoom();
    /**
     * 行驶,共性方法抽取到抽象类,子类不用重新实现。
     */
    public void run() {
        this.start();
        this.engineBoom();
        System.out.print("跑起来了,");
        this.alarm();
        this.stop();
    }
    /**
     * 遇到情况鸣笛
     */
    public abstract void alarm();
    /**
     * 停车
     */
    public abstract void stop();


}
测试

public class Test {
    public static void main(String[] args) {
        HummerModel hm320 = new Hummer320();
        hm320.run();
    }
}



输出结果:
H320发动。。。H320引擎发出轰鸣声 轰轰轰。。。跑起来了,H320:妈的,嘀嘀嘀。。。好狗不挡道,快让开H320:前方遇到紧急情况,滋滋滋...,总算停下来了。
模板方法

这个共性方法run()就是模板方法,不管车子是什么型号, 一定是启动,引擎发动,可以跑了,遇到问题鸣笛,遇到紧急情况刹车。这个流程是不变的,即run()的实现不变,所以称为模板方法。

  注意 为了防止恶意的操作,一般模板方法都加上final关键字,不允许被覆写。 抽象模板中的基本方法尽量设计为protected类型,符合迪米特法则,不需要暴露的属性或方法尽量不要设置为protected类型。实现类若非必要,尽量不要扩大父类中的访问权限。 模板方法模式的使用场景

● 多个子类有公有的方法,并且逻辑基本相同时。 ● 重要、复杂的算法,可以把核心算法设计为模板方法,周边的相关细节功能则由各个 子类实现。 ● 重构时,模板方法模式是一个经常使用的模式,把相同的代码抽取到父类中,然后通 过钩子函数(见“模板方法模式的扩展”)约束其行为。

三、模板方法模式的扩展

目前为止,这两个模型都稳定地运行,突然有一天,领导急匆匆地找到了我:“看你怎么设计的,车子一启动,喇叭就狂响,吵死人了!客户提出H1型号的悍马喇叭想让它响就响,H2型号的喇叭不要有声音,赶快修改一下。”

怎么做呢

整个流程不变, 只需改变可以控制鸣笛,添加一个控制因素来选择是否鸣笛 添加一个控制方法isAlarm()来控制是否鸣笛。

    /**
     * 钩子方法,默认是会鸣笛
     * @return
     */
    protected boolean isAlarm() {
        return true;
    } 
修改模板方法
    /**
     * 行驶
     */
    public final void run() {
        this.start();
        this.engineBoom();
        System.out.print("跑起来了,");
        if (isAlarm()) {//想叫它鸣笛就鸣笛
            this.alarm();
        }
        this.stop();
    }
抽象类
package com.chb.l.TemplateDesignPattern;
/**
一辆车的功能
    start
    engineboom
    run
    alarm
    stop
 */
public abstract class HummerModel {
    /**
     * 启动
     */
    protected abstract void start();
    /**
     * 引擎轰鸣
     */
    protected abstract void engineBoom();
    /**
     * 行驶
     */
    public final void run() {
        this.start();
        this.engineBoom();
        System.out.print("跑起来了,");
        if (isAlarm()) {//想叫它鸣笛就鸣笛
            this.alarm();
        }
        this.stop();
    }
    /**
     * 遇到情况鸣笛
     */
    protected abstract void alarm();
    /**
     * 停车
     */
    protected abstract void stop();
    /**
     * 钩子方法,默认是会鸣笛
     * @return
     */
    protected boolean isAlarm() {
        return true;
    } 
}
H320重构
package com.chb.l.TemplateDesignPattern;
/**
 230系列车型
 */
public class Hummer320 extends HummerModel{
    //设置一个变量供客户控制钩子方法
    private boolean alarmFlag = true;
    /**
     * 要不要响喇叭,是由客户来决定的
     * @param alarmFlag
     */
    public void setAlarmFlag(boolean alarmFlag) {
        this.alarmFlag = alarmFlag;
    }
    protected boolean isAlarm() {//将外部的参数,通过钩子方法传入公共方法run(),决定是否鸣笛。
        return this.alarmFlag;
    };

    @Override
    protected void start() {
        System.out.print("H320发动。。。");
    }

    @Override
    protected void engineBoom() {
        System.out.print("H320引擎发出轰鸣声 轰轰轰。。。");
    }



    @Override
    protected void alarm() {
        System.out.print("H320:妈的,嘀嘀嘀。。。好狗不挡道,快让开");
    }

    @Override
    protected void stop() {
        System.out.println("H320:前方遇到紧急情况,滋滋滋...,总算停下来了。");
    }

}
H320型号的悍马是由客户自己控制是否要响喇叭,也就是说外界条件改变,影响到模板方法的执行。在我们的抽象类中isAlarm的返回值就是影响了模板方法的执行结果,该方法就叫做钩子方法(Hook Method)。有了钩子方法模板方法模式才算完美,大家 可以想想,由子类的一个方法返回值决定公共部分的执行结果,是不是很有吸引力呀!
关注
打赏
1587549273
查看更多评论
立即登录/注册

微信扫码登录

0.0421s