定义
动态地将责任附加到对象上。若要扩展功能,装饰者提供了比继承更有弹性的替代方案。
结构:
1、Component,抽象构件
Component是一个接口或者抽象类,是定义我们最核心的对象,也可以说是最原始的对象,比如街边小吃;
2、ConcreteComponent,具体构件,或者基础构件
ConcreteComponent是最核心、最原始、最基本的接口或抽象类Component的实现,可以单独用,也可将其进行装饰,比如街边小吃最有名的手抓饼;
3、Decorator,装饰角色
一般是一个抽象类,继承自或实现Component,在它的属性里面有一个变量指向Component抽象构件,我觉得这是装饰器最关键的地方。
4、ConcreteDecorator,具体装饰角色
ConcreteDecoratorA和ConcreteDecoratorB是两个具体的装饰类,它们可以把基础构件装饰成新的东西,比如把一个普通的手抓饼装饰成加蛋、加肠儿、金针菇的手抓饼。
优缺点
优点:
- 装饰类和被装饰类可以独立发展,而不会相互耦合。换句话说,Component类无需知道Decorator类,Decorator类是从外部来扩展Component类的功能,而Decorator也不用知道具体的构件。
装饰器模式是继承关系的一个替代方案。我们看装饰类Decorator,不管装饰多少层,返回的对象还是Component(因为Decorator本身就是继承自Component的),实现的还是is-a的关系。
缺点:
装饰器模式虽然减少了类的爆炸,但是在使用的时候,你就可能需要更多的对象来表示继承关系中的一个对象。
- 装饰器模式虽然从数量级上减少了类的数量,但是为了要装饰,仍旧会增加很多的小类这些具体的装饰类的逻辑将不会非常的清晰,不够直观,容易令人迷惑。
- 多层的装饰是比较复杂的。为什么会复杂?你想想看,就像剥洋葱一样,你剥到最后才发现是最里层的装饰出现了问题,可以想象一下工作量。
适用场景
- 当你想要给一个类增加功能,然而,却并不想修改原来类的代码时,可以考虑装饰器模式如果你想要动态的给一个类增加功能,并且这个功能你还希望可以动态的撤销,就好像直接拿掉了一层装饰物;
比如java里面的基本数据类型int、boolean、char….都有它们对应的装饰类Integer、Boolean、Character….
装饰器模式实现方法
用蛋和烤肠去装饰手抓饼,让手抓饼更加美味!
Component,抽象构件:街边小吃@Data
public abstract class Snack {
public String des; // 描述
private float price = 0.0f;
//计算费用的抽象方法
//子类来实现
public abstract float cost();
}
ConcreteComponent,具体构件,或者基础构件 ```java //手抓饼 public class HandGrabCake extends Snack { public HandGrabCake() {
setPrice(5.0f);
setDes(" 手抓饼 "+cost());
}
@Override public float cost() {
return super.getPrice();
} }
//烤冷面
public class GrilledColdNoodles extends Snack { public GrilledColdNoodles() { setPrice(4.0f); setDes(“ 烤冷面 “+cost()); } @Override public float cost() { return super.getPrice(); } }
**Decorator,装饰角色**
```java
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() {
// obj.getDes() 输出被装饰者的信息
return des + " " + getPrice() + " && " + obj.getDes();
}
}
具体装饰角色
//鸡蛋
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);
}
}
------------------------------------------------
//金针菇
public class NeedleMushroom extends Decorator{
public NeedleMushroom(Snack obj) {
super(obj);
setDes(" 金针菇 ");
setPrice(2.5f);
}
}
老板,来个手抓饼,加2个蛋、加1根烤肠
public class HandGrabCakeBar {
public static void main(String[] args) {
// 装饰者模式下的订单:2个蛋+一根烤肠的手抓饼
// 1. 点一份手抓饼
Snack order = new HandGrabCake();
System.out.println("小白手抓饼费用=" + order.cost());
System.out.println("描述=" + order.getDes());
// 2. order 加入一个鸡蛋
order = new Egg(order);
System.out.println("手抓饼 加入1个鸡蛋 费用 =" + order.cost());
System.out.println("手抓饼 加入1个鸡蛋 描述 = " + order.getDes());
// 3. order 加入一个鸡蛋
order = new Egg(order);
System.out.println("手抓饼 加入1个鸡蛋 加入2个鸡蛋 费用 =" + order.cost());
System.out.println("手抓饼 加入1个鸡蛋 加入2个鸡蛋 描述 = " + order.getDes());
// 3. order 加入一根烤肠
order = new Sausage(order);
System.out.println("手抓饼 加入1个鸡蛋 加入2个鸡蛋 加1根烤肠 费用 =" + order.cost());
System.out.println("手抓饼 加入1个鸡蛋 加入2个鸡蛋 加1根烤肠 描述 = " + order.getDes());
System.out.println("===========================");
Snack order2 = new GrilledColdNoodles();
System.out.println("考冷面 费用 =" + order2.cost());
System.out.println("考冷面 描述 = " + order2.getDes());
// 1. order2 加入一袋金针菇
order2 = new NeedleMushroom(order2);
System.out.println("考冷面 加入一袋金针菇 费用 =" + order2.cost());
System.out.println("考冷面 加入一袋金针菇 描述 = " + order2.getDes());
}
}