• 大话设计模式之---模板方法模式


    在学习java的过程中,我们肯定听到过设计模式这名词,在行业中有这么一句话,若您能熟练的掌握23种设计模式,那么你便是大牛!

    好了,废话不多说,今天我跟大家分享一下23种设计模式之一的  模板方法 设计模式

    首先我们要知道什么是模板方法设计模式?

      模板方法设计模式就是定义一个操作中的算法骨架,而将一些实现步骤延迟到子类当中。模板方法使得子类可以在不改变算法结构的情况下,重新定义算法中的某些步骤。

    为什么要使用模板方法设计模式?
      模板方法模式是比较简单的一种设计模式,但是它却是代码复用的一项基本的技术,在类库中尤其重要,它遵循“抽象类应当拥有尽可能多的行为,应当拥有尽可能少的数据”的重构原则。作为模板的方法要定义在父类中,在方法的定义中使用到抽象方法,而只看父类的抽象方法是根本不知道怎样处理的,实际做具体处理的是子类,在子类中实现具体功能,因此不同的子类执行将会得出不同的实现结果,但是处理流程还是按照父类定制的方式。这就是模板方法的要义所在,制定算法骨架,让子类具体实现。

    在什么情况下使用?
         -->算法或操作遵循相似的逻辑
      
       -->重构时(把相同的代码抽取到父类中)

       -->重要、复杂的算法,核心算法设计为模板算法

    接下来我们来看看到底怎么才能实现模板方法设计模式
    我们以饮料机为示例的原型,每台饮料机都可以制作出不同的饮料,如同一台饮料机可 制作咖啡 还可以 制作茶
      假如:制作咖啡的步骤如下:        制作茶的步骤如下:
          1.将水煮沸                1.将水煮沸
          2.用沸水泡咖啡              2.用沸水将茶叶煮五到六分钟
          3.将咖啡倒入杯中             3.将茶水倒入杯中
          4.假如糖块或牛奶             4.加入柠檬或不加任何东西
    那么,由上面的背景可见,我们制作咖啡和制作茶的步骤中 1 3是完全一致的,而2 4则是各自执行的各自的步骤
    所有我们就可以设计一个模板,来规范制作过程
    /*             
     * 抽象类   饮料机模板类
     */
    public abstract class Template {
        /*
         * 制备饮料的模板方法
         * 封装了所有子类的共同遵循的算法框架
         */
        public final void driveTemplate(){ //这个模板必须用final修饰,因为不能允许子类修改这个模板框架,只能是修改特定的步骤
            //1.将水煮沸
            boilWater();
            //2. 炮制饮料
            blew();
            //3. 倒入杯中
            pourInCup();
           //4. 进入调味料
            addCondiments();  
        }
    }
    如上代码就是定义了一个制作饮料的模板,将具体的步骤都罗列出来了
    因为我们的步骤1和步骤3都是相同的所以我们可以将其实现方法定义为私有的,以减少代码的复杂度,而步骤2和步骤4则可定义为抽象方法,其实现交由其子类完成
    如:
    /*
         * 基本方法,将水煮沸
         */
        private void boilWater() {
            System.out.println("将水煮沸");
        }
        
        /*
         * 基本方法,倒入杯中
         */
        private void pourInCup() {
            System.out.println("倒入杯中");
        }
    
        /*
         * 抽象的基本方法  加入调味料
         */
        public abstract void addCondiments();
        
        
        /*
         * 抽象的基本方法  炮制饮料
         */
        public abstract void blew();
    这样我们就定义好了一个模板方法了,我们可以通过创建一个子类来继承自这个模板,重新其抽象方法 
    如 制作咖啡
    /*
     * 制备咖啡的具体实现
     */
    public class Coffee extends Template {
    
        //加入调味料
        @Override
        public void addCondiments() {
            System.out.println("加入糖和牛奶");
        }
    
        //炮制咖啡
        @Override
        public void blew() {
            System.out.println("用沸水冲泡咖啡");
        }
    
    }

     或者是制作茶
    /*
     * 制备茶的具体实现
     */
    public class Tea extends Template {
        //添加调料
        @Override
        public void addCondiments() {
            System.out.println("加入柠檬");
        }
        //冲泡茶
        @Override
        public void blew() {
            System.out.println("用80度的热水浸泡茶叶5分钟");
        }
        
    }
    
    
    
     这样我们在测试类中就能很清楚的看到结果了
    //测试类
    public class Test {
        public static void main(String[] args) {
            System.out.println("制备咖啡");
            Template t1=new Coffee();
            t1.driveTemplate();
            System.out.println("咖啡制备完成");
            System.out.println("=====================");
            System.out.println("制备茶");
            Template t2=new Tea();
            t2.driveTemplate();
            System.out.println("制备茶完成");
        }
    }
    
    

     测试结果如图

     
    当然,如果我们现在有另外一种需求呢?就是我制作茶的时候不想要添加任何东西,这时候我们使用上面的方法是没法完成的,这时候我们就引出了
    模板方法设计模式中的另一个名词, 钩子函数
    我们可以使用钩子函数来判断是否要执行某一步的操作
    如:
    /*             
     * 抽象类   饮料机模板类
     */
    public abstract class Template {
        /*
         * 制备饮料的模板方法
         * 封装了所有子类的共同遵循的算法框架
         */
        public final void driveTemplate(){ //这个模板必须用final修饰,因为不能允许子类修改这个模板框架,只能是修改特定的步骤
            //1.将水煮沸
            boilWater();
            //2. 炮制饮料
            blew();
            //3. 倒入杯中
            pourInCup();
            
            //钩子函数进行判定(例如茶不想加入调味料)
            if(isRight()){
                //4. 进入调味料
                addCondiments();
            }
        }
        
        /*
         * 基本方法,将水煮沸
         */
        private void boilWater() {
            System.out.println("将水煮沸");
        }
        
        /*
         * 基本方法,倒入杯中
         */
        private void pourInCup() {
            System.out.println("倒入杯中");
        }
    
        /*
         * 抽象的基本方法  加入调味料
         */
        public abstract void addCondiments();
        
        
        /*
         * 抽象的基本方法  炮制饮料
         */
        public abstract void blew();
    
        
        //钩子函数  判断用户是否要执行某些功能  
        public boolean isRight(){
            return true;
        }
        
    }
    
    
    
    假如在制作茶的时候不想加任何东西,那么我们只需要在制作茶的子类中将钩子函数重写即可
    /*
     * 制备茶的具体实现
     */
    public class Tea extends Template {
        //添加调料
        @Override
        public void addCondiments() {
            System.out.println("加入柠檬");
        }
        //冲泡茶
        @Override
        public void blew() {
            System.out.println("用80度的热水浸泡茶叶5分钟");
        }
        //重写钩子函数 改变其值
        @Override
        public boolean isRight(){
            return false;
        }
    
    }
    
    
    
    这样的执行结果如图
     
    这样就完成了我们的需求了

    以上就是模板方法设计模式中的内容了,其他设计模式会在后续学到后再跟大家分享分享~~
    注:本人也是初学者,所以写得不好的地方望各位大牛勿怪,有不足的地方还望指出来,欢迎讨论!



  • 相关阅读:
    一行代码轻松修改 Text Field 和 Text View 的光标颜色 — By 昉
    六种手势识别,你用了哪些?——董鑫
    Mac 屏幕录制Gif 制作 By-胡罗
    利用ICMP协议的PING命令获取客户端当前网络质量 by徐文棋
    iOS加载Gif图片的N种方式 By-H罗
    [手游项目3]-10-Go语言atomic原子操作
    [手游项目3]-9-Go语言sync.Map(在并发环境中使用的map)
    LRU原理和Redis实现
    Cleanup failed to process the following paths错误的解决
    [手游项目3]-8-排行榜redis实现
  • 原文地址:https://www.cnblogs.com/liujiayun/p/5544344.html
Copyright © 2020-2023  润新知