⑨设计模式之模板模式(Template Module)

来源:互联网 发布:那个答题软件好用 编辑:程序博客网 时间:2024/06/08 12:28

⑨设计模式之模板模式(Template Module)

什么是模板模式?

先给一个情景,现在我要设计一个车辆模型,一开始的类图如下

QQ截图20170904200149

然后程序写到这里,你就看到问题了,run方法的实现应该写在抽象类上,而不是实现类上

QQ截图20170904200853

写到这里读者可能会有疑问:

  1. 为什么HummerModel的前四个基本方法都是protected修饰的呢?

    客户不需要关系启动、停止、鸣笛和引擎声音,他只要在run过程中听到或看到就成了,不需要暴露那么多方法。(这跟需求分析有关,所以想不懂也没关系)

  2. 为什么run方法使用final修饰?

    因为final修饰后,该抽象类的子类就不能修改run这个模板方法了。对的,你没看错,run()就是模板方法,就是这么简单

可以看一下代码。

package cn.cjm.templateModule;/** * 悍马汽车模型 *  <p>Title:HummerModule </p> *  <p>Description: </p> *  @author cjm  *  @date 2017年9月4日 下午8:07:53    */    public abstract class HummerModule {    protected abstract void start();    protected abstract void alarm();    protected abstract void engineBoom();    protected abstract void stop();    final public void run(){        this.start();// 启动汽车        this.alarm();// 开启喇叭        this.engineBoom();// 引擎在发动        this.stop();//汽车停止    }}

但是这里有一个问题,一但车子启动,喇叭就狂响,不能根据实际情况设置喇叭响不响,现在修改类图:QQ截图20170904201603

看一下抽象类代码

package cn.cjm.templateModule;/** * 悍马汽车模型 *  <p>Title:HummerModule </p> *  <p>Description: </p> *  @author cjm  *  @date 2017年9月4日 下午8:07:53    */    public abstract class HummerModule {    protected abstract void start();    protected abstract void alarm();    protected abstract void engineBoom();    protected abstract void stop();    final public void run(){        this.start();// 启动汽车        if(this.isAlarm()){            this.alarm();// 开启喇叭        }        this.engineBoom();// 引擎在发动        this.stop();//汽车停止    }    // 钩子方法,默认喇叭会响的    protected boolean isAlarm(){        return false;    }    }

看一下实现类

package cn.cjm.templateModule;public class HummerH1Module extends HummerModule{private boolean alarmFlag = false;    @Override    protected void start() {        System.out.println("悍马H1汽车启动...");    }    @Override    protected void alarm() {        System.out.println("悍马H1汽车喇叭响...");    }    @Override    protected void engineBoom() {        System.out.println("悍马H1汽车引擎启动...");    }    @Override    protected void stop() {        System.out.println("悍马H1汽车停止...");    }    @Override    protected boolean isAlarm() {        return super.isAlarm();    }    protected void setAlarm(boolean flag){        this.alarmFlag = flag;    }}

看到没,通过setAlarm()就可以控制alarm()这个方法是否执行了,这就是钩子方法的作用!

总结:

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

QQ截图20170904203422

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

经常有人问“父类怎么调用子类的方法”,这个问题很有普遍性,我的回答是能,但是强烈的、极度的不建议,怎么做呢?

  1. 把子类传递到父类的有参构造中,然后调用

  2. 使用反射的方式调用。

  3. 父类调用子类的静态方法


    这三种都是父类直接调用子类的方法,但是我就一直不懂为什么要父类调用子类的方法,如果一定要调用子类,那为什么继承它呢?搞不懂。

    其实这个问题可以换个角度去理解,使用模板方法模式,也可以实现父类调用子类的方法。你修改了子类,影响了父类的结果,模板方法模式就是这样的效果

原创粉丝点击