IO的装饰模式
我已经在维基百科中读过Decorator模式用于.Net和Java IO类。
有人可以解释如何使用? 和一个可能的例子,它的好处是什么?
在wiki上有一个窗口窗体的例子,但我想知道它是如何发生在IO类。
InputStream
是一个抽象类。 像BufferedInputStream
, GzipInputStream
, ObjectInputStream
等大多数具体实现都有一个构造函数,它需要一个相同抽象类的实例。 这是装饰器模式的识别关键(这也适用于采取相同接口的实例的构造函数)。
当使用这样的构造函数时,所有方法都将委托给包装的实例,同时改变方法的行为。 例如,预先在内存中缓冲stream,预先解压缩stream或以不同的方式解释stream。 有些甚至还有其他的方法,最终还将进一步委托给包装的实例。 这些方法用额外的行为来装饰包装的实例。
假设我们在Gzip文件中有一堆序列化的Java对象,并且我们希望快速读取它们。
首先打开它的inputstream:
FileInputStream fis = new FileInputStream("/objects.gz");
我们想要速度,所以让我们把它缓冲在内存中:
BufferedInputStream bis = new BufferedInputStream(fis);
该文件是gzipped,所以我们需要解压缩它:
GzipInputStream gis = new GzipInputStream(bis);
我们需要反序列化这些Java对象:
ObjectInputStream ois = new ObjectInputStream(gis);
现在我们终于可以使用它了:
SomeObject someObject = (SomeObject) ois.readObject(); // ...
好处是你有很大的自由来装饰stream使用一个或多个各种装饰,以满足您的需求。 比单独使用ObjectGzipBufferedFileInputStream
, ObjectBufferedFileInputStream
, GzipBufferedFileInputStream
, ObjectGzipFileInputStream
, ObjectFileInputStream
, GzipFileInputStream
, BufferedFileInputStream
等组合类的方法要好得多。
请注意,当你要closuresstream时,只closures最外层的装饰器就足够了。 它会将closures呼叫一直委托给底部。
ois.close();
也可以看看:
- Java核心库中的GoFdevise模式示例
让我们在通过Java IO类之前了解Decorator
模式的组件。
装饰模式有四个组成部分
-
Component:
Component
定义了可以dynamic添加职责的对象的接口 -
ConcreteComponent:
它只是一个Component
接口的实现 -
Decorator:
Decorator
有一个Component
的引用,也符合Component
接口。Decorator
者本质上是包装Component
-
ConcreteDecorator:
ConcreteDecorator
只是增加了原始Component
职责。
装饰器模式可以被用来静态地或者在运行时扩展(修饰)某个对象的function,而不依赖于同一类的其他实例,只要在devise时做一些基础工作即可。 这是通过devise一个包装original class
的新的Decorator
类来实现的。
现在让我们将这些概念映射到java.io派生类。
零件:
InputStream :
这个抽象类是表示input字节stream的所有类的超类。
需要定义InputStream子类的应用程序必须始终提供一个返回下一个input字节的方法。
public abstract int read()
是一个抽象方法。
ConcreteComponent:
FileInputStream :
FileInputStream从文件系统中的文件获取input字节。 哪些文件可用取决于主机环境。
FileInputStream用于读取诸如图像数据之类的原始字节stream。 为了读取字符stream,请考虑使用FileReader。
InputStream的所有ConcreteComponents的例子:
AudioInputStream, ByteArrayInputStream, FileInputStream, FilterInputStream, InputStream, ObjectInputStream, PipedInputStream, SequenceInputStream, StringBufferInputStream
装饰:
FilterInputStream :
FilterInputStream包含一些其他的inputstream,它用作其基本的数据源,可能会沿途转换数据或提供附加function。
请注意, FilterInputStream
实现了InputStream
=> Decorator implements Component as shown in UML diagram
。
public class FilterInputStream extends InputStream
ConcreteDecorator:
的BufferedInputStream
BufferedInputStream将function添加到另一个inputstream,即缓冲input和支持标记和重置方法的function。
所有ConcreteDecorators
例子:
BufferedInputStream, CheckedInputStream, CipherInputStream, DataInputStream, DeflaterInputStream, DigestInputStream, InflaterInputStream, LineNumberInputStream, ProgressMonitorInputStream, PushbackInputStream
工作示例代码:
我已经使用BufferedInputStream
来读取一个单词的每个字符,它已经存储在一个文本文件a.txt中
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(new File("a.txt"))); while(bis.available()>0) { char c = (char)bis.read(); System.out.println("Char: "+c);; }
何时使用这种模式:
- 对象的职责和行为应该dynamic添加/删除
- 具体实施应该与责任和行为分离
- 当分类分类过于昂贵时,无法dynamic增加/删除责任
在.NET中,有一堆stream装饰器,如BufferedStream,CryptoStream,GzipStream等。所有这些装饰Stream
类。
当您操作input/输出stream时,装饰器模式在java.io类中使用(读者和作者同样适用)。
inputstream,bytearrayinputstream,stringbuilderinputstreams等是基于元素。 Filterinputstream是装饰类的基类。 filterinputstream(例如bufferedinputstream)在读取stream或写入stream时可以做其他事情。
它们是通过封装stream来构build的,并且是stream本身。
new BufferedReader( new FileInputStream() ).readLine();
我想不出任何在java.net中实现这个模式的类,但是我想你会被告知这个包,因为它与java.io紧密相关(比如socket.getInputStream)。
实际上, 这里是O'Relly的一个课程,它解释了如何在java.io中实现装饰器。
问候,Stéphane
您可以修饰input/输出stream的一种方法是对其进行压缩/解压缩。 例如,查看java.util.zip
的类。 这样的装饰stream可以与“常规”input/输出stream完全相同的方式使用,压缩/解压缩完全透明地执行。
装饰器模式用于为现有对象(如库中定义的类)添加function。 你可以“装饰”它来适应你的需求。 如果您有兴趣了解更多关于模式的信息,我推荐四人帮的“devise模式”。
那么我可能会迟到,但这个问题不会老化。 理解装饰器的关键在于,它使您能够将对象与现有对象连接到另一个现有对象,等等。 在构造函数中实现这个模式是很受欢迎的。 例如,
Icecream ic = new RainbowTopUp(new ChocoTopUp(new Vanilla()));
如果你看看维基百科的图表,你会看到ConcreteComponent和Decoratorinheritance自同一个超类/接口Component 。 也就是说,这两个类具有相同的实现方法。
但是,在Decorator类中,您会看到一个箭头回到Component ,这意味着您在Decorator类的某处使用Component 。 在这种情况下,您可以使用Component作为Decorator中构造函数的数据types。 这是一个很大的窍门。 没有这个技巧,你将无法将一个新的对象插入到一个现有的对象中。
之后,您可以创build从Decorator类inheritance的子类。 因为所有的类都有相同的根,所以每一个类都可以自由的插入而不需要任何的顺序。