zoukankan      html  css  js  c++  java
  • 设计模式---模板设计模式(java)

    模板设计模式

    1)基本定义

    定义:在一个抽象类中公开定义执行它的方法的方式/模板,子类可以重写方法的实现,但调用将以抽象类中定义的方式进行。这种类型的设计模式属于行为型设计模式。
    意图:定义一个操作种的算法骨架,将一些具体步骤的实现延迟到子类中
    解决问题:一些方法通用,却在每一个子类重写这些方法
    关键代码:算法骨架在抽象类实现(有时使用final修饰以禁止子类重写以防止恶意修改),一些具体步骤在子类类实现
    优点:封装不变部分、扩展可变部分;提取公共代码、便于维护;行为由父类统一控制,子类实现
    缺点:每一个不同的实现都需要一个子类实现,导致类数量增加,系统变得庞大
    场景:有多个子类共有的方法,逻辑相同;重要的、复杂的方法,可以考虑作为模板方法

    设计模式类图

     2)例子

    以悍马车模型为例,类图如下:

    实现代码如下:

    /** 悍马车模型 **/
    public abstract class HummerModel {
        /** 启动 **/
        public abstract void start();
        /** 停止 **/
        public abstract void stop();
        /** 喇叭鸣叫 **/
        public abstract void alarm();
        /** 引擎轰鸣 **/
        public abstract void engineBoom();
        /** 汽车跑起来 **/
        public abstract void run();
    }
    
    public class HM1 extends HummerModel{
        @Override
        public void start() {
            System.out.println("HM1 start");
        }
        @Override
        public void stop() {
            System.out.println("HM1 stop");
        }
        @Override
        public void alarm() {
            System.out.println("HM1 alarm");
        }
        @Override
        public void engineBoom() {
            System.out.println("HM1 engineBoom");
        }
        @Override
        public void run() {
            System.out.println("HM1 run");
            alarm();
            start();
            engineBoom();
            stop();
        }
    }
    
    public class HM2 extends HummerModel{
        @Override
        public void start() {
            System.out.println("HM2 start");
        }
        @Override
        public void stop() {
            System.out.println("HM2 stop");
        }
        @Override
        public void alarm() {
            System.out.println("HM2 alarm");
        }
        @Override
        public void engineBoom() {
            System.out.println("HM2 engineBoom");
        }
        @Override
        public void run() {
            System.out.println("HM2 run");
            alarm();
            start();
            engineBoom();
            stop();
        }
    }

    观察上面代码,发现明显的问题,让汽车跑起来的方法run()所有的车型应该是一样的,应该在抽象类中,修改类图如下:

    新的实现代码如下:

    /** 悍马车模型 **/
    public abstract class HummerModel {
        /** 启动 **/
        public abstract void start();
        /** 停止 **/
        public abstract void stop();
        /** 喇叭鸣叫 **/
        public abstract void alarm();
        /** 引擎轰鸣 **/
        public abstract void engineBoom();
        /** 汽车跑起来 **/
        public final void run() {
            System.out.println("HM2 run");
            alarm();
            start();
            engineBoom();
            stop();
        }
    }
    
    public class HM1 extends HummerModel{
        @Override
        public void start() {
            System.out.println("HM1 start");
        }
        @Override
        public void stop() {
            System.out.println("HM1 stop");
        }
        @Override
        public void alarm() {
            System.out.println("HM1 alarm");
        }
        @Override
        public void engineBoom() {
            System.out.println("HM1 engineBoom");
        }
    }
    
    public class HM2 extends HummerModel{
        @Override
        public void start() {
            System.out.println("HM2 start");
        }
        @Override
        public void stop() {
            System.out.println("HM2 stop");
        }
        @Override
        public void alarm() {
            System.out.println("HM2 alarm");
        }
        @Override
        public void engineBoom() {
            System.out.println("HM2 engineBoom");
        }
    }

    调用如下:

    public class HMTest {
        public static void main(String[] args) {
            HummerModel h1 = new HM1();
            h1.run();
            HummerModel h2 = new HM2();
            h2.run();
        }
    }

    仔细思考上面的实现,会发现以下问题:
    1)客户要关心模型的启动,停止,鸣笛,引擎声音吗?他只要在run的过程中,听到或看到就成了,暴露那么多方法干嘛呢?把抽象类上的四个方法设置为protected访问权限
    2)run方法设置成final,子类不可修改,但不是所有的车型都是想鸣喇叭,且客户更想在想要鸣时就鸣,由自己决定,这就可以使用钩子方法。
    修改类图如下:

    实现代码如下:

    /** 悍马车模型 **/
    public abstract class HummerModel {
        /** 启动 **/
        protected abstract void start();
        /** 停止 **/
        protected abstract void stop();
        /** 喇叭鸣叫 **/
        protected abstract void alarm();
        /** 引擎轰鸣 **/
        protected abstract void engineBoom();
        /** 汽车跑起来 **/
        public final void run() {
            System.out.println("HM2 run");
            if(isAlarm())
                alarm();
            start();
            engineBoom();
            stop();
        }
        /** 钩子方法,是否鸣笛 ,默认实现**/
        protected boolean isAlarm() {
            return true;
        }
    }
    
    public class HM1 extends HummerModel{
        @Override
        protected void start() {
            System.out.println("HM1 start");
        }
        @Override
        protected void stop() {
            System.out.println("HM1 stop");
        }
        @Override
        protected void alarm() {
            System.out.println("HM1 alarm");
        }
        @Override
        protected void engineBoom() {
            System.out.println("HM1 engineBoom");
        }
        
        private boolean isAlarm = false;
        /** 子类自己提供设置是否鸣笛的接口 **/
        public void setIsAlarm(boolean isAlarm) {
            this.isAlarm = isAlarm;
        }
        /** 重写钩子方法,是否鸣笛 **/
        protected boolean isAlarm() {
            return isAlarm;
        }
    }
    
    public class HM2 extends HummerModel{
        @Override
        protected void start() {
            System.out.println("HM2 start");
        }
        @Override
        protected void stop() {
            System.out.println("HM2 stop");
        }
        @Override
        protected void alarm() {
            System.out.println("HM2 alarm");
        }
        @Override
        protected void engineBoom() {
            System.out.println("HM2 engineBoom");
        }
        /** 不提供钩子方法重写,不提供设置是否鸣笛的接口 **/
    }

    调用如下:

    public class HMTest {
        public static void main(String[] args) {
            HM1 h1 = new HM1();
            h1.setIsAlarm(true);//这里setIsAlarm方法不在父类中,只可以使用子类对象调用
            h1.run();
            HummerModel h2 = new HM2();
            h2.run();
        }
    }

    注意:callback和“钩子”是两个完全不同的概念,callback是指:由我们自己实现的,但是预留给系统调用的函数,我们自己是没有机会调用的,但是我们知道系统在什么情况下会调用该方法。而“钩子”是指:声明在抽象类中的方法,只有空的或默认的实现,通常应用在模板设计模式中,让子类可以对算法的不同点进行选择或挂钩,要不要挂钩由子类决定。

    由例子可以看出,模板设计核心原理是通过继承、重写、实现来实现父类调用子类方法。

  • 相关阅读:
    关于springMVC+Mybatis jar包详解
    关于struts2的过滤器和mybatis的插件的分析
    C# Zip压缩、解压
    JS 字符串转字节截取
    JS 时间差计算 XX秒前、XX小时前、XX天前
    IIS配置web.config 将带www域名转为不带www域名
    JavaScript获取当前url路径
    SQL 查询今天、昨天、7天内、30天的数据
    SQL求解两个时间差
    SqlServer获取当前日期
  • 原文地址:https://www.cnblogs.com/ShouWangYiXin/p/10862408.html
Copyright © 2011-2022 走看看