文 / vincentzh
原文连接:http://www.cnblogs.com/vincentzh/p/6057666.html
目录
1、概述
装饰器模式在不改变原类文件和使用继承的情况下,动态地扩展一个对象的功能。通常给一个对象添加功能,要么在类中直接进行修改,要么通过子类继承来扩展对象的功能,又或者使用装饰模式将相应的功能进行任意的组合,使功能的扩展变的具有灵活性和动态性。装饰模式是通过创建一个包装对象,也就是装饰来包裹真实的对象,给真实对象扩展包装对象所具有的功能。
2、目的
装饰器的目的是:通过装饰对象的任意组合,对真实对象进行功能包装,实现对象功能扩展的动态性、简便性、复用性、灵活性。
3、结构组成
装饰模式主要涉及到四个角色:抽象主题角色、具体主题角色、抽象装饰角色、具体装饰角色
抽象主题角色:抽象主题角色提供具体角色和抽象装饰角色共同实现的功能(基本功能方法),具体主题角色和抽象装饰角色都必须去实现抽象主题角色定义的方法;
具体主题角色:具体主题角色就是装饰模式中的真实对象类,实现抽象主题角色的方法(基本功能方法),通过具体装饰角色包装给该角色添加附加功能;
抽象装饰角色:所有装饰器的父类,实现了抽象主题角色的功能(主要是为了实现装饰器功能的复用,即具体的装饰器A可以装饰另外一个具体的装饰器B,因为装饰器类也是一个抽象主题角色),并持有一个抽象主题角色的对象,该对象其实就是被装饰的对象。如果不继承组件接口类,则只能为某个组件添加单一的功能,即装饰器对象不能在装饰其他的装饰器对象。
具体装饰角色:具体的装饰器类,实现具体要向被装饰对象添加的功能。用来装饰具体的组件对象或者另外一个具体的装饰器对象。
4、实现
抽象主题角色
1 package com.cnblogs.vincentzh.decoratormodel; 2 // 抽象主题角色 3 // 只定义基本功能方法 4 public interface Component 5 { 6 public void function(); 7 }
具体主题角色
1 package com.cnblogs.vincentzh.decoratormodel; 2 // 具体主题角色 3 public class ConcreteComponent implements Component 4 { 5 @Override 6 public void function() 7 { 8 baseFunction(); 9 } 10 11 public void baseFunction() 12 { 13 System.out.println("基础功能"); 14 } 15 }
抽象装饰角色
1 package com.cnblogs.vincentzh.decoratormodel; 2 // 抽象装饰角色 3 public class Decorator implements Component 4 { 5 private Component component; // 持有抽象主题的角色 6 7 public Decorator(Component component) 8 { 9 this.component = component; 10 } 11 12 @Override 13 public void function() 14 { 15 component.function(); 16 } 17 }
两个具体装饰角色
1 package com.cnblogs.vincentzh.decoratormodel; 2 // 具体装饰角色A 3 public class ConcreteDecoratorA extends Decorator 4 { 5 public ConcreteDecoratorA(Component component) 6 { 7 super(component); 8 } 9 10 @Override 11 public void function() 12 { 13 super.function(); 14 functionA(); 15 } 16 17 public void functionA() 18 { 19 System.out.println("附加功能A"); 20 } 21 }
package com.cnblogs.vincentzh.decoratormodel; // 具体装饰角色B public class ConcreteDecoratorB extends Decorator { public ConcreteDecoratorB(Component component) { super(component); } @Override public void function() { super.function(); functionB(); } public void functionB() { System.out.println("附加功能B"); } }
客户端
1 package com.cnblogs.vincentzh.decoratormodel; 2 // 客户端测试类 3 public class Client 4 { 5 public static void main(String[] args) 6 { 7 Component component = new ConcreteComponent(); 8 Component decoratorA = new ConcreteDecoratorA(component); 9 Component decoratorB = new ConcreteDecoratorB(decoratorA); 10 11 decoratorB.function(); 12 // 调用 decoratorB 的 function 方法时,会去先执行父类 Decorator 的 function 方法,而 13 // Decorator 中持有 Component 的对象引用(所有的被装饰类和装饰类都实现了Component), 14 // 会去调用传入 Component 引用对象的 function 方法,此处 decoratorB 执行时会先执行 15 // decoratorA 的方法,而 decoratorA 执行时 又会先去执行 component 的 function 方法,传 16 // 入的是哪个装饰器的或真实对象的引用就会去先执行引用对象下的方法,这也就是装饰器能够 17 // 随意组合的缘由所在。 18 } 19 }
执行结果
5、总结
Java 的 I/O 流中就是使用了装饰模式I/O流可以划分为节点流和过滤流。,
节点流:就是直接与输入/输出设备或者文件系统打交道的基本类,如:FileInputStream、FileOutputStream等;
过滤流:过滤过滤,就是对已有的输入/输出流进行相应的附加处理,如缓冲读/写(BufferedInputStream、BufferedOutputStream)等;
InputStream 和 OutputStream 是所有输入/输出流的父类,它就是装饰模式中所谓的抽象主题角色(Component);而属于节点流的类自然就是具体主题角色(ConcreteComponent),它们负责与硬件或文件系统交互,形成最基本的读写操作流;FilterInputStream 和 FilterrOutputStream 则是所有过滤流的父类,同时它也继承自 InputStream 和 OutputStream,对应上去就是抽象装饰角色(Decorator);剩下具体的过滤流就是具体装饰角色(ConcreteDecorator),它对负责基本功能的节点流进行包装添加功能,如:BufferInputStream 添加缓冲读取功能。
在 Hadoop 的编程模型中,MapReduce 用于 HDFS 文件数据读取的两个基本类 FSDataInputStream 和 FSDataOutputStream 也是继承自 Java 的 FilterInputStream 和 FilterOutputStream,那么这样来看,用于 HDFS 文件读/写的原理也是与一般文件读/写的原理并无差别,只是在原有的文件读/写基础上进行了分布式文件读取功能的添加。