• 装饰者模式


    装饰者模式:动态的将额外的责任添加到对象上去,相对于继承,提供更加灵活的扩展方案。

    装饰者模式,有4个抽象的类概念:

    1. 抽象构建类:被装饰对象的接口
    2. 具体的构建类:被装饰的对象
    3. 抽象装饰者:怎么进行装饰的接口
    4. 具体装饰者:具体装饰的对象

    关系类图如下:

    其中重点是:抽象装饰者接口继承了被装饰对象的接口,这点非常重要,它是能够进行动态装饰的关键,根据接口动态的去匹配具体构件类。

    举例:
    咖啡店原本提供有2种咖啡:CoffeeDarked深焙咖啡、CoffeeMixed混合咖啡,先需要在这2中咖啡中可以添加:Milk牛奶、Mocha摩卡。
    思考:

    按照上图分析结果,可以调出6中不同口味的咖啡。如果按照继承的逻辑,一种咖啡可能需要建立一个子类(或者实现类),此处就需要建6个子类。如果需要添加的不止牛奶和摩卡2种,那子类将非常庞大。

    如果使用装饰者模式,就不需要建立6个子类,只需要建立2种具体装饰者类(Milk、Mocha),即可满足需求。

    下面是代码实现:()
    1)抽象构件类

     1 /**
     2  * 抽象构件类
     3  * @author Administrator
     4  *
     5  */
     6 public interface Coffee {
     7   /**
     8    * 描述什么样的咖啡
     9    * @return
    10    */
    11   public abstract String getDescription();
    12   
    13   /**
    14    * 计算咖啡的价格
    15    * @return
    16    */
    17   public abstract double count();
    18 }

    2)具体构件类

     1 /**
     2  * 具体构件类:深焙咖啡
     3  * @author Administrator
     4  *
     5  */
     6 public class CoffeeDarked implements Coffee {
     7 
     8   @Override
     9   public String getDescription() {
    10     return "深焙咖啡";
    11   }
    12 
    13   @Override
    14   public double count() {
    15     return 10;
    16   }
    17 }
     1 /**
     2  * 具体构建类:混合咖啡
     3  * @author Administrator
     4  *
     5  */
     6 public class CoffeeMixed implements Coffee {
     7 
     8   @Override
     9   public String getDescription() {
    10     return "混合咖啡";
    11   }
    12 
    13   @Override
    14   public double count() {
    15     return 20;
    16   }
    17 }

    3)抽象装饰者类

     1 /**
     2  * 咖啡装饰者接口
     3  * @author Administrator
     4  *
     5  */
     6 public interface DecoratorCoffee extends Coffee {
     7 
     8   public abstract String getDescription();
     9   
    10 }

    4)具体装饰者类

     1 /**
     2  * 具体装饰者:加牛奶
     3  * @author Administrator
     4  *
     5  */
     6 public class DecoratorMilk implements DecoratorCoffee {
     7   
     8   private Coffee coffee;
     9   
    10   public DecoratorMilk(Coffee coffee){
    11     this.coffee = coffee;
    12   }
    13 
    14   @Override
    15   public double count() {
    16     
    17     return coffee.count() + 5;
    18   }
    19 
    20   @Override
    21   public String getDescription() {
    22     return coffee.getDescription() + "加牛奶";
    23   }
    24 }
     1 /**
     2  * 具体装饰者类:加摩卡
     3  * @author Administrator
     4  *
     5  */
     6 public class DecoratorMocha implements DecoratorCoffee {
     7   
     8   private Coffee coffee;
     9   
    10   public DecoratorMocha(Coffee coffee){
    11     this.coffee = coffee;
    12   }
    13 
    14   @Override
    15   public String getDescription() {
    16     return coffee.getDescription() + "加摩卡";
    17   }
    18 
    19   public double count() {
    20     return coffee.count() + 2;
    21   }
    22 }

    最后测试下:

     1 public class DecoratorTest {
     2 
     3   /**
     4    * @param args
     5    */
     6   public static void main(String[] args) {
     7     
     8     //想要一杯混合咖啡
     9     Coffee coffee1 = new CoffeeMixed();
    10     System.out.println(coffee1.getDescription() + " " + coffee1.count());
    11     
    12     // 想要一杯加牛奶的混合咖啡(对coffee1进行装饰,加上牛奶)
    13     Coffee coffee2 = new DecoratorMilk(coffee1);
    14     System.out.println(coffee2.getDescription() + " " + coffee2.count());
    15     
    16     // 想要一杯加摩卡加牛奶的深焙咖啡
    17     Coffee coffee3 = new CoffeeDarked();
    18     coffee3 = new DecoratorMilk(coffee3);
    19     coffee3 = new DecoratorMocha(coffee3);//进一步对加了牛奶的咖啡加上摩卡
    20     System.out.println(coffee3.getDescription() + " " + coffee3.count());
    21   }
    22 }

    测试结果:

    总结:
    装饰者模式能实现动态的对对象进行扩展,主要有2点,一是,抽象装饰者类和具体的构建类有相同的接口,二是具体的装饰者类和抽象构建类之间有依赖(具体在UML中怎么称呼不太了解,之后在补习下),并且通过构造器依赖注入,在运行时,就根据具体的实现类注入了。这样就实现了对象动态扩展。

    装饰者模式和代理模式的区别:
    代理模式:给对象创建一个代理对象,由代理对象代替对象进行操作。
    装饰者模式:给对象创建一个装饰类对象,对对象进行功能的扩展。

  • 相关阅读:
    如何获得刚刚插入数据的id
    Ado.net怎么执行存储过程?
    SqlServer存储过程,学习
    视图view
    CTE(公用表表达式)
    事务
    over()的用法
    Inno Setup 系列之安装、卸载前检测进程运行情况并关闭相应进程
    Inno Setup的常用脚本
    跟武哥一起学习Spring Boot
  • 原文地址:https://www.cnblogs.com/teiba/p/10620195.html
Copyright © 2020-2023  润新知