装饰器模式 - 结构型

本文主要是通过Java I/O学习装饰器模式。

一、装饰器模式的定义和实现
定义:指在不改变现有对象结构的情况下,动态地给该对象增加额外功能的模式。
实现:装饰类Decorator为ConcreteApple新增功能resA()、resB()

public class ConcreteApple{
    public void res() {
        // ...
    }
}


public class Decorator implements ConcreteApple{
    protected ConcreteApple apple;

    public Decorator(ConcreteApple apple) {
        super();
        this.apple = apple;
    }

    public void res() {
        resA();   // 扩展功能A
        apple.res();
        resB();   // 扩展功能B
    }
    public void resA() {
        // ...
    }
    public void resB() {
        // ...
    }
}

二、Java I/O的装饰器模式
Java I/O类图如下所示。

图1.jpg

I/O类的使用如下所示,FileInputStream具有读取文件的功能,BufferedInputStream具有缓存功能。FileInputStream作为BufferedInputStream的构造参数,感觉有点问题:创建了两次InputStream,一层嵌套一层。

InputStream in = new FileInputStream("/user/wangzheng/test.txt");
InputStream bin = new BufferedInputStream(in);
byte[] data = new byte[128];
while (bin.read(data) != -1) {
  //...
}

问题1:为什么需要嵌套InputStream?
解答:我们需要读取文件,也需要有缓存功能

问题2:为什么不直接设计读取文件+缓存功能的类,如BufferedFileInputStream?
解答:如果直接设计BufferedFileInputStream,可能导致类太多。

InputStream bfin = new BufferedFileInputStream("/user/wangzheng/test.txt");
while (bfin.read(data) != -1) {
  //...
}

针对问题2,我们一起来看看,如何直接设计BufferedFileInputStream:可以采用继承的方案。思考一下,如上图1,InputStream有4个数据源子类+2个功能子类(非抽象类),分别是ByteArrayInputStream、PipeInputStream、FileInputStream、ObjectInputStream和BufferedInputStream、DatainputStream。

基于继承的方案:BufferedByteArrayInputStream、BufferedPipeInputStream等,总共4*2个类。如果功能子类数量增加,例如OutputStream的BufferedOutputStream、DataOutputStream、PrintOutputStream,导致类数量的爆炸。

因此,可以采用装饰器模式,符合“组合优于继承”,可以“使用组合来替代继承。

装饰器模式的特点
1.继承相同的父类:装饰器类和原始类继承同样的父类,这样我们可以对原始类“嵌套”多个装饰器类。
2.增强效果:装饰器类是对功能的增强,这也是装饰器模式应用场景的一个重要特点。

文章参考王争老师的《设计模式之美》。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容