结构模式--之--装饰模式
装饰模式以对客户端透明的方式动态地给一个对象附加上更多的责任。客户端并不会觉得对象在装饰前和装饰后有什么不同。装饰模式可以在不使用创造更多子类的情况下,将对象的功能加以扩展。
主要有以下角色:
1.抽象构件(Component)角色:给出一个抽象接口,以规范准备接收附加责任的对象
2.具体构件(ConcreteComponent)角色:定义一个将要接收附加责任的类。
3.装饰(Decorator)角色:持有一个构件(Component)对象的实例,并定义一个与抽象构件接口一致的接口
4.具体装饰(Concrete Decorator)角色:负责给构件对象“贴上”附加的责任。
示例性代码:
1 public class DecoratorTest { 2 public static void main(String[] args) { 3 Decorator decorator = new Decorator(new ConcreteComponent()); 4 decorator.Hello(); 5 } 6 } 7 8 9 //抽象构件角色 10 interface Component{ 11 public void Hello(); 12 } 13 14 //装饰角色,也可能是抽象类 15 class Decorator implements Component{ 16 //持有构件角色 17 private Component componet; 18 19 public Decorator(Component component){ 20 this.componet = component; 21 } 22 23 public Decorator(){} 24 25 //把方法委派给构件去做 26 @Override 27 public void Hello() { 28 componet.Hello(); 29 } 30 31 } 32 33 //具体构件类角色 34 class ConcreteComponent implements Component{ 35 public ConcreteComponent(){} 36 37 @Override 38 public void Hello() { 39 System.out.println("Hello,world"); 40 } 41 42 } 43 44 //具体装饰类 45 class ConcreteDecorator extends Decorator{ 46 47 @Override 48 public void Hello(){ 49 super.Hello(); 50 } 51 }
装饰模式在什么情况下使用?
1.需要扩展一个类的功能,或给一个类增加附加责任
2.需要动态地给一个对象增加功能,这些功能可以再动态地撤销
3.需要增加由一些基本功能的排列组合而产生的非常大量的功能,从而使继承关系变得不现实。
使用装饰模式的优点:
1.装饰模式与继承关系的目的都是扩展对象的功能,但是装饰模式可以提供比继承更多的灵活性
装饰模式允许系统动态地决定“贴上”一个需要的“装饰”,或者除掉一个不需要的“装饰”。继承关系则不同,继承关系是静态的,它在系统运行前就决定了。
2.通过使用不同的具体装饰类以及这些装饰类的排列组合,设计师可以创造出很多不同行为的组合。
3.这种比类继承更加灵活机动的特性,也同时意味着装饰模式比继承更加易于出错。
使用装饰模式的缺点:
1.由于使用装饰模式,可以比使用类继承关系需要较少数的类。使用较少的类,当然使设计比较易于进行。但是,在另一方面,使用装饰模式会产生比使用类继承关系更多的对象。更多的对象会使得查错变得困难,特别是这些对象看上去都很相像。
对比javaIO中输出流中使用装饰模式:
1.抽象构件角色:由OutputStream扮演。这是一个抽象类,为各种的子类型流处理器提供统一接口
2.具体构件(Concrete Component)角色:由ByteArrayOutputStream,FileOutputStream以及PipedOutputStream等扮演,它们均实现了OutputStream所声明的接口
3.抽象装饰(Decoratro)角色:由FilterOutputStream扮演,它有与OutputStream相同的接口,而这正是装饰类的关键
4.具体装饰(Concrete Decorator)角色:由几个类扮演,分别是BufferedOutputStream,DataOutputStream.以及PrintStream.
装饰模式和适配器模式都是“包裹模式(Wrapper Pattern)”它们都是通过封装其他对象达到设计目的,但是它们的形态有很大的区别。
理想的装饰模式在对装饰对象进行功能增强的同时,要求具体构件角色,装饰角色的接口与抽象构件角色的接口完全一致。而适配器模式则不然,一般而言,适配器模式并不要求对源对象的功能进行增强,但是会改变源对象的接口,以便和目标接口相符合。如果装饰角色的接口与抽象构件角色的接口不一致,也就是说装饰角色的接口比抽象构件角色的接口宽的话,装饰角色实际上已经成了一个适配器角色,这种装饰模式称为“半透明”装饰模式。
一个关于装饰模式的重要的事实是,很难找到理想的装饰模式。一般而言,对一个对象进行功能增加,都会导致加入新的行为。因此,装饰角色的接口比抽象构件角色的接口宽是很难避免的。这种现象存在于Java I/O库中所有的类型的链接流处理器中。一个装饰类提供的新的方法越多,它离纯装饰模式的距离也就越远,离适配器模式就距离也就越近。