装饰者模式
定义
Attach additional responsibilities to an object dynamically keeping the same interface.Decorators provide a flexible alternative to subclassing for extending functionality.
动态地给一个对象添加一些额外的职责。就增加功能来说,装饰模式相比生成子类更为灵活。
类图
图片来自百度百科
角色结构
Component抽象构件:是一个接口或者是抽象类,就是定义我们最核心的对象,也就是最原始的对象。
ConcreteComponent具体构件:是最核心、最原始、最基本的接口或抽象类的实现,你要装饰的就是它。
Decorator装饰角色:一般是一个抽象类,做什么用呢?实现接口或者抽象方法,它里面可不一定有抽象的方法呀,在它的属性里必然有一个private变量指向Component抽象构件。
具体装饰角色:ConcreteDecoratorA和ConcreteDecoratorB是两个具体的装饰类,你要把你最核心的、最原始的、最基本的东西装饰成其他东西。
实例
现在很多人都喜欢喝奶茶,每天一杯有益身心健康(主要是心和嘴)。当我们在喝奶茶的时候,服务员总会问”要加什么?”,这跟每天的终极难题–吃什么–是一样,今天暂且不谈。而供选择的材料可能有波霸椰果布丁等,加了椰果的奶茶最后就被标为椰果奶茶售卖。今天就用买奶茶作为装饰者模式的例子。
- 首先创建一个制作奶茶的原料抽象类
Material
。
public abstract class Material {
/**
* 该奶茶原料的名字
*/
private String name;
/**
* 获取已加入的原料
*/
public String getFullName() {
return this.name;
}
/**
* 费用
*/
public abstract double cost();
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
- 然后创建配料抽象类
Burden
,继承于原谅抽象类。
public abstract class Burden extends Material {
/**
* 配料类需要持有一个被修饰类,即奶茶
*/
private Material material;
/**
* 配料类需要重写获取全部原料的方法,为了获得完成的原料
* @return
*/
public abstract String getFullName();
public Material getMaterial() {
return material;
}
public void setMaterial(Material material) {
this.material = material;
}
}
- 分别创建具体的原料和配料
public class MilkTea extends Material {
public MilkTea() {
this.setName("奶茶");
}
@Override
public double cost() {
return 5;
}
}
public class Pudding extends Burden {
public Pudding(Material material) {
this.setMaterial(material);
}
@Override
public String getFullName() {
return this.getMaterial().getFullName() + " + 布丁";
}
@Override
public double cost() {
return 2 + this.getMaterial().cost();
}
}
- 创建测试类
public class Test {
public static void main(String[] args) {
// 买一杯奶茶,不加任何配料
Material milkTea = new MilkTea();
System.out.println("奶茶费用 = " + milkTea.cost());
// 买一被加椰果的奶茶
Material milkTeaWithCoCo = new MilkTea();
milkTeaWithCoCo = new NataDeCoco(milkTeaWithCoCo);
System.out.println("椰果奶茶费用 = " + milkTeaWithCoCo.cost());
// 买一被加布丁的玛奇朵
Material MacchiatoWithPudding = new Macchiato();
MacchiatoWithPudding = new Pudding(MacchiatoWithPudding);
System.out.println("布丁玛奇朵费用 = " + MacchiatoWithPudding.cost());
}
}
- 测试结果为
奶茶费用 = 5.0
椰果奶茶费用 = 6.0
布丁玛奇朵费用 = 12.0
装饰者模式的优缺点
优点
- 在不影响其他对象的情况下,动态为单个对象新增功能。
- 装饰类与被装饰类 (ConcreteComponent) 相互独立,互不耦合,易于扩展。
- 代替继承方式的功能实现,减少继承类的存在。
缺点
- 多层的装饰是比较复杂的,且不容易理解,参照Java的IO类。
使用场景
- 需要扩展一个类的功能,或给一个类增加附加功能。
- 需要动态地给一个对象增加功能,这些功能可以再动态地撤销。
- 需要为一批的兄弟类进行改装或加装功能,当然是首选装饰模式。
源代码
版权声明:本文为Planeswalker23所创,转载请带上原文链接,感谢。
文档信息
- 本文作者:Planeswalker23
- 本文链接:https://planeswalker23.github.io/2019/08/31/decorator/
- 版权声明:本作品系原创,作者保留所有权利,未经作者允许,禁止转载和演绎。