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

本文介绍了设计模式中的模板模式,通过车辆模型的例子展示了如何使用模板方法定义操作流程,并利用钩子方法实现条件判断。文章强调了模板方法模式在框架中的应用,允许子类在不改变整体流程的情况下扩展特定步骤。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

⑨设计模式之模板模式(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. 父类调用子类的静态方法


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

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值