装饰器模式允许向一个现有对象添加新的功能,同时又不改变其结构。装饰者可以在所委托被装饰者的行为之前或之后加上自己的行为,以达到自己的目的。
需要为一个类动态的添加功能而又不想增加类型体系的时候。
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点了份大汉堡,加熏猪肉和奶酪,要记录点的都是什么,以及每个客人该付多少钱。
该角色要提供以下功能:
抽象去一个接口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图,可以看出装饰器模式有如下优缺点: