Java设计模式之装饰器模式

Java设计模式之装饰器模式

模式定义

装饰器模式允许向一个现有对象添加新的功能,同时又不改变其结构。装饰者可以在所委托被装饰者的行为之前或之后加上自己的行为,以达到自己的目的。

应用场景

需要为一个类动态的添加功能而又不想增加类型体系的时候。

模式角色

Component,抽象构件角色,I/O系统里由InputStream和OutputStream这两个抽象类来担任(注意:Component是用来定义真实对象和装饰对象间相同的接口的)。

ConcreteComponent,具体构件角色(真实对象),I/O系统里由FileInputStream、FileOutputStream等担任(它们要么实现了Component,要么继承了Component)。

Decorator,装饰角色,I/O系统里由FilterInputStream和FilterOutputStream担任,它持有一个Component的引用(具体指的是InputStream和OutputStream)。

ConcreteDecorator,具体装饰角色(Decorator直接子类),I/O系统里由BufferedInputStream或BufferedOutputStream等担任)

举个例子

汉堡女王开了一个汉堡店,主要买以下三种汉堡,这三种汉堡如下:

  • WhopperBurger,大汉堡,售价1美元
  • SubmarineSandwich,潜艇三明治,售价1.1美元
  • Sandwich,三明治,售价0.9美元

同时还提供以下调味品:

  • Cheese,奶酪,售价0.9美元
  • Beef,牛肉,售价1.6美元
  • Bacon,熏猪肉,售价1.5美元
  • Chicken,鸡肉,售价1.9美元
  • Lettuce,生菜,售价0.7美元

这部开始营业了,客人A点了份潜艇三明治,加牛肉;客人B点了份三明治,加奶酪;客人C点了份大汉堡,加鸡肉和生菜;客人D点了份大汉堡,加熏猪肉和奶酪,要记录点的都是什么,以及每个客人该付多少钱。

代码实现

抽象构件角色

该角色要提供以下功能:

  1. 记录客人点的是什么;
  2. 计算客人该付多少钱

抽象去一个接口Burger

package com.rainmonth.pattern.structural.decorator;

public interface Burger {
    // 获取食物描述
    public String getDescription();
    // 获取食物话费
    public float cost();
}
具体构件角色

大汉堡

WhopperBurger.java

package com.rainmonth.pattern.structural.decorator;

public class WhopperBurger implements Burger {

    public String getDescription() {
        return "whopper burger";
    }

    @Override
    public float cost() {
        return 1.0f;
    }
}

潜艇三明治

SubmarineSandwich.java

package com.rainmonth.pattern.structural.decorator;

public class SubmarineSandwich implements Burger {

    @Override
    public String getDescription() {
        return "submarine sandwich";
    }

    @Override
    public float cost() {
        return 1.10f;
    }

}

三明治

Sandwich.java

package com.rainmonth.pattern.structural.decorator;

public class Sandwich implements Burger {

    public String getDescription() {
        return "sandwich";
    }

    @Override
    public float cost() {
        return 0.9f;
    }

}
抽象装饰器角色

调味品类(装饰器基类)

CondimentDecorator.java

package com.rainmonth.pattern.structural.decorator;

public abstract class CondimentDecorator implements Burger {

    protected Burger burger;

    public CondimentDecorator(Burger burger) {
        this.burger = burger;
    }

}
具体装饰器角色

熏猪肉,Bacon.java

package com.rainmonth.pattern.structural.decorator;

public class Bacon extends CondimentDecorator {

   public Bacon(Burger burger) {
      super(burger);
   }

   @Override
   public String getDescription() {
      return burger.getDescription() + ", Bacon";
   }

   @Override
   public float cost() {
      return burger.cost() + 1.5f;
   }

}

牛肉,Beef.java

package com.rainmonth.pattern.structural.decorator;

public class Beef extends CondimentDecorator {

   public Beef(Burger burger) {
      super(burger);
   }

   @Override
   public String getDescription() {
      return burger.getDescription() + ", Beef";
   }

   @Override
   public float cost() {
      return burger.cost() + 1.6f;
   }

}

奶酪,Cheese.java

package com.rainmonth.pattern.structural.decorator;

public class Cheese extends CondimentDecorator {

   public Cheese(Burger burger) {
      super(burger);
   }

   @Override
   public String getDescription() {
      return burger.getDescription() + ", Cheese";
   }

   @Override
   public float cost() {
      return burger.cost() + 0.9f;
   }

}

鸡肉,Chicken.java

package com.rainmonth.pattern.structural.decorator;

public class Chicken extends CondimentDecorator {

   public Chicken(Burger burger) {
      super(burger);
   }

   @Override
   public String getDescription() {
      return burger.getDescription() + ", Chicken";
   }

   @Override
   public float cost() {
      return burger.cost() + 1.9f;
   }

}

生菜,Lettuce.java

package com.rainmonth.pattern.structural.decorator;

public class Lettuce extends CondimentDecorator {

   public Lettuce(Burger burger) {
      super(burger);
   }

   @Override
   public String getDescription() {
      return burger.getDescription() + ", Lettuce";
   }

   @Override
   public float cost() {
      return burger.cost() + 0.7f;
   }

}

模拟客户点餐

package com.rainmonth.pattern.structural.decorator;

public class BurgerQueen {

   public static void main(String[] args) {
      // 潜艇三明治,加牛肉
      Burger submarineSandwichBeef = new Beef(new SubmarineSandwich());
      System.out.println(submarineSandwichBeef.getDescription());
      System.out.println(submarineSandwichBeef.cost() + "\n");

      // 三明治,加奶酪
      Burger cheeseSandwich = new Cheese(new Sandwich());
      System.out.println(cheeseSandwich.getDescription());
      System.out.println(cheeseSandwich.cost() + "\n");

      // 大汉堡,加生菜和鸡肉
      Burger lettuceChickenWhopper = new Lettuce(new Chicken(new WhopperBurger()));
      System.out.println(lettuceChickenWhopper.getDescription());
      System.out.println(lettuceChickenWhopper.cost() + "\n");

      // 大汉堡,加熏猪肉和奶酪
      Burger baconCheeseWhopper = new Bacon(new Cheese(new WhopperBurger()));
      System.out.println(baconCheeseWhopper.getDescription());
      System.out.println(baconCheeseWhopper.cost() + "\n");
   }

}

输出如下

submarine sandwich, Beef
2.7

sandwich, Cheese
1.8

whopper, Chicken, Lettuce
3.6000001

whopper, Cheese, Bacon
3.4


Process finished with exit code 0

UML图

上面例子的简单版UML图如下:

Java设计模式之装饰器模式_第1张图片
带方法的UML图如下:
Java设计模式之装饰器模式_第2张图片

总结

从上面的例子及UML图,可以看出装饰器模式有如下优缺点:

优点

  1. 可以很好的扩展功能,具体表现就是可以随意的为一款主食(大汉堡、潜艇三明治、三明治)添加调味品(Bacon、Beef等)
  2. ConfidentDecorator和具体的Bacon、Beef等没有发生耦合

缺点

  1. 很明显,我要加多个调味品的话,就要新建多个对象(多个new),在一定程度上增加了对象使用的复杂行

你可能感兴趣的:(Java基础,java,java设计模式)