1. 为什么要有装饰器模式
假设有一个蛋糕店,店里有一种奶油蛋糕,售价100块。但是,通常顾客会有各种其他的需求,比如加草莓,加蓝莓等等,这时我们怎么办呢?你也许会说,可以多做几种类型的蛋糕,不就满足需求了,但是如果哪天又有新的客人有新的需求,按照这种方式我们要提供多少种分别计价呢,老板会不会疯掉呢。
这种单纯的设置新的种类像不像通过继承实现新的子类呢,光实现这些子类就会是一项很大的开发工作量,如果以后出现维护问题,那简直就是灾难。
这时我们是不是可以通过别的方法,以奶油蛋糕为主体,其他草莓,蓝莓类的材料作为装饰单独计价,这样每次顾客有新需求,只需在蛋糕的基础上加上材料的价格即可:

2. 装饰器模式UML图

2.1 角色
- Component:统一接口,也是装饰类和被装饰类的基本类型。
- ConcreteComponent:具体实现类,也是被装饰类,他本身是一个具有一定功能的完整的类。
- Decorator: 实现了Component接口的同时还在内部维护了ConcreteComponent的实例,并可以通过构造函数初始化,而Decorator本身,通常采用默认实现,他的存在仅仅是一个生命,要生产出一些用于装饰的子类,而其子类才是富有装饰效果的装饰产品类。
- ConcreteDecorator:具体的装饰产品类,每一种装饰产品具有特定的装饰效果,可以通过构造器生命装饰那种类型的ConcreteComponent,从而对其进行装饰。
3. 代码实战
先定一个Cake(Component)
public abstract class Cake {
public abstract int cost();
}
实现Cake,做一个奶油蛋糕
public class CreamCake extends Cake {
@Override
public int cost() {
return 100;
}
}
定义一个装饰器接口
public abstract class Decorator extends Cake {
private Cake cake = null;
public Decorator(Cake cake) {
this.cake = cake;
}
@Override
public int cost() {
return this.cake.cost();
}
}
加草莓
public class StrawberryCake extends Decorator {
public StrawberryCake(Cake cake) {
super(cake);
}
@Override
public int cost() {
return super.cost() + 20;
}
}
加蓝莓
public class BlueberryCake extends Decorator {
public BlueberryCake(Cake cake) {
super(cake);
}
@Override
public int cost() {
return super.cost() + 10;
}
}
测试
public class Demo {
public static void main(String[] args) {
// 做一个奶油蛋糕
Cake cake = new CreamCake();
// 加草莓
cake = new StrawberryCake(cake);
// 加蓝莓
cake = new BlueberryCake(cake);
System.out.println(cake.cost());
}
}
输出
130