定义
Decorator装饰器会动态地将责任附加到对象上。若要扩展功能,装饰者提供了比继承更有弹性的替代方案。
组成
- 抽象构件(Component):核心,是一个接口或抽象类。
- 具体构件(ConcreteComponent):Component的具体实现,需要被装饰的构建。
- 装饰者(Decorator):继承或者实现Component,在它的属性里面有一个变量指向Component抽象构件。
- 具体装饰者(ConcreteDecorator):可以把具体构件装饰成新的东西。
优缺点
优点:
- 装饰类和被装饰类可以独立发展,而不会相互耦合。
- 装饰器模式是继承关系的一个替代方案,但就增加功能来说,装饰模式相比生成子类更为灵活。
缺点:
- 为了要装饰,会增加很多的小类,这些具体的装饰类的逻辑将不会非常的清晰直观,容易令人迷惑。
- 如果进行了多层的装饰,排查错误时工作量会很大,需要一层一层的找下去。
使用场景
- 当我们需要在不影响其他类的状况下,以动态、透明的方式为类添加功能。
- 当不适合使用继承,又想进行方法扩展的时候。
示例
举一个手抓饼加菜的例子。
抽象构件(Component)
/**
* 街边小吃
*/
public abstract class Snack {
public String des; // 描述
private float price = 0.0f;
public String getDes() {
return des;
}
public void setDes(String des) {
this.des = des;
}
public float getPrice() {
return price;
}
public void setPrice(float price) {
this.price = price;
}
//计算费用的抽象方法
public abstract float cost();
}
基础构件(ConcreteComponent)
/**
* 手抓饼
*/
public class HandGrabCake extends Snack {
public HandGrabCake() {
setPrice(5.0f);
setDes("手抓饼(" + cost() + ")");
}
@Override
public float cost() {
//需要被装饰的构建,所以只需要输出自己的价格
return super.getPrice();
}
}
装饰者(Decorator)
/**
* 装饰者
*/
public class Decorator extends Snack {
private Snack obj;
public Decorator(Snack obj) { // 组合被装饰者的信息
this.obj = obj;
}
@Override
public float cost() {
// 输出装饰后的价格
return super.getPrice() + obj.cost();
}
@Override
public String getDes() {
// 输出装饰后的描述
return des + "(" + getPrice() + ")&&" + obj.getDes();
}
}
具体装饰者(ConcreteDecorator)
/**
* 鸡蛋
*/
public class Egg extends Decorator {
public Egg(Snack obj) {
super(obj);
setDes("鸡蛋");
setPrice(1.0f);
}
}
/**
* 烤肠
*/
public class Sausage extends Decorator {
public Sausage(Snack obj) {
super(obj);
setDes("烤肠");
setPrice(2.0f);
}
}
Main
public class Main {
public static void main(String[] args) {
// 1. 点一份手抓饼
Snack order = new HandGrabCake();
System.out.println(order.getDes() + "=" + order.cost() + "元。");
// 2. order 加入一个鸡蛋
order = new Egg(order);
System.out.println(order.getDes() + "=" + order.cost() + "元。");
// 3. order 加入一根烤肠
order = new Sausage(order);
System.out.println(order.getDes() + "=" + order.cost() + "元。");
}
}
-------输出结果----------
手抓饼(5.0)=5.0元。
鸡蛋(1.0)&&手抓饼(5.0)=6.0元。
烤肠(2.0)&&鸡蛋(1.0)&&手抓饼(5.0)=8.0元。