一、定义
动态地给一个对象添加一些额外的职责。就增加功能来说,装饰器模式相比生成子类更为灵活。可以将新功能动态地附加于现有对象而不改变现有对象的功能。
装饰类和被装饰类可以独立发展,不会相互耦合。
二、模式结构
抽象构件(Component)角色: 定义一个抽象接口以规范准备接收附加责任的对象。——egg接口
具体构件(ConcreteComponent)角色: 实现抽象构件,通过装饰角色为其添加一些职责。——simpleEgg
抽象装饰(Decorator)角色: 继承抽象构件,并包含具体构件的实例,可以通过其子类扩展具体构件的功能。——eggDecorator
具体装饰(ConcreteDecorator)角色: 实现抽象装饰的相关方法,并给具体构件对象添加附加的责任。——卤蛋,茶叶蛋
比如我们做鸡蛋这道菜。包含egg这个接口(Component),白水煮蛋simpleEgg角色(ConcreteComponent),鸡蛋装饰类eggDecorator角色(Decorator),具体装饰角色:比如卤蛋、茶叶蛋等。
结构图如下:
装饰器模式在 Java 语言中的最著名的应用莫过于 Java I/O 标准库的设计了。例如,InputStream 的子类 FilterInputStream,OutputStream 的子类 FilterOutputStream,Reader 的子类 BufferedReader 以及 FilterReader,还有 Writer 的子类 BufferedWriter、FilterWriter 以及 PrintWriter 等,它们都是抽象装饰类。
三、代码详解
1、抽象构件(Component)角色
public interface Egg {
void cookEgg();
}
2、具体构件(ConcreteComponent)角色
public class SimpleEgg implements Egg {
@Override
public void cookEgg() {
System.out.println("我是白水煮蛋");
}
}
3、抽象装饰(Decorator)角色
同样实现Egg接口,定义一个Egg对象的引用,在构造器中进行初始化。并且将cookEgg()方法转发给被装饰对象。
public abstract class EggDecorator implements Egg {
private Egg egg;
public EggDecorator(Egg egg) {
this.egg = egg;
}
@Override
public void cookEgg() {
egg.cookEgg();
}
}
4、具体装饰(ConcreteDecorator)角色
cookEgg()方法中,可以在转发请求之前或者之后,增加功能。
卤蛋:
public class SpicedEggDecorator extends EggDecorator{
public SpicedEggDecorator(Egg egg) {
super(egg);
}
@Override
public void cookEgg(){
super.cookEgg();
addedFunction();
}
public void addedFunction() {
System.out.println("我本来是白水煮蛋,现在是一颗大卤蛋");
}
}
茶叶蛋:
public class TeaEggDecorator extends EggDecorator {
public TeaEggDecorator(Egg egg) {
super(egg);
}
@Override
public void cookEgg() {
super.cookEgg();
addedFunction();
}
public void addedFunction() {
System.out.println("我本来是白水煮蛋,现在是一颗茶叶蛋");
}
}
5、测试类
public static void main(String[] args) {
//具体的白水煮蛋对象
Egg egg = new SimpleEgg();
//卤蛋
EggDecorator eggDecoratorSpice = new SpicedEggDecorator(egg);
//茶叶蛋
EggDecorator eggDecoratorTea = new TeaEggDecorator(egg);
egg.cookEgg();
System.out.println("---------------");
eggDecoratorSpice.cookEgg();
System.out.println("---------------");
eggDecoratorTea.cookEgg();
}
运行结果如下:
我是白水煮蛋
---------------
我是白水煮蛋
我本来是白水煮蛋,现在是一颗大卤蛋
---------------
我是白水煮蛋
我本来是白水煮蛋,现在是一颗茶叶蛋
五、总结
从上面结构和代码可以看出,白水煮蛋和卤蛋还有茶叶蛋独立发展,不会相互耦合。
优点:
这里实际上我想起了建造者模式,可以参考java(面向对象)的23种设计模式(4)——原型模式&建造者模式做一下对比。
对于扩张一个对象的功能,装饰模式比继承模式更加灵活,不会导致类的数量急剧增加。
可以通过一种动态的方式扩张一个类的功能。
可以对一个对象进行多次装饰,通过使用不同的具体装饰类以及这些装饰类的排列组合可以创造不同的行为的组合。
缺点:
在使用装饰模式的时候进行系统设计时会产生很多小对象,这些对象的区别在于他们之间相互连接的方式有所不同,
而不是他们的类或者属性值有所不同,大量小对象势必产生一大部分的系统资源开销。影响系统性能。
装饰模式是一种比继承更加灵活的解决方案。但同时,也意味着比继承更加容易出错,更加难排查。