设计模式学习(九):装饰器模式

设计模式学习(九):装饰器模式

作者:Grey

原文地址:

博客园:设计模式学习(九):装饰器模式

CSDN:设计模式学习(九):装饰器模式

装饰器模式

装饰器模式是一种结构型模式。

顾名思义,就是对某个方法或者对象进行装饰,举个简单的例子,有个圆形类 Circle,我需要把这个圆形的涂上红色,其实就是新增一个装饰器来装饰这个圆形类。

如果要让装饰器通用一些,可以处理圆形类对应的抽象类 Sharp ,那么对于任意 Sharp 的子类,都可以用红色装饰器来涂红色。

示例代码如下

我们先定义 Sharp 这个抽象类

public abstract class Sharp {     protected abstract void draw(); } 

然后我们定义 Sharp 的装饰类 SharpDecorator ,这个类是所有装饰器类的抽象类,后续的装饰器只需要实现这个抽象类就可以对 Sharp 进行各种装饰了,

public abstract class SharpDecorator extends Sharp {     protected Sharp decoratedSharp;      public SharpDecorator(Sharp decoratedSharp) {         this.decoratedSharp = decoratedSharp;     } } 

红色装饰器实现这个抽象类即可:

public class RedSharpDecorator extends SharpDecorator {     public RedSharpDecorator(Sharp decoratedSharp) {         super(decoratedSharp);     }      private static void redIt() {         System.out.println("[RED]");     }      @Override     protected void draw() {         redIt();         this.decoratedSharp.draw();         redIt();     } } 

主方法调用的时候只需要:

new RedSharpDecorator(new Circle()).draw(); 

UML 图如下:

设计模式学习(九):装饰器模式

说明:

  1. 装饰器类和原始类继承同样的父类,这样我们可以对原始类“嵌套”多个装饰器类。

  2. 装饰器类是对功能的增强,这也是装饰器模式应用场景的一个重要特点。符合“组合关系”这种代码结构的设计模式有很多,比如代理模式桥接模式,还有现在的装饰器模式。尽管它们的代码结构很相似,但是每种设计模式的意图是不同的。就拿比较相似的代理模式和装饰器模式来说:

代理模式中,代理类附加的是跟原始类无关的功能;

装饰器模式中,装饰器类附加的是跟原始类相关的增强功能。

装饰器模式应用

在 JDK 中,BufferedInputStream 、 DataInputStream 并非继承自 InputStream ,而是另外一个叫 FilterInputStream 的类。

这是因为 InputStream 是一个抽象类而非接口,而且它的大部分函数(比如 read()available())都有默认实现,按理来说,我们只需要在 BufferedInputStream 类中重新实现那些需要增加缓存功能的函数就可以了,其他函数只需要复用 InputStream 的默认实现。但实际上,这样做是行不通的。对于即便是不需要增加缓存功能的函数来说,BufferedInputStream 还是必须把它重新实现一遍,简单包裹对 InputStream 对象的函数调用。那 BufferedInputStream 类就无法将最终读取数据的任务,委托给传递进来的 InputStream 对象来完成,DataInputStream 也存在跟 BufferedInputStream 同样的问题。为了避免代码重复,Java I/O 包中抽象出了一个装饰器父类 FilterInputStream,包装了 InputStream 的默认实现

package java.io;  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[]) throws IOException {         return read(b, 0, b.length);     }      public int read(byte b[], int off, int len) throws IOException {         return in.read(b, off, len);     }      public long skip(long n) throws IOException {         return in.skip(n);     }      public int available() throws IOException {         return in.available();     }      public void close() throws IOException {         in.close();     }      public synchronized void mark(int readlimit) {         in.mark(readlimit);     }      public synchronized void reset() throws IOException {         in.reset();     }      public boolean markSupported() {         return in.markSupported();     } }  

InputStream 的所有的装饰器类( BufferedInputStream 和 DataInputStream )都继承自这个装饰器父类。这样,装饰器类只需要实现它需要增强的方法就可以了,其他方法继承装饰器父类的默认实现。

其他应用

  • Java 中的 I/O 流, Read/InputStream ,Write/OutputStream

  • Java 中的 UnmodifiableCollection

  • Spring 中的 HttpHeadResponseDecorator, 还有对 Cache 的装饰类 TransactionAwareCacheDecorator

UML 和 代码

UML 图

代码

更多

设计模式学习专栏

参考资料

发表评论

评论已关闭。

相关文章