装饰器模式对于笔者来说,印象还是比较深刻的。因为当年笔者考软件设计师的设计模式大题考的就是这个模式,差点阵亡。
附链
你也可以在这些平台阅读本文:
定义
动态地为一个对象添加一些额外的职责。
在扩展原有对象功能上,装饰器模式比继承的方式更加灵活。
模式中的角色
- 抽象构建(Component):定义一个抽象接口(可以是抽象类),用以给对象动态地添加职责。
- 具体构建(ConcreteComponent):定义一个具体的对象,实现Component接口。
- 抽象装饰者(Decorator):继承Component,用有Component的职责,同时也可以扩展职责。
- 具体装饰者(ConcretorDecorator):负责给具体的构建对象添加职责,同时可以定义额外的职责。
场景示例
笔者作为一点点的重度爱好者,这里就以奶茶为例。
创建抽象构建
/**
* @author zhh
* @description 抽象奶茶类
* @date 2020-02-13 23:30
*/
public abstract class AbstractMilkyTea {
/**
* 描述
*/
protected abstract String desc();
/**
* 价格
*/
protected abstract int price();
}
创建具体构建
/**
* @author zhh
* @description 具体奶茶类
* @date 2020-02-13 23:35
*/
public class MilkyTea extends AbstractMilkyTea {
@Override
protected String desc() {
return "奶茶";
}
@Override
protected int price() {
return 7;
}
}
创建抽象装饰者
/**
* @author zhh
* @description 抽象装饰者类
* @date 2020-02-13 23:37
*/
public abstract class AbstractDecorator extends AbstractMilkyTea {
private AbstractMilkyTea abstractMilkyTea;
public AbstractDecorator(AbstractMilkyTea abstractMilkyTea) {
this.abstractMilkyTea = abstractMilkyTea;
}
@Override
protected String desc() {
return this.abstractMilkyTea.desc();
}
@Override
protected int price() {
return this.abstractMilkyTea.price();
}
}
这里抽象装饰者继承了抽象奶茶类。
这个时候,具体奶茶类和抽象装饰者类都作为抽象奶茶类的子类。
我们可以通过具体奶茶类和抽象装饰者类继承的父类(抽象奶茶类)进行组合让这两个子类建立关系。
创建具体装饰者
/**
* @author zhh
* @description 糖装饰者
* @date 2020-02-13 23:58
*/
public class SugarDecorator extends AbstractDecorator {
public SugarDecorator(AbstractMilkyTea abstractMilkyTea) {
super(abstractMilkyTea);
}
@Override
protected String desc() {
return super.desc() + " 加糖";
}
@Override
protected int price() {
return super.price() + 1;
}
}
/**
* @author zhh
* @description 红豆装饰者
* @date 2020-02-14 00:14
*/
public class RedBeanDecorator extends AbstractDecorator {
public RedBeanDecorator(AbstractMilkyTea abstractMilkyTea) {
super(abstractMilkyTea);
}
@Override
protected String desc() {
return super.desc() + " 加红豆";
}
@Override
protected int price() {
return super.price() + 2;
}
}
/**
* @author zhh
* @description 珍珠装饰者
* @date 2020-02-13 23:56
*/
public class PearlDecorator extends AbstractDecorator {
public PearlDecorator(AbstractMilkyTea abstractMilkyTea) {
super(abstractMilkyTea);
}
@Override
protected String desc() {
return super.desc() + " 加珍珠";
}
@Override
protected int price() {
return super.price() + 2;
}
}
测试类及输出
/**
* @author zhh
* @description 测试类
* @date 2020-02-14 00:21
*/
public class Test {
public static void main(String[] args) {
AbstractMilkyTea abstractMilkyTea = new MilkyTea();
abstractMilkyTea = new SugarDecorator(abstractMilkyTea);
abstractMilkyTea = new PearlDecorator(abstractMilkyTea);
System.out.println(abstractMilkyTea.desc() + " 的销售价格是:" + abstractMilkyTea.price());
abstractMilkyTea = new MilkyTea();
abstractMilkyTea = new RedBeanDecorator(abstractMilkyTea);
abstractMilkyTea = new PearlDecorator(abstractMilkyTea);
System.out.println(abstractMilkyTea.desc() + " 的销售价格是:" + abstractMilkyTea.price());
}
}
测试类输出的结果如下:
奶茶 加糖 加珍珠 的销售价格是:10
奶茶 加红豆 加珍珠 的销售价格是:11
类结构图
以上示例类的结构图如下所示
总结
适用场景
- 给一个类添加额外的职责
- 动态的为一个对象添加功能同时可以动态撤销
优点
- 比继承更加灵活,易扩展。可以在不改变原有对象的情况下给一个对象扩展功能。
- 解耦。装饰类和被装饰者可以独立变化,不会相互耦合。
缺点
会导致代码和类的骤增,增加程序复杂性。
参考
- 《Head First 设计模式》
- 《大话设计模式》
- 维基百科-修饰模式
- 菜鸟教程-装饰器模式