8

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

 1 year ago
source link: https://www.cnblogs.com/greyzeng/p/16878615.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

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

作者: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 图如下:

image
  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 图

代码

更多#

设计模式学习专栏

参考资料#


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK