装饰模式

概述

《设计模式》一书中对于 “装饰模式” 的动机描述如下:

动态地给一个对象添加一些额外的职责

按照 SOLID 面向对象编程原则中的 O(开闭原则),对于功能的修改应当关闭,而对于功能的扩展应予以放开,“装饰模式” 就很好地体现了这一点

一般装饰模式的 UML 图如下所示:

Decorator.png

一般在以下几种i情况中使用装饰模式:

  • 在不影响其它对象的情况下,以动态、透明的方式给单个对象添加职责
  • 处理那些可以撤销的职责
  • 当不能通过生成子类的方式来对已有类的功能进行扩展(语法上不能扩展或者需要扩展的子类太多)

具体实例

一个比较经典的实例就是 javaIO 处理类,对于基层的数据读取来讲,可以通过 Reader 来读取字符,具体有以下几个方法:

public abstract class Reader implements Readable, Closeable {
    // 这个方法每次将会读取一个单独的字符
    public int read() throws IOException {
        // 省略具体内容
    }
}

一般如果希望读取一个文本文件,那么可能希望一次读取一行内容而不是一个字符,因此引入了 BufferedReader 来对其进行扩展,扩展后的 BufferedReader 需要一个 Reader 作为构造参数,通过 Readerread() 方法来实现每次读取一行数据的功能:

public class BufferedReader extends Reader {
    private Reader in;

    private char cb[];
    private int nChars, nextChar;
    
    public BufferedReader(Reader in, int sz) {
        super(in);
        if (sz <= 0)
            throw new IllegalArgumentException("Buffer size <= 0");
        this.in = in;
        cb = new char[sz];
        nextChar = nChars = 0;
    }
    
    // 每次读取一行文本内容
    public String readLine() throws IOException {
        return readLine(false);
    }
    
    // Reader 方法,每次读取一个字符
    public int read() throws IOException {
        // 省略部分内容。。。。
    }
}

这是一个典型的装饰模式的使用

总结

一般扩展类的功能可以通过继承的方式来实现,而引入装饰模式则提供了另一种可行的扩展实现方案。相比较于通过继承的方式来扩展功能, “装饰模式” 会更加灵活,并且可以简化部分类结构。但 “装饰模式” 的引入也可能会导致类的扩展点不容易被发现,因此希望再进行其它的扩展时可能相比较于继承的方式来讲更加困难,在设计类的结构时需要做出部分的取舍


参考:

[1] 《设计模式—可复用面向对象基础》

posted @ 2023-03-02 22:23  FatalFlower  阅读(13)  评论(0编辑  收藏  举报