• 设计模式之模板设计模式


    模板设计模式—基于抽象类的,核心是封装算法

    • 模板方法定义了一个算法的步骤,并允许子类为一个或多个步骤提供具体实现
    • 模板(模板方法)模式(Servlet、AQS)
      • 在一个方法中定义一个算法的骨架,并将一些具体步骤延迟到子类中实现。
      • 模板模式使得子类可以在不改变算法结构的基础上,重新具体定义算法中的某些步骤

    讲模板设计模式之前,我们用代码来实现咖啡和茶制作的类:

    class Coffee {    
        /*   
         * 咖啡冲泡法(算法)     
        */    
        void prepareRecipe() {        
            boilWater();        
            brewCoffeeGrings();        
            pourInCup();        
            addSugarAndMilk();    
        }       
        public void boilWater() {        
            System.out.println("将水煮沸");    
        } 
        public void brewCoffeeGrings() {        
            System.out.println("冲泡咖啡");    
        }  
        public void pourInCup() {        
            System.out.println("把咖啡倒进杯子中");    
        }
        public void addSugarAndMilk() {        
            System.out.println("加糖和牛奶");    
        } 
    }
    

    class Tea {
    /*
    * 冲泡茶法(算法)
    */
    void prepareRecipe() {
    boilWater();
    steepTeaBag();
    pourInCup();
    addLemon();
    }
    public void boilWater() {
    System.out.println("将水煮沸");
    }
    public void steepTeaBag() {
    System.out.println("浸泡茶叶");
    }
    public void pourInCup() {
    System.out.println("把茶倒进杯子中");
    }
    public void addLemon() {
    System.out.println("加柠檬");
    }
    }
    class Test {
    public static void main(String[] agrs) {
    Coffee coffee = new Coffee();
    Tea tea = new Tea();
    coffee.prepareRecipe();
    tea.prepareRecipe();
    }
    }

    在这里插入图片描述

    我们在这两个类中发现了重复代码,因此我们需要重新理一下我们的设计。

    • 既然茶和咖啡是如此的相似,因此我们应该将共同的部分抽取出来,放进一个基类中。
    • 从冲泡法入手。观察咖啡和茶的冲泡法我们会发现,两种冲泡法都采用了相同的算法:
      • 将水煮沸
      • 用热水泡饮料
      • 把饮料倒进杯子
      • 在饮料内加入适当的调料

    实际上,浸泡(steep)和冲泡(brew)差异并不大。因此我们给它一个新的方法名称brew(),这样我们无论冲泡的是何种饮 料都可以使用这个方法。同样的,加糖、牛奶还是柠檬也很相似,都是在饮料中加入其它调料,因此我们也给它一 个通用名称addCondiments()。

    /** 
     * 咖啡因饮料是一个抽象类 
    **/ 
    abstract class CaffeineBeverage {    
        /**
         * 现在用同一个prepareRecipe()方法处理茶和咖啡。     
         * 声明为final的原因是我们不希望子类覆盖这个方法!     
        **/    
        final void prepareRecipe() {        
            boilWater();        
            brew();        
            pourInCup();        
            addCondiments();   
        }
         /**     
          * 咖啡和茶处理这些方法不同,因此这两个方法必须被声明为抽象,留给子类实现     
         **/    
        abstract void brew();    
        abstract void addCondiments();
    
    void boilWater() {        
         System.out.println("将水煮沸");    
    }
    void pourInCup() {        
         System.out.println("把饮料倒进杯子中");    
    } 
    

    }

    class Coffee extends CaffeineBeverage {
    public void brew() {
    System.out.println("冲泡咖啡");
    }
    public void addCondiments() {
    System.out.println("加糖和牛奶");
    }
    }

    class Tea extends CaffeineBeverage {
    public void brew() {
    System.out.println("浸泡茶叶");
    }
    public void addCondiments() {
    System.out.println("加柠檬");
    }
    }
    class Test {
    public static void main(String[] agrs) {
    CaffeineBeverage coffee = new Coffee();
    CaffeineBeverage tea = new Tea();
    coffee.prepareRecipe();
    tea.prepareRecipe();
    }
    }

    模板方法定义了一个算法的步骤,并允许子类为一个或者多个步骤提供具体实现

    在模板设计模式下还有一种钩子用法

    钩子方法是一类"默认不做事的方法" ,子类可以视情况决定要不要覆盖它们。
    比如说,顾客点杯咖啡时,可以选择加不加牛奶或者糖!!!

    import java.util.Scanner;
    

    /**

    • 咖啡因饮料是一个抽象类
      /
      abstract class CaffeineBeverage {
      /

      • 现在用同一个prepareRecipe()方法处理茶和咖啡。
      • 声明为final的原因是我们不希望子类覆盖这个方法!
        /
        final void prepareRecipe() {
        boilWater();
        brew();
        pourInCup();
        if(customerWantsCondiments())
        addCondiments();
        }
        /
      • 咖啡和茶处理这些方法不同,因此这两个方法必须被声明为抽象,留给子类实现
        **/
        abstract void brew();
        abstract void addCondiments();

      void boilWater() {
      System.out.println("将水煮沸");
      }
      void pourInCup() {
      System.out.println("把饮料倒进杯子中");
      }
      boolean customerWantsCondiments() {
      return true;
      }
      }

    class Coffee extends CaffeineBeverage {
    public void brew() {
    System.out.println("冲泡咖啡");
    }
    public void addCondiments() {
    System.out.println("加糖和牛奶");
    }

     /**  
      * 子类覆写了钩子函数,实现自定义功能   
     **/ 
    boolean customerWantsCondiments() {
        String result = getUserInput();
        if(result.equals("y"))
            return true;
        else
            return false;
    }    
    private String getUserInput() {
        System.out.println("您想要在咖啡中加入牛奶或糖吗(y/n)?");
        Scanner scanner = new Scanner(System.in);
        String str = scanner.nextLine();
        return str;
    }
    

    }

    class Tea extends CaffeineBeverage {
    public void brew() {
    System.out.println("浸泡茶叶");
    }
    public void addCondiments() {
    System.out.println("加柠檬");
    }
    }
    class Test {
    public static void main(String[] agrs) {
    CaffeineBeverage coffee = new Coffee();
    CaffeineBeverage tea = new Tea();
    coffee.prepareRecipe();
    tea.prepareRecipe();
    }
    }

    在这里插入图片描述
    在这里插入图片描述

    转载:https://blog.csdn.net/sifanchao/article/details/83418339

  • 相关阅读:
    PHP配置redis支持
    redis入门——redis常用命令
    CentOS7 linux下yum安装redis以及使用
    Linux安装配置git
    Java基础88 数据库设计的三大范式
    Java基础87 MySQL数据约束
    Java基础85 MVC开发模式
    错误/异常:java.net.SocketException: Unrecognized Windows Sockets error: 0: JVM_Bind;的解决方法
    Java基础84 javaBean规范
    Java基础83 JSP标签及jsp自定义标签(网页知识)
  • 原文地址:https://www.cnblogs.com/blogcpp/p/13382060.html
Copyright © 2020-2023  润新知