定义

动态地将责任附加到对象上。若要扩展功能,装饰者提供了比继承更有弹性的替代方案。
8.装饰器模式 - 图1
结构:
1、Component,抽象构件
Component是一个接口或者抽象类,是定义我们最核心的对象,也可以说是最原始的对象,比如街边小吃;
2、ConcreteComponent,具体构件,或者基础构件
ConcreteComponent是最核心、最原始、最基本的接口或抽象类Component的实现,可以单独用,也可将其进行装饰,比如街边小吃最有名的手抓饼;
3、Decorator,装饰角色
 一般是一个抽象类,继承自或实现Component,在它的属性里面有一个变量指向Component抽象构件,我觉得这是装饰器最关键的地方。
4、ConcreteDecorator,具体装饰角色
ConcreteDecoratorA和ConcreteDecoratorB是两个具体的装饰类,它们可以把基础构件装饰成新的东西,比如把一个普通的手抓饼装饰成加蛋、加肠儿、金针菇的手抓饼。

优缺点

优点:

  • 装饰类和被装饰类可以独立发展,而不会相互耦合。换句话说,Component类无需知道Decorator类,Decorator类是从外部来扩展Component类的功能,而Decorator也不用知道具体的构件。
  • 装饰器模式是继承关系的一个替代方案。我们看装饰类Decorator,不管装饰多少层,返回的对象还是Component(因为Decorator本身就是继承自Component的),实现的还是is-a的关系。

    缺点:

  • 装饰器模式虽然减少了类的爆炸,但是在使用的时候,你就可能需要更多的对象来表示继承关系中的一个对象。

  • 装饰器模式虽然从数量级上减少了类的数量,但是为了要装饰,仍旧会增加很多的小类这些具体的装饰类的逻辑将不会非常的清晰,不够直观,容易令人迷惑。
  • 多层的装饰是比较复杂的。为什么会复杂?你想想看,就像剥洋葱一样,你剥到最后才发现是最里层的装饰出现了问题,可以想象一下工作量。

    适用场景

  1. 当你想要给一个类增加功能,然而,却并不想修改原来类的代码时,可以考虑装饰器模式如果你想要动态的给一个类增加功能,并且这个功能你还希望可以动态的撤销,就好像直接拿掉了一层装饰物;
  2. 比如java里面的基本数据类型int、boolean、char….都有它们对应的装饰类Integer、Boolean、Character….

    装饰器模式实现方法

    用蛋和烤肠去装饰手抓饼,让手抓饼更加美味!
    Component,抽象构件:街边小吃

    1. @Data
    2. public abstract class Snack {
    3. public String des; // 描述
    4. private float price = 0.0f;
    5. //计算费用的抽象方法
    6. //子类来实现
    7. public abstract float cost();
    8. }

    ConcreteComponent,具体构件,或者基础构件 ```java //手抓饼 public class HandGrabCake extends Snack { public HandGrabCake() {

    1. setPrice(5.0f);
    2. setDes(" 手抓饼 "+cost());

    }

    @Override public float cost() {

    1. return super.getPrice();

    } }


//烤冷面

public class GrilledColdNoodles extends Snack { public GrilledColdNoodles() { setPrice(4.0f); setDes(“ 烤冷面 “+cost()); } @Override public float cost() { return super.getPrice(); } }

  1. **Decorator,装饰角色**
  2. ```java
  3. public class Decorator extends Snack {
  4. private Snack obj;
  5. public Decorator(Snack obj) { //组合
  6. this.obj = obj;
  7. }
  8. @Override
  9. public float cost() {
  10. return super.getPrice() + obj.cost();
  11. }
  12. @Override
  13. public String getDes() {
  14. // obj.getDes() 输出被装饰者的信息
  15. return des + " " + getPrice() + " && " + obj.getDes();
  16. }
  17. }

具体装饰角色

  1. //鸡蛋
  2. public class Egg extends Decorator {
  3. public Egg(Snack obj) {
  4. super(obj);
  5. setDes(" 鸡蛋 ");
  6. setPrice(1.0f);
  7. }
  8. }
  9. -------------------------------------------------
  10. //烤肠
  11. public class Sausage extends Decorator {
  12. public Sausage(Snack obj) {
  13. super(obj);
  14. setDes(" 烤肠 ");
  15. setPrice(2.0f);
  16. }
  17. }
  18. ------------------------------------------------
  19. //金针菇
  20. public class NeedleMushroom extends Decorator{
  21. public NeedleMushroom(Snack obj) {
  22. super(obj);
  23. setDes(" 金针菇 ");
  24. setPrice(2.5f);
  25. }
  26. }

老板,来个手抓饼,加2个蛋、加1根烤肠

  1. public class HandGrabCakeBar {
  2. public static void main(String[] args) {
  3. // 装饰者模式下的订单:2个蛋+一根烤肠的手抓饼
  4. // 1. 点一份手抓饼
  5. Snack order = new HandGrabCake();
  6. System.out.println("小白手抓饼费用=" + order.cost());
  7. System.out.println("描述=" + order.getDes());
  8. // 2. order 加入一个鸡蛋
  9. order = new Egg(order);
  10. System.out.println("手抓饼 加入1个鸡蛋 费用 =" + order.cost());
  11. System.out.println("手抓饼 加入1个鸡蛋 描述 = " + order.getDes());
  12. // 3. order 加入一个鸡蛋
  13. order = new Egg(order);
  14. System.out.println("手抓饼 加入1个鸡蛋 加入2个鸡蛋 费用 =" + order.cost());
  15. System.out.println("手抓饼 加入1个鸡蛋 加入2个鸡蛋 描述 = " + order.getDes());
  16. // 3. order 加入一根烤肠
  17. order = new Sausage(order);
  18. System.out.println("手抓饼 加入1个鸡蛋 加入2个鸡蛋 加1根烤肠 费用 =" + order.cost());
  19. System.out.println("手抓饼 加入1个鸡蛋 加入2个鸡蛋 加1根烤肠 描述 = " + order.getDes());
  20. System.out.println("===========================");
  21. Snack order2 = new GrilledColdNoodles();
  22. System.out.println("考冷面 费用 =" + order2.cost());
  23. System.out.println("考冷面 描述 = " + order2.getDes());
  24. // 1. order2 加入一袋金针菇
  25. order2 = new NeedleMushroom(order2);
  26. System.out.println("考冷面 加入一袋金针菇 费用 =" + order2.cost());
  27. System.out.println("考冷面 加入一袋金针菇 描述 = " + order2.getDes());
  28. }
  29. }

8.装饰器模式 - 图2