基本概念
装饰器模式(Decorator Pattern) 动态的将一个新的特性附加到一个对象上。属于结构性设计模式,如同快递一样一层一层的包裹一样,里面的商品就是被装饰对象Component,包装袋就是装饰器Decorator。
试想一下我们火锅调味料的场景,最基本的有香油,植物油,在基础调料上可以添加大蒜,盐,辣椒。。。
那么被装饰对象就是香油,大蒜,盐,辣椒都是装饰器,最终得到的调料里面就包含了所有的东西。
如果按传统的设计方法,香油,大蒜都抽成一个类独立维护在他们出现组合的时候就会出现香油大蒜组合,香油盐组合,香油大蒜盐组合,类就会直接爆炸无法维护。
UML
Decorator 中通过构造器传入一个Seasoning对象 复写了totalWeight 总重量的方法,改为获取上层的总重量加上本次添加的总量 形成递归操作
角色分析
- 被装饰主体抽象类 Component 最里层的被装饰对象顶级接口 抽象公共方法也可以没有
- 具体被装饰对象 ConcreteComponent
- 装饰器 Decorator
- 具体装饰器 ConcreteDecorator
代码展示
// 调味料顶级父类 Component
public abstract class Seasoning {
private String name;
private float weight;
public Seasoning(String name, float weight) {
this.name = name;
this.weight = weight;
}
public abstract float totalWeight();
public void display() {
System.out.println(this.getName() + this.totalWeight());
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public float getWeight() {
return weight;
}
public void setWeight(float weight) {
this.weight = weight;
}
}
// 植物油直接继承顶级父类 ConcreteComponent
public class PlantOil extends Seasoning {
public PlantOil(String name, float weight) {
super(name, weight);
}
@Override
public float totalWeight() {
return this.getWeight();
}
}
// 芝麻油直接继承顶级父类 ConcreteComponent
public class SesameOil extends Seasoning {
public SesameOil(String name, float weight) {
super(name, weight);
}
@Override
public float totalWeight() {
return this.getWeight();
}
}
// 装饰器抽象 Decorator
public abstract class Decorator extends Seasoning {
private Seasoning seasoning;
public Decorator(String name, float weight, Seasoning seasoning) {
super(name, weight);
this.seasoning = seasoning;
setName(seasoning.getName() + "+" + name);
}
@Override
public float totalWeight() {
return seasoning.totalWeight() + this.getWeight();
}
}
// 各种装饰调料 ConcreteDecorator
public class Salt extends Decorator {
public Salt(Seasoning seasoning) {
super("盐", 0.8f, seasoning);
}
}
public class Garlic extends Decorator {
public Garlic(Seasoning seasoning) {
super("大蒜",0.5f,seasoning);
}
}
public class Sugar extends Decorator {
public Sugar(Seasoning seasoning) {
super("糖", 0.5f, seasoning);
}
}
// 客户端调用形式
public class DecoratorTest {
public static void main(String[] args) {
//基础调料
SesameOil sesameOil = new SesameOil("芝麻油", 1.0f);
// 加一分盐
Salt salt = new Salt(sesameOil);
salt.display();
// 再加一份盐
Salt salt2 = new Salt(salt);
salt2.display();
// 加一分大蒜
Garlic garlic = new Garlic(salt2);
garlic.display();
// 加一点糖
Sugar sugar = new Sugar(garlic);
// 好了可以吃了
sugar.display();
}
}
使用细节
- 装饰器模式使得装饰类和被装饰类解耦,拓展性很强,可以动态的给对象添加一些属性,如JDK中的各种流 InputStream --> ObjectInputStream 等等都使用了装饰器模式
- 装饰器模式缺点在于会增加系统的复杂度,在调试的时候会大量的递归增加调试的难度