设计模式(七)--装饰器模式
装饰器模式的目的有三个:
1,不改变原类文件。
2,不使用继承。
3,动态扩展。
上述三句话一语道出了装饰器模式的特点,下面LZ给出装饰器模式的类图,先上图再解释。
从图中可以看到,我们装饰的是一个接口的任何实现类,而这些实现类也包括了装饰器本身。
另外,这个类图只是装饰器模式的完整结构,但其实里面有很多可以变化的地方,LZ给出如下两条。
1,Component接口可以是接口也可以是抽象类,甚至是一个普通的父类(这个强烈不推荐,普通的类作为继承体系的超级父类不易于维护)。
2,装饰器的抽象父类Decorator并不是必须的。
那么我们将上述标准的装饰器模式,用我们熟悉的JAVA代码诠释一下。首先是带装饰的接口Component。
package com.decorator; public class ConcreteComponent implements Component{ public void method() { System.out.println("原来的方法"); } }
下面便是我们的抽象装饰器父类,它主要是为装饰器定义了我们需要装饰的目标是什么,并对Component进行了基础的装饰。
package com.decorator; public abstract class Decorator implements Component{ protected Component component; public Decorator(Component component) { super(); this.component = component; } public void method() { component.method(); } }
再来就是我们具体的装饰器A和装饰器B。
package com.decorator; public class ConcreteDecoratorA extends Decorator{ public ConcreteDecoratorA(Component component) { super(component); } public void methodA(){ System.out.println("被装饰器A扩展的功能"); } public void method(){ System.out.println("针对该方法加一层A包装"); super.method(); System.out.println("A包装结束"); } }
package com.decorator; public class ConcreteDecoratorB extends Decorator{ public ConcreteDecoratorB(Component component) { super(component); } public void methodB(){ System.out.println("被装饰器B扩展的功能"); } public void method(){ System.out.println("针对该方法加一层B包装"); super.method(); System.out.println("B包装结束"); } }
下面给出我们的测试类。我们针对多种情况进行包装。
package com.decorator; public class Main { public static void main(String[] args) { Component component =new ConcreteComponent();//原来的对象 System.out.println("------------------------------"); component.method();//原来的方法 ConcreteDecoratorA concreteDecoratorA = new ConcreteDecoratorA(component);//装饰成A System.out.println("------------------------------"); concreteDecoratorA.method();//原来的方法 concreteDecoratorA.methodA();//装饰成A以后新增的方法 ConcreteDecoratorB concreteDecoratorB = new ConcreteDecoratorB(component);//装饰成B System.out.println("------------------------------"); concreteDecoratorB.method();//原来的方法 concreteDecoratorB.methodB();//装饰成B以后新增的方法 concreteDecoratorB = new ConcreteDecoratorB(concreteDecoratorA);//装饰成A以后再装饰成B System.out.println("------------------------------"); concreteDecoratorB.method();//原来的方法 concreteDecoratorB.methodB();//装饰成B以后新增的方法 } }
由此可以看到,我们首先是使用的原始的类的方法,然后分别让A和B装饰完以后再调用,最后我们将两个装饰器一起使用,再调用该接口定义的方法。
装饰器模式就是一个可以非常灵活的动态扩展类功能的设计模式,它采用组合的方式取代继承,使得各个功能的扩展更加独立和灵活。
在上一篇介绍适配器模式的时候,提到过对象适配器也是采用组合替代继承的方式,也是给原对象增加新的特性,那它们有什么区别吗?
对于适配器模式中的定制适配器与装饰器模式,二者都是使用组合加继承的手段,不同的是,适配器模式的目的在于适配接口,装饰器模式的目的在于动态的添加功能,且可以叠加。