专栏首页Jed的技术阶梯Java设计模式之模板方法模式

Java设计模式之模板方法模式

假设我们现在要造一批悍马汽车,悍马汽车有两个系列H1和H2,首先不考虑任何设计模式,看看设计的类图:

看看代码的实现:

/**
 * @description: 代表悍马汽车的抽象类
 */
public abstract class Hummer {
    
    public abstract void start(); // 启动汽车
    public abstract void stop(); // 刹车
    public abstract void alarm(); // 鸣笛
    public abstract void engineBoom(); // 启动引擎
    public abstract void run(); // 汽车行驶的整个过程
    
}
public class HummerH1 extends Hummer {

    @Override
    public void start() {
        System.out.println("悍马H1启动...");
    }

    @Override
    public void stop() {
        System.out.println("悍马H1停止...");
    }

    @Override
    public void alarm() {
        System.out.println("悍马H1鸣笛...");
    }

    @Override
    public void engineBoom() {
        System.out.println("悍马H1引擎轰鸣...");
    }

    /**
     * 悍马H1行驶的整个过程
     */
    @Override
    public void run() {
        start();
        engineBoom();
        alarm();
        stop();
    }

}
public class HummerH2 extends Hummer {
    
    @Override
    public void start() {
        System.out.println("悍马H2启动...");
    }

    @Override
    public void stop() {
        System.out.println("悍马H2停止...");
    }

    @Override
    public void alarm() {
        System.out.println("悍马H2鸣笛...");
    }

    @Override
    public void engineBoom() {
        System.out.println("悍马H2引擎轰鸣...");
    }

    /**
     * 悍马H2行驶的整个过程
     */
    @Override
    public void run() {
        start();
        engineBoom();
        alarm();
        stop();
    }
}

程序写到这里,我们发现,run()方法的实现应该在抽象类上,不应该在实现类上,好,我们修改一下类图和实现:

public abstract class Hummer {
    
    public abstract void start(); // 启动汽车
    public abstract void stop(); // 刹车
    public abstract void alarm(); // 鸣笛
    public abstract void engineBoom(); // 启动引擎
    
    // 汽车行驶的过程
    public void run() {
        start();
        engineBoom();
        alarm();
        stop();
    } 
    
}
public class HummerH1 extends Hummer {

    @Override
    public void start() {
        System.out.println("悍马H1启动...");
    }

    @Override
    public void stop() {
        System.out.println("悍马H1停止...");
    }

    @Override
    public void alarm() {
        System.out.println("悍马H1鸣笛...");
    }

    @Override
    public void engineBoom() {
        System.out.println("悍马H1引擎轰鸣...");
    }

}
public class HummerH2 extends Hummer {
    
    @Override
    public void start() {
        System.out.println("悍马H2启动...");
    }

    @Override
    public void stop() {
        System.out.println("悍马H2停止...");
    }

    @Override
    public void alarm() {
        System.out.println("悍马H2鸣笛...");
    }

    @Override
    public void engineBoom() {
        System.out.println("悍马H2引擎轰鸣...");
    }

}

接下来我们测试一下模板方法模式:

public class App {
    
    public static void main(String[] args) {
        
        HummerH1 h1 = new HummerH1();
        h1.run();
        
        HummerH2 h2 = new HummerH2();
        h2.run();
        
    }

}

结果:

悍马H1启动...
悍马H1引擎轰鸣...
悍马H1鸣笛...
悍马H1停止...
悍马H2启动...
悍马H2引擎轰鸣...
悍马H2鸣笛...
悍马H2停止...

然后我们又发现问题了,悍马牌汽车start()、stop()、alarm()、engineBoom()方法是只有悍马系列的车(H1、H2)可以调用,奥拓是万万不能使用悍马的这些的方法的,那么我们就把抽象类的其他4个方法的权限改为protected

而且,run()方法既然子类都不修改,就设置为final类型的方法

修改后的类图和Hummer类的代码如下:

public abstract class Hummer {
    
    protected abstract void start(); // 启动汽车
    protected abstract void stop(); // 刹车
    protected abstract void alarm(); // 鸣笛
    protected abstract void engineBoom(); // 启动引擎
    
    // 汽车行驶的过程
    public final void run() {
        start();
        engineBoom();
        alarm();
        stop();
    } 
    
}

其他的子类都不用修改,大家请看这个run()方法,他定义了调用其他方法的顺序,并且子类是不能修改的,这个叫做模板方法

start()、stop()、alarm()、engineBoom()这四个方法是子类必须实现的,而且这四个方法的修改对应了不同的类,这个叫做基本方法,基本方法又分为三种:在抽象类中实现了的基本方法叫做具体方法;在抽象类中没有实现,在子类中实现了叫做抽象方法,我们这四个基本方法都是抽象方法,由子类来实现的;还有一种叫做钩子方法,看下面的内容来学习一下钩子方法:

我们发现,汽车一运行起来就会鸣笛(调用alarm()),更符合实际情况的是,我想让它鸣笛它才能鸣笛,我不按喇叭它就不能自己响,于是增加一个钩子方法,isAlarm(),继续修改类图:

修改Hummer类:

public abstract class Hummer {
    
    protected abstract void start(); // 启动汽车
    protected abstract void stop(); // 刹车
    protected abstract void alarm(); // 鸣笛
    protected abstract void engineBoom(); // 启动引擎
    
    // 钩子方法,默认喇叭是会响的
    protected boolean isAlarm() { 
        return true; 
    }
    
    // 汽车行驶的过程
    public final void run() {
        start();
        engineBoom();
        if(isAlarm()) {
            alarm();
        }
        stop();
    } 
    
}

H2系列的悍马车不会鸣笛,喇叭就是个摆设,那么代码如下:

public class HummerH2 extends Hummer {
    
    @Override
    public void start() {
        System.out.println("悍马H2启动...");
    }

    @Override
    public void stop() {
        System.out.println("悍马H2停止...");
    }

    @Override
    public void alarm() {
        System.out.println("悍马H2鸣笛...");
    }

    @Override
    public void engineBoom() {
        System.out.println("悍马H2引擎轰鸣...");
    }
    
    @Override
    public boolean isAlarm() {
        return false;
    }

}

H1系列的悍马,用户可以自己决定是否鸣笛,代码如下:

public class HummerH1 extends Hummer {
    
    private boolean alarmFlag = true; //是否要响喇叭
    
    //要不要响喇叭,是由用户来决定的
    public void setAlarm(boolean isAlarm){ 
        this.alarmFlag = isAlarm; 
    }

    @Override
    public void start() {
        System.out.println("悍马H1启动...");
    }

    @Override
    public void stop() {
        System.out.println("悍马H1停止...");
    }

    @Override
    public void alarm() {
        System.out.println("悍马H1鸣笛...");
    }

    @Override
    public void engineBoom() {
        System.out.println("悍马H1引擎轰鸣...");
    }
    
    //钩子方法,默认喇叭是会响的
    @Override
    protected boolean isAlarm(){ 
        return this.alarmFlag; 
    }

}

然后我们修改一下测试代码:

public class App {
    
    public static void main(String[] args) {
        
        HummerH1 h1 = new HummerH1();
        // 我就不想听见H1的喇叭响!
        h1.setAlarm(false);
        h1.run();
        
        HummerH2 h2 = new HummerH2();
        h2.run();
        
    }

}

结果:

悍马H1启动...
悍马H1引擎轰鸣...
悍马H1停止...
悍马H2启动...
悍马H2引擎轰鸣...
悍马H2停止...

总结一下模板方法模式:

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

其中templateMethod()就是模板方法,operation1()和operation2()就是基本方法,模板方法是通过汇总或排序基本方法而产生的结果集。

好了,模板方法模式就是这样,以后再有高手很牛X的说“用模板方法模式就可以实现…”,你再也不用很崇拜的看着他,哇,牛人,模板方法模式是什么呀?

本文原书: 《您的设计模式》 作者:CBF4LIFE

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • Java设计模式之命令模式

    假设某个项目组分为需求组(Requirement Group,简称RG)、美工组(Page Group,简称PG)、代码组(Code Group,简称CG),还...

    CoderJed
  • Java设计模式之单例模式

    这个模式是很有意思,而且比较简单,但是我还是要说因为它使用的是如此的广泛,如此的有人缘,单例就是单一、独苗的意思,那什么是独一份呢?你的思维是独一份,除此之外还...

    CoderJed
  • Java设计模式之代理模式

    什么是代理模式呢?我很忙,忙的没空理你,那你要找我呢就先找我的代理人吧,那代理人总要知道被代理人能做哪些事情不能做哪些事情吧,那就是两个人具备同一个接口,代理人...

    CoderJed
  • 装饰模式

    概述 23种设计模式之一,英文叫DecoratorPattern,中文也叫装饰模式、修饰模式。装饰模式是在不改变类文件和不使用继承的情况下,运行期动态扩展一个对...

    高爽
  • APK安装流程详解1——有关"安装ing"的实体类概述

    该类包含了从AndroidManifest.xml文件中收集的所有信息。 PackageInfo.java源码地址 通过源码我们知道PackageInfo是...

    隔壁老李头
  • 基于Springboot+Dubbo+Nacos 注解方式实现微服务调用

    今天跟大家分享基于Springboot+Dubbo+Nacos 注解方式实现微服务调用的知识。

    程序员小强
  • JavaSE学习总结(四)——Java面向对象十分钟入门

    面向对象编程(Object Oriented Programming,OOP)是一种计算机模拟人类的自然思维方式的编程架构技术,解决了传统结构化开发方法中客观...

    张果
  • Android四大组件之Service

    Android四大组件之Service 服务的两种开启方式: startService();开启服务. 开启服务后 服务就会长期的后台运行,即使调用者退出了....

    xiangzhihong
  • java设计模式 (1) 工厂模式,抽象工厂模式,单子模式

    工厂模式就是实例化对象,用工厂方法代替new操作的一种模式,会给你系统带来更大的可扩展性和尽量少的修改量。

    曼路
  • 怒肝俩月,新鲜出炉史上最有趣的Java小白手册,第一版

    这么说吧,在我眼里,Java 就是最流行的编程语言,没有之一(PHP 往一边站)。不仅岗位多,容易找到工作,关键是薪资水平也到位,不学 Java 亏得慌,对吧?

    沉默王二

扫码关注云+社区

领取腾讯云代金券