IO 的 GoF 装饰器模式的用例和示例

2022-08-31 15:29:15

在维基百科中读到,装饰器模式用于.NetJava IO类。

任何人都可以解释这是如何使用的吗?用一个可能的例子来说,它有什么好处?

维基百科上有一个Windows表单的例子,但我想知道Java IO类是如何发生的。


答案 1

InputStream 是一个抽象类。大多数具体的实现,如BufferedInputStreamGzipInputStreamObjectInputStream等,都有一个构造函数,该构造函数采用一抽象类的实例。这是装饰器模式的识别键(这也适用于采用相同接口实例的构造函数)。

使用此类构造函数时,所有方法都将委托给包装的实例,并更改方法的行为方式。例如,事先在内存中缓冲流、事先解压缩流或以不同的方式解释流。有些甚至有其他方法,这些方法最终还会进一步委托给包装的实例。这些方法使用额外的行为来修饰包装的实例。

假设我们在Gzipped文件中有一堆序列化的Java对象,并且我们希望快速读取它们。

首先打开它的输入流:

FileInputStream fis = new FileInputStream("/objects.gz");

我们想要速度,所以让我们在内存中缓冲它:

BufferedInputStream bis = new BufferedInputStream(fis);

该文件已 gzip,因此我们需要将其解压缩:

GzipInputStream gis = new GzipInputStream(bis);

我们需要取消序列化这些 Java 对象:

ObjectInputStream ois = new ObjectInputStream(gis);

现在我们终于可以使用它了:

SomeObject someObject = (SomeObject) ois.readObject();
// ...

好处是,您可以使用一个或多个不同的装饰器来装饰流,以满足您的需求。这比为每个可能的组合(如、等)使用单个类要好得多。ObjectGzipBufferedFileInputStreamObjectBufferedFileInputStreamGzipBufferedFileInputStreamObjectGzipFileInputStreamObjectFileInputStreamGzipFileInputStreamBufferedFileInputStream

请注意,当您要关闭流时,只需关闭最外层的装饰器就足够了。它将把关闭调用一直委托到底部。

ois.close();

另请参阅:


答案 2

让我们在介绍 java IO 类之前了解 Decorator 模式的组件。

enter image description here

装饰器图案有四个组成部分

  1. 元件:组件定义可以动态添加责任的对象的接口
  2. 混凝土组件:它只是组件接口的实现
  3. 装饰:装饰器具有对组件的引用,并且还符合组件接口。装饰器实质上是包装组件
  4. 混凝土装饰:混凝土装饰器只是向原始组件增加了责任。

装饰器模式可用于静态扩展(装饰)某个对象的功能,或者在某些情况下在运行时独立于同一类的其他实例,前提是在设计时完成一些基础工作。这是通过设计一个包装原始类的新 Decorator 类来实现的。

现在,让我们将这些概念映射到 java.io pacakge 类。

元件:

输入流

此抽象类是表示字节输入流的所有类的超类。

需要定义 InputStream 子类的应用程序必须始终提供返回下一个输入字节的方法。

public abstract int read()是一种抽象方法。

混凝土组件:

文件输入流

FileInputStream 从文件系统中的文件获取输入字节。哪些文件可用取决于主机环境。

FileInputStream 用于读取原始字节流,例如图像数据。要读取字符流,请考虑使用 FileReader。

输入流的所有混凝土组件的示例:

AudioInputStream, ByteArrayInputStream, FileInputStream, FilterInputStream, 
InputStream, ObjectInputStream, PipedInputStream, SequenceInputStream, 
StringBufferInputStream

装饰:

过滤器输入流

FilterInputStream 包含一些其他输入流,它使用这些输入流作为其基本数据源,可能会在此过程中转换数据或提供其他功能。

请注意,实现 =>装饰器实现组件,如 UML 图所示FilterInputStreamInputStream

public class FilterInputStream
extends InputStream

混凝土装饰:

缓冲输入流

BufferedInputStream 向另一个输入流添加功能,即缓冲输入以及支持标记和重置方法的功能。

所有混凝土装饰器的示例

BufferedInputStream, CheckedInputStream, CipherInputStream, DataInputStream, 
DeflaterInputStream, DigestInputStream, InflaterInputStream, 
LineNumberInputStream, ProgressMonitorInputStream, PushbackInputStream

工作示例代码:

我曾经读过一个单词的每个字符,它都存储在一个文本文件中.txtBufferedInputStream

BufferedInputStream bis = new BufferedInputStream(new FileInputStream(new File("a.txt")));
while(bis.available()>0)
{
        char c = (char)bis.read();
        System.out.println("Char: "+c);;
}

何时使用此模式:

  1. 应动态添加/删除对象职责和行为
  2. 具体实施应与责任和行为脱钩
  3. 当子类分类成本太高而无法动态添加/删除职责时

推荐