设计模式-模版模式

模型模式例子:悍马车模型
不考虑使用设计模式,扩展性等都不考虑
类图:
这里写图片描述
非常简单的实现,你要悍马模型,我给你悍马模型,先写个抽象类,然后两个不同型号的模型实现类,那我们把这个程序实现出来:
HummerModel抽象类的程序如下:

package com.example.xpeng.myapplication;

import android.util.Log;

/**
 * Created by xpeng on 2018/5/29.
 */

public abstract class HumanerModel {

    /**
     * 首先,发动起来
     */
    protected abstract void start();

    /**
     * 还要能停下来
     */
    protected abstract void stop();



    /**
     * 喇叭的声音
     */
    protected abstract void alarm();

    /**
     * 引擎ongoing响
     */
    protected abstract void engineBoom();

    /**
     * 跑起来
     */
    public abstract void run() 
}

H1型号悍马的定义如下:

package com.example.xpeng.myapplication;

import android.util.Log;

/**
 * Created by xpeng on 2018/5/29.
 */

public class HummerH1Model extends HumanerModel {

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

    @Override
    public void start() {
        Log.e("xyz","悍马发动...");
    }

    @Override
    public void stop() {
        Log.e("xyz","悍马停止...");
    }


    @Override
    public void alarm() {
        Log.e("xyz","悍马鸣笛...");
    }

    @Override
    public void engineBoom() {
        Log.e("xyz","悍马引擎声音...");
    }

     public void run() {
        Log.e("xyz","悍马跑起来...");

        this.start();


            this.alarm();


        this.engineBoom();
        this.stop();
    }
}

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

package com.example.xpeng.myapplication;

import android.util.Log;

/**
 * Created by xpeng on 2018/5/29.
 */

public class HummerH2Model extends HumanerModel {

    @Override
    public void start() {
        Log.e("xyz","悍马H2发动...");
    }

    @Override
    public void stop() {
        Log.e("xyz","悍马H2停止...");
    }

    @Override
    public void alarm() {
        Log.e("xyz","悍马H2鸣笛...");
    }

    @Override
    public void engineBoom() {
        Log.e("xyz","悍马H2引擎声音...");
    }

     public void run() {
        Log.e("xyz","悍马跑起来...");

        this.start();


            this.alarm();


        this.engineBoom();
        this.stop();
    }
}

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

package com.example.xpeng.myapplication;

import android.util.Log;

/**
 * Created by xpeng on 2018/5/29.
 */

public abstract class HumanerModel {

    /**
     * 首先,发动起来
     */
    protected abstract void start();

    /**
     * 还要能停下来
     */
    protected abstract void stop();



    /**
     * 喇叭的声音
     */
    protected abstract void alarm();

    /**
     * 引擎ongoing响
     */
    protected abstract void engineBoom();

    /**
     * 跑起来
     */
    public void run() {
        Log.e("xyz","悍马跑起来...");

        this.start();


            this.alarm();


        this.engineBoom();
        this.stop();
    }

}

下面是HummerH1Model的程序:

package com.example.xpeng.myapplication;

import android.util.Log;

/**
 * Created by xpeng on 2018/5/29.
 */

public class HummerH1Model extends HumanerModel {

    @Override
    public void start() {
        Log.e("xyz","悍马发动...");
    }

    @Override
    public void stop() {
        Log.e("xyz","悍马停止...");
    }


    @Override
    public void alarm() {
        Log.e("xyz","悍马鸣笛...");
    }

    @Override
    public void engineBoom() {
        Log.e("xyz","悍马引擎声音...");
    }


}

下面是HummerH2Model的程序:

package com.example.xpeng.myapplication;

import android.util.Log;

/**
 * Created by xpeng on 2018/5/29.
 */

public class HummerH2Model extends HumanerModel {

    @Override
    public void start() {
        Log.e("xyz","悍马H2发动...");
    }

    @Override
    public void stop() {
        Log.e("xyz","悍马H2停止...");
    }

    @Override
    public void alarm() {
        Log.e("xyz","悍马H2鸣笛...");
    }

    @Override
    public void engineBoom() {
        Log.e("xyz","悍马H2引擎声音...");
    }
}

类图修改完毕了,程序也改好了,提交给老大,挺好,开始生产了,提交客户使用了

//客户开着H1型号,出去遛弯儿了
   HummerModel h1 = new HummerH1Model();
        h1.run();
//客户开着H2型号,出去撩妹去了
        HumanerModel h2 = new HummerH2Model();
        h2.run();

非常非常的简单,那如果我告诉你这就是模版模式你会不会很不屑呢?
然后我们继续回顾我们这个模型,回头一想,不对啊,需求分析有点问题,客户要关心模型的启动,停止,鸣笛,引擎声音吗?他只要在run的过程中,听到或看到就成了,暴露那么多方法干嘛呢?把抽象类上的四个方法设置为protected访问权限,还有个缺陷,run方法既然子类都不修改,那是不是可以设置成final类型呢?是滴是滴
好了,重新修改一下类图:
这里写图片描述
这个代码实现就不贴出来了,太简单了,后续有demo下载

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

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

package com.example.xpeng.myapplication;

import android.util.Log;

/**
 * Created by xpeng on 2018/5/29.
 */

public abstract class HumanerModel {

    /**
     * 首先,发动起来
     */
    protected abstract void start();

    /**
     * 还要能停下来
     */
    protected abstract void stop();



    /**
     * 喇叭的声音
     */
    protected abstract void alarm();

    /**
     * 引擎ongoing响
     */
    protected abstract void engineBoom();

    /**
     * 跑起来
     */
    final public void run() {
        Log.e("xyz","悍马跑起来...");

        this.start();

        if (this.isAlarm()){
            this.alarm();
        }

        this.engineBoom();
        this.stop();
    }

    protected  boolean isAlarm(){
        return true;
    }

}

钩子方法模式是由抽象类来实现的,子类可以重写,H2型号的悍马是不会叫的,喇叭是个摆设,看HummerH2Model代码:

package com.example.xpeng.myapplication;

import android.util.Log;

/**
 * Created by xpeng on 2018/5/29.
 */

public class HummerH2Model extends HumanerModel {

    @Override
    public void start() {
        Log.e("xyz","悍马H2发动...");
    }

    @Override
    public void stop() {
        Log.e("xyz","悍马H2停止...");
    }

    @Override
    public void alarm() {
        Log.e("xyz","悍马H2鸣笛...");
    }

    @Override
    public void engineBoom() {
        Log.e("xyz","悍马H2引擎声音...");
    }

    @Override
    protected boolean isAlarm() {
        return false;
    }
}

H1的喇叭是由客户来决定响不响的,其实在类图上已经标明了setAlarm这个方法,我们看HummerH1Model的代码:

package com.example.xpeng.myapplication;

import android.util.Log;

/**
 * Created by xpeng on 2018/5/29.
 */

public class HummerH1Model extends HumanerModel {

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

    @Override
    public void start() {
        Log.e("xyz","悍马发动...");
    }

    @Override
    public void stop() {
        Log.e("xyz","悍马停止...");
    }


    @Override
    public void alarm() {
        Log.e("xyz","悍马鸣笛...");
    }

    @Override
    public void engineBoom() {
        Log.e("xyz","悍马引擎声音...");
    }

    @Override
    protected boolean isAlarm() {
        return this.alarmFlag;
    }

    public void setAlarm(boolean isAlarm){
        this.alarmFlag = isAlarm;
    }
}

我们来看最终的调用:

        HummerH1Model h1 = new HummerH1Model();
        h1.setAlarm(true);
        h1.run();

        HumanerModel h2 = new HummerH2Model();
        h2.run();

看到没,这个模型run起来就有声音了,那当然把h1.setAlarm(false)运行起来喇叭就没有声音了,钩子方法的作用就是这样滴。
那我们总结一下模版方法模式,模版方法模式就是在模版方法中按照一个规则和顺序调用基本方法,具体到我们上面那个例子就是run方法按照规定的顺序(先调用start,然后再调用engineBoom,再调用alarm,最后调用stop)调用本类的其他方法,并且由isAlarm妇女广发的返回值确定run中拿执行顺序变更,通用类图如下:
这里写图片描述
其中TemplateMethod就是模版方法,operation1和operation2就是基本方法,模版方法就是通过汇总或排序基本方法而产生的结果集。

经常有人问,父类怎么调用子类的方法?
三种:
第一,把子类传递到父类的有参构造中,然后调用
第二,使用反射的方式调用,你使用了反射还有谁不能调用呢
第三,父类调用子类的静态方法
没想明白为什么父类要调用子类的方法,如果一定要调用,那为什么要继承它呢?搞不懂。其实这个问题可以换个角度去理解,在重写了父类部分方法后,再调用从父类继承的方法,产生不同的结果(而这正是模版方法模式),这是不是也可以理解为父类调用了子类的方法呢?你修改了子类,影响了父类的结果,模版方法模式就是这样的效果。

DEMO下载地址

模版模式demo

  • 1
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值