欢迎访问悦橙教程(wld5.com),关注java教程。悦橙教程  java问答|  每日更新
页面导航 : > > 文章正文

Java装饰者模式的深入了解,

来源: javaer 分享于  点击 18192 次 点评:92

Java装饰者模式的深入了解,


目录
  • 一、装饰模式的定义和特点
  • 二、装饰模式的结构
  • 三、咖啡点单案例演示
    • 代码实例:
  • 四、总结
    • 总结

      一、装饰模式的定义和特点

      在软件开发过程中,有时想用一些现存的组件。这些组件可能只是完成了一些核心功能。但在不改变其结构的情况下,可以动态地扩展其功能。所有这些都可以釆用装饰器模式来实现。

      就像我们做菜,需要用到调料,菜,刀,火等一系列抽象的组件来最终完成一道菜。

      装饰模式的定义:

      指在不改变现有对象结构的情况下,动态地给该对象增加一些职责(即增加其额外功能)的模式,它属于对象结构型模式。就增加功能来说,装饰模式比生成子类更加灵活。

      特点:

      装饰器是继承的有力补充,比继承灵活,在不改变原有对象的情况下,动态的给一个对象扩展功能,即插即用
      通过使用不用装饰类及这些装饰类的排列组合,可以实现不同效果
       装饰器模式完全遵守开闭原则

      缺点

       装饰器模式会增加许多子类,过度使用会增加程序得复杂性。

      二、装饰模式的结构

      装饰模式的结构一般包含以下几个角色

      1. 抽象构件(Component)角色:定义一个抽象接口以规范准备接收附加责任的对象。
      2. 具体构件(ConcreteComponent)角色:实现抽象构件,通过装饰角色为其添加一些职责。
      3. 抽象装饰(Decorator)角色:继承抽象构件,并包含具体构件的实例,可以通过其子类扩展具体构件的功能。
      4. 具体装饰(ConcreteDecorator)角色:实现抽象装饰的相关方法,并给具体构件对象添加附加的责任。

      图示

      三、咖啡点单案例演示

      有一个需求,点一杯咖啡需要咖啡,材料等等,这个案例就很适合装饰模式,类似于穿衣,点餐,买包子,等等,我们怎么把他设计成装饰模式呢?

      看类图

      这个结构就是我已经设计好的一个装饰模式的类图,idea自动生成的,这里的Drink就是我们上面说的抽象构建角色,装饰者是Decorator,他是一个抽象装饰,下面他的子类就是具体的装饰者,那么具体构建中间我们提供了一个中间构建,提供了coffee的一些共性,可以放在这里,用的时候直接继承,他的下面就是相应的具体构件,具体被装饰者角色,装饰者与被装饰者共同继承自component抽象构件,需要用到装饰的就是我们点一杯咖啡,用装饰去包裹即可,层层包裹,案例如下:

      比如我要点一份加糖加奶的拿铁咖啡

      代码实例:

      component抽象构件角色:

      package com.decoratorPattern.starBucks;
       
      /**
       * @author wang
       * @version 1.0
       * @packageName com.decoratorPattern.starBucks
       * @className Drink
       * @date 2021/12/28 10:28
       * @Description 饮料构件类抽象component
       */
      public abstract class Drink {
          private String description;
          private float price = 0.0f;
       
          public String getDescription() {
              return description;
          }
       
          public void setDescription(String description) {
              this.description = description;
          }
       
          public float getPrice() {
              return price;
          }
       
          public void setPrice(float price) {
              this.price = price;
          }
       
          /**
           * @Date  2021/12/28 10:30
           * @Param
           * @Return float
           * @MetodName cost
           * @Author wang
           * @Description 计算花费,订单价格
           */
          public abstract float cost();
      }

      装饰者类:

      package com.decoratorPattern.starBucks;
       
      /**
       * @author wang
       * @version 1.0
       * @packageName com.decoratorPattern.starBucks
       * @className Decorator
       * @date 2021/12/28 10:40
       * @Description 装饰者定义类,配料
       */
      public class Decorator extends Drink {
       
          private Drink drink;
       
          /**
           * @param drink
           * @Date 2021/12/28 10:42
           * @Param
           * @Return null
           * @MetodName Decorator
           * @Author wang
           * @Description 传入一个被装饰者,由装饰者进行装饰
           */
          public Decorator(Drink drink) {
              this.drink = drink;
          }
       
          /**
           * @Date 2021/12/28 10:43
           * @Param
           * @Return float
           * @MetodName cost
           * @Author wang
           * @Description 装饰者的价格加上被装饰者的价格
           */
          @Override
          public float cost() {
              return super.getPrice() + drink.cost();
          }
       
          /**
           * @Date 2021/12/28 10:44
           * @Param
           * @Return String
           * @MetodName getDescription
           * @Author wang
           * @Description 输出订单信息,包含装饰者,装饰者的价格,以及被装饰者的信息
           */
          @Override
          public String getDescription() {
              return drink.getDescription() + "\n加入的材料:" + super.getDescription()
                      + "\t材料价格:" + super.getPrice() ;
          }
      }

      装饰者类:

      package com.decoratorPattern.starBucks;
       
      /**
       * @author wang
       * @version 1.0
       * @packageName com.decoratorPattern.starBucks
       * @className Decorator
       * @date 2021/12/28 10:40
       * @Description 装饰者定义类,配料
       */
      public class Decorator extends Drink {
       
          private Drink drink;
       
          /**
           * @param drink
           * @Date 2021/12/28 10:42
           * @Param
           * @Return null
           * @MetodName Decorator
           * @Author wang
           * @Description 传入一个被装饰者,由装饰者进行装饰
           */
          public Decorator(Drink drink) {
              this.drink = drink;
          }
       
          /**
           * @Date 2021/12/28 10:43
           * @Param
           * @Return float
           * @MetodName cost
           * @Author wang
           * @Description 装饰者的价格加上被装饰者的价格
           */
          @Override
          public float cost() {
              return super.getPrice() + drink.cost();
          }
       
          /**
           * @Date 2021/12/28 10:44
           * @Param
           * @Return String
           * @MetodName getDescription
           * @Author wang
           * @Description 输出订单信息,包含装饰者,装饰者的价格,以及被装饰者的信息
           */
          @Override
          public String getDescription() {
              return drink.getDescription() + "\n加入的材料:" + super.getDescription()
                      + "\t材料价格:" + super.getPrice() ;
          }
      }

      具体构件类:拿铁

      package com.decoratorPattern.starBucks;
       
      /**
       * @author wang
       * @version 1.0
       * @packageName com.decoratorPattern.starBucks
       * @className latte
       * @date 2021/12/28 10:32
       * @Description 拿铁咖啡实类,被装饰者
       */
      public class Latte extends Coffee{
          public Latte() {
              setDescription("拿铁咖啡");
              setPrice(15.0f);
          }
      }

      具体构件类:摩卡

      package com.decoratorPattern.starBucks;
       
      /**
       * @author wang
       * @version 1.0
       * @packageName com.decoratorPattern.starBucks
       * @className Mocha
       * @date 2021/12/28 10:36
       * @Description 摩卡咖啡实类,被装饰者
       */
      public class Mocha extends Coffee {
          public Mocha() {
              setDescription("摩卡咖啡");
              setPrice(12.2f);
          }
      }

      其他同上,不过多展示

       具体装饰类:牛奶

      package com.decoratorPattern.starBucks;
       
      /**
       * @author wang
       * @version 1.0
       * @packageName com.decoratorPattern.starBucks
       * @className Milk
       * @date 2021/12/28 10:47
       * @Description 牛奶调味品,具体装饰者
       */
      public class Milk extends Decorator{
       
          /**
           * @param drink
           * @Date 2021/12/28 10:42
           * @Param
           * @Return null
           * @MetodName Decorator
           * @Author wang
           * @Description 传入一个被装饰者,由装饰者进行装饰
           */
          public Milk(Drink drink) {
              super(drink);
              setDescription("牛奶");
              setPrice(1.0f);
          }
      }

      具体装饰:糖

      package com.decoratorPattern.starBucks;
       
      /**
       * @author wang
       * @version 1.0
       * @packageName com.decoratorPattern.starBucks
       * @className sugar
       * @date 2021/12/28 10:50
       * @Description 糖,装饰者
       */
      public class Sugar extends Decorator{
          /**
           * @param drink
           * @Date 2021/12/28 10:42
           * @Param
           * @Return null
           * @MetodName Decorator
           * @Author wang
           * @Description 传入一个被装饰者,由装饰者进行装饰
           */
          public Sugar(Drink drink) {
              super(drink);
              setDescription("糖");
              setPrice(0.5f);
          }
      }

      订单测试代码:

      package com.decoratorPattern.starBucks;
       
      /**
       * @author wang
       * @version 1.0
       * @packageName com.decoratorPattern.starBucks
       * @className OrderTest
       * @date 2021/12/28 10:51
       * @Description 前台订单类
       */
      public class OrderTest {
          public static void main(String[] args) {
              //点一份加糖加奶的拿铁咖啡
       
              System.out.println("+++++++没加任何东西+++++++");
              Drink latte = new Latte();
              System.out.println("当前总价:" + latte.cost());
              System.out.println("coffee:" +latte.getDescription());
              //加糖
              System.out.println("+++++++加糖后+++++++");
              latte = new Sugar(latte);
              System.out.println("当前总价:" + latte.cost());
              System.out.println("coffee:" + latte.getDescription());
       
              System.out.println("+++++++加奶后+++++++");
              latte = new Milk(latte);
              System.out.println("当前总价:" + latte.cost());
              System.out.println("coffee:" +latte.getDescription());
          }
      }
      /**
       * +++++++没加任何东西+++++++
       * 当前总价:15.0
       * coffee:拿铁咖啡
       * +++++++加糖后+++++++
       * 当前总价:15.5
       * coffee:拿铁咖啡
       * 加入的材料:糖	材料价格:0.5
       * +++++++加奶后+++++++
       * 当前总价:16.5
       * coffee:拿铁咖啡
       * 加入的材料:糖	材料价格:0.5
       * 加入的材料:牛奶	材料价格:1.0
       *
       * Process finished with exit code 0
       */

      综上, 如果我们需要新的咖啡种类或者是新的调料,只需要新增类去继承coffee或者decorator类即可。

      四、总结

      装饰模式是为已有的功能动态的添加更多功能的一种方式,当系统需要新功能的时候,向旧的类中添加新的代码,这些新加的代码通常装饰了原有类的核心职责或主要行为。

      优点:

      把类中装饰功能从类中移除,这样可以简化原来的类,

      有效的把类的核心职责和装饰功能分开了,而且可以去除相关类中的重复装饰逻辑

      可代替继承。

      总结

      本篇文章就到这里了,希望能够给你带来帮助,也希望您能够多多关注3672js教程的更多内容!

      您可能感兴趣的文章:
      • Java设计模式之职责链模式详解
      • 深入理解Java设计模式之职责链模式
      • Java单例模式的深入了解
      • Java工厂模式的深入了解
      • Java代理模式的深入了解
      • Java观察者模式的深入了解
      • Java职责链模式的深入了解
      相关栏目:

      用户点评