一、定义
装饰器模式又叫做包装模式(Wrapper)。装饰器模式以对客户端透明的方式扩展对象的功能,是继承关系的一个替代方案。
在以下情况下应该使用装饰器模式:
1.需要扩展一个类的功能,或给一个类增加附加责任
2.需要动态的给一个对象增加功能,这些功能可以再动态的撤销
3.需要增加由一些基本功能的排列组合而产生的非常大量的功能,从而使其继承关系变的不现实。
二、类图
装饰器模式中的角色有:
- 抽象组件角色:给出一个抽象接口,一规范准备接收附加责任的对象
- 具体组件角色:定义一个将要接收附加责任的类
- 装饰角色:持有一个组件对象的实例,并定义一个一个与抽象组件接口一致的接口。
- 具体装饰角色:负责给组件对象"贴上去"附加的责任。
将类图转换为代码,如下所示。
/** * 装饰者通过对被装饰者进行装饰,从而使得自己拥有的加强的行为 * * @author lp * */ public class Client { public static void main(String[] args) { // 被装饰者 Component component = new ConcreteComponent(); // 装饰者 Decorator decorator = new ConcreteDecorator(component); // 被装饰者的行为 component.operation(); // 装饰者既具有被装饰者的行为,也有增加的行为。即对被装饰者进行了装饰。 decorator.operation(); decorator.addedBehavior(); } } /** * 抽象的被装饰者 */ interface Component { void operation(); } /** * 具体的被装饰者 */ class ConcreteComponent implements Component{ @Override public void operation() { System.out.println("被装饰者的操作"); } } /** * 抽象的装饰者 */ interface Decorator extends Component{ /** * 增加的方法 */ void addedBehavior(); } /** * 具体的装饰者 */ public class ConcreteDecorator implements Decorator { // 持有被装饰者的引用 private Component decoratedComponent; // 通过构造器将被装饰者传进来 public ConcreteDecorator(Component decoratedComponent) { this.decoratedComponent = decoratedComponent; } @Override public void operation() { System.out.println("decorated operation!"); decoratedComponent.operation(); } /** * 添加的功能 */ @Override public void addedBehavior() { System.out.println("addedBehaviour!"); } }
应该指出:
- 装饰类中,有一个私有的属性component,其数据类型是组件(Component)
- 该装饰器类实现了Component接口
- 接口的实现方法也值得注意,每一个实现的方法都委派给父类,但并不单纯的委派,而是有功能的增强。
三、JDK中的装饰器模式
JDK中的部分流的实现就使用了装饰器模式,比如BufferedInputStream对InputStream进行了装饰,BufferedReader对Reader进行了装饰,对应的OutputStream和Write也分别被BufferedOutputStream和BufferedWriter装饰了。
下面以BufferedInputStream为例,来分析一下装饰者模式。
/*抽象组件角色*/ public abstract class InputStream implements Closeable { public abstract int read() throws IOException; } /*具体组件角色*/ public class FileInputStream extends InputStream{ public int read() throws IOException { Object traceContext = IoTrace.fileReadBegin(path); int b = 0; try { b = read0(); } finally { IoTrace.fileReadEnd(traceContext, b == -1 ? 0 : 1); } return b; } } /*抽象装饰器角色*/ public class FilterInputStream extends InputStream { protected volatile InputStream in; protected FilterInputStream(InputStream in) { this.in = in; } public int read() throws IOException { return in.read(); } public int read(byte b[], int off, int len) throws IOException { return in.read(b, off, len); } } /*具体装饰器角色*/ public class BufferedInputStream extends FilterInputStream { protected volatile byte buf[]; public BufferedInputStream(InputStream in){ this(in, defaultBufferSize); } public synchronized int read() throws IOException { if (pos >= count) { fill(); if (pos >= count) return -1; } return getBufIfOpen()[pos++] & 0xff; } }
BufferedInputStream是继承自FilterInputStream的具体的装饰器类,该类提供一个内存的缓冲区来保存输入流中的数据。这样就带有缓冲功能,提高文件读入的效率。
所以,我们通常以这样的形式来使用它们
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file));
……更多设计模式的内容,可以访问Refactoring.Guru