Java IO 的 GoF 装饰器模式的用例和示例
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/6366385/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Use Cases and Examples of GoF Decorator Pattern for IO
提问by DarthVader
I have read in wikipediathat Decorator patternis used for .Netand Java IOclasses.
我在维基百科中读到装饰器模式用于.Net和Java IO类。
Can anybody explain how this is being used? And what is the benefit of it with a possible example?
谁能解释一下这是如何使用的?用一个可能的例子有什么好处?
There is an example of Windows formson wikipedia but I want to know how it happens with Java IOclasses.
维基百科上有一个Windows 表单示例,但我想知道Java IO类是如何发生的。
采纳答案by BalusC
InputStream
is an abstract class. Most concrete implementations like BufferedInputStream
, GzipInputStream
, ObjectInputStream
, etc. have a constructor that takes an instance of the sameabstract class. That's the recognition key of the decorator pattern (this also applies to constructors taking an instance of the same interface).
InputStream
是一个抽象类。大多数具体实现,如BufferedInputStream
、GzipInputStream
、ObjectInputStream
等,都有一个构造函数,该构造函数采用同一抽象类的实例。这是装饰器模式的识别键(这也适用于采用相同接口实例的构造函数)。
When such a constructor is used, all methods will delegate to the wrapped instance, with changes in the way the methods behave. For example, buffering the stream in memory beforehand, decompressing the stream beforehand or interpreting the stream differently. Some even have additional methods that finally also delegate further to the wrapped instance. Those methods decorate the wrapped instance with extra behaviour.
当使用这样的构造函数时,所有方法都将委托给包装的实例,方法的行为方式会发生变化。例如,预先在内存中缓冲流、预先解压缩流或以不同方式解释流。有些甚至有额外的方法,最终也进一步委托给包装的实例。这些方法用额外的行为装饰包装的实例。
Let's say that we have a bunch of serialized Java objects in a Gzipped file and that we want to read them quickly.
假设我们在一个 Gzipped 文件中有一堆序列化的 Java 对象,并且我们想快速读取它们。
First open an inputstream of it:
首先打开它的输入流:
FileInputStream fis = new FileInputStream("/objects.gz");
We want speed, so let's buffer it in memory:
我们想要速度,所以让我们将它缓存在内存中:
BufferedInputStream bis = new BufferedInputStream(fis);
The file is gzipped, so we need to ungzip it:
该文件已被 gzip 压缩,因此我们需要对其进行解压缩:
GzipInputStream gis = new GzipInputStream(bis);
We need to unserialize those Java objects:
我们需要反序列化这些 Java 对象:
ObjectInputStream ois = new ObjectInputStream(gis);
Now we can finally use it:
现在我们终于可以使用它了:
SomeObject someObject = (SomeObject) ois.readObject();
// ...
The benefit is that you have a lot of freedom to decorate the stream using one or more various decorators to suit your needs. That's much better than having a single class for every possible combination like ObjectGzipBufferedFileInputStream
, ObjectBufferedFileInputStream
, GzipBufferedFileInputStream
, ObjectGzipFileInputStream
, ObjectFileInputStream
, GzipFileInputStream
, BufferedFileInputStream
, etc.
好处是您可以自由地使用一个或多个不同的装饰器来装饰流以满足您的需要。这比具有每一个可能的组合就像一个类好得多ObjectGzipBufferedFileInputStream
,ObjectBufferedFileInputStream
,GzipBufferedFileInputStream
,ObjectGzipFileInputStream
,ObjectFileInputStream
,GzipFileInputStream
,BufferedFileInputStream
,等。
Note that when you're about to close the stream, just closing the outermostdecorator is sufficient. It will delegate the close call all the way to the bottom.
请注意,当您要关闭流时,只需关闭最外面的装饰器就足够了。它会将近距离呼叫一直委托到底部。
ois.close();
See also:
也可以看看:
回答by Chris Jester-Young
One way you can decorate an input/output stream is to apply compression/decompression to it. See the classes in java.util.zip
, for example. Such a decorated stream can be used exactly the same way as a "regular" input/output stream, with compression/decompression performed totally transparently.
装饰输入/输出流的一种方法是对其应用压缩/解压缩。java.util.zip
例如,请参阅 中的类。这种修饰流可以与“常规”输入/输出流完全相同的方式使用,压缩/解压缩完全透明地执行。
回答by Alex Aza
In .NET, there are a bunch of stream decorators, like BufferedStream, CryptoStream, GzipStream, etc. All those decorate Stream
class.
在 .NET 中,有一堆流装饰器,如 BufferedStream、CryptoStream、GzipStream 等。所有这些都装饰Stream
类。
回答by Snicolas
The decorator pattern is used in java.io classes when you manipulated input/output streams (and the same applies for readers and writers).
当您操作输入/输出流时,在 java.io 类中使用装饰器模式(这同样适用于读取器和写入器)。
inputstream, bytearrayinputstream, stringbuilderinputstreams and so on are based elements. Filterinputstream is the base class for the decorator classes. Filter input streams (such as bufferedinput stream) can do additional things when they read streams or write to them.
inputstream、bytearrayinputstream、stringbuilderinputstreams 等都是基于元素的。Filterinputstream 是装饰器类的基类。过滤器输入流(例如 bufferedinput 流)可以在读取流或写入流时执行其他操作。
They are built by encapsulating a stream, and are streams themselves.
它们是通过封装流来构建的,并且本身就是流。
new BufferedReader( new FileInputStream() ).readLine();
I can't think of any class implementing this pattern in java.net, but I think your were told about this package as it is strongly tied to java.io (socket.getInputStream for instance).
我想不出任何在 java.net 中实现这种模式的类,但我认为你听说过这个包,因为它与 java.io(例如 socket.getInputStream)紧密相关。
Actually, here is a course from O'Relly (pdf on uwosh.edu | archive.org, slides on slideshare.net) that explains how decorator is implemented in java.io.
其实,这里是从O'Relly(课程上uwosh.edu PDF | archive.org,在slideshare.net幻灯片),说明装饰是如何在java.io.实施
回答by Will Johnson
The decorator pattern is used to add functionality to existing objects such as a class defined in a library. You can then "decorate" it to fit your needs. If you are interested in learning more about patterns I recommend "Design Patterns" by the Gang of Four.
装饰器模式用于向现有对象(例如库中定义的类)添加功能。然后,您可以“装饰”它以满足您的需要。如果您有兴趣了解更多有关模式的知识,我推荐四人帮的“设计模式”。
回答by Ravindra babu
Let's understand components of Decoratorpattern before going through java IO classes.
在了解Java IO 类之前,让我们了解装饰器模式的组件。
Decoratorpattern has four components
装饰者模式有四个组成部分
- Component:The Componentdefines the interface for objects that can have responsibilties added dynamically
- ConcreteComponent:It is simply an implementation of Componentinterface
- Decorator:The Decoratorhas a reference to a Component, and also conforms to the Componentinterface. Decorator is essentially wrapping the Component
- ConcreteDecorator:The ConcreteDecoratorjust adds responsibilities to the original Component.
- 组件:该组件定义了接口,其可具有动态添加responsibilties对象
- ConcreteComponent:它只是Component接口的一个实现
- 装饰:将装饰具有到一个参考组件,并且也符合 组件接口。装饰器本质上是包装组件
- ConcreteDecorator:该ConcreteDecorator只是增加了责任到原来的组件。
The decorator pattern can be used to extend (decorate) the functionality of a certain object statically, or in some cases at run-time, independently of other instances of the same class, provided some groundwork is done at design time. This is achieved by designing a new Decoratorclass that wraps the original class.
装饰器模式可用于静态地或在某些情况下在运行时扩展(装饰)某个对象的功能,独立于同一类的其他实例,前提是在设计时完成了一些基础工作。这是通过设计一个包装原始类的新装饰器类来实现的。
Now let's map these concepts to java.io pacakge classes.
现在让我们将这些概念映射到 java.io pacakge 类。
Component:
成分:
输入流:
This abstract class is the superclass of all classes representing an input stream of bytes.
Applications that need to define a subclass of InputStream must always provide a method that returns the next byte of input.
这个抽象类是所有表示字节输入流的类的超类。
需要定义 InputStream 子类的应用程序必须始终提供返回输入的下一个字节的方法。
public abstract int read()
is an abstract method.
public abstract int read()
是一个抽象方法。
ConcreteComponent:
具体组件:
A FileInputStream obtains input bytes from a file in a file system. What files are available depends on the host environment.
FileInputStream is meant for reading streams of raw bytes such as image data. For reading streams of characters, consider using FileReader.
FileInputStream 从文件系统中的文件中获取输入字节。哪些文件可用取决于主机环境。
FileInputStream 用于读取原始字节流,例如图像数据。要读取字符流,请考虑使用 FileReader。
Examples of all ConcreteComponents of InputStream:
InputStream 的所有 ConcreteComponents 的示例:
AudioInputStream, ByteArrayInputStream, FileInputStream, FilterInputStream,
InputStream, ObjectInputStream, PipedInputStream, SequenceInputStream,
StringBufferInputStream
Decorator:
装饰器:
A FilterInputStream contains some other input stream, which it uses as its basic source of data, possibly transforming the data along the way or providing additional functionality.
FilterInputStream 包含一些其他输入流,它用作其基本数据源,可能沿途转换数据或提供附加功能。
Please note that FilterInputStream
implements InputStream
=> Decorator implements Component as shown in UML diagram.
请注意,FilterInputStream
implements InputStream
=> Decorator 实现了 Component,如 UML 图中所示。
public class FilterInputStream
extends InputStream
ConcreteDecorator:
混凝土装饰器:
A BufferedInputStream adds functionality to another input stream-namely, the ability to buffer the input and to support the mark and reset methods.
BufferedInputStream 向另一个输入流添加功能,即缓冲输入和支持标记和重置方法的能力。
Examples of all ConcreteDecorators:
所有ConcreteDecorators 的例子:
BufferedInputStream, CheckedInputStream, CipherInputStream, DataInputStream,
DeflaterInputStream, DigestInputStream, InflaterInputStream,
LineNumberInputStream, ProgressMonitorInputStream, PushbackInputStream
Working example code:
工作示例代码:
I have used BufferedInputStream
to read each character of a word, which has been stored in a text file a.txt
我曾经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);;
}
When to use this pattern:
何时使用此模式:
- Object responsibilities and behaviours should be dynamically added/removed
- Concrete implementations should be decoupled from responsibilities and behaviours
- When sub - classing is too costly to dynamically add/remove responsibilities
- 应动态添加/删除对象职责和行为
- 具体的实现应该与职责和行为脱钩
- 当子类化成本太高而无法动态添加/删除职责时
回答by kosalgeek
Well, I may be late to the party but this question never gets old. The key point to understand Decoratoris that it gives you the ability to plug an object to an existing object to another existing object and so on. It is popular to implement this pattern in a constructor. For example,
好吧,我可能会迟到,但这个问题永远不会过时。理解装饰器的关键在于它使您能够将一个对象插入现有对象到另一个现有对象,依此类推。在构造函数中实现这种模式很流行。例如,
Icecream ic = new RainbowTopUp(new ChocoTopUp(new Vanilla()));
If you look at the diagram in the wikipedia, you would see ConcreteComponentand Decoratorinherit from the same superclass/interface, Component. That is, these two classes have the same implement method(s).
如果您查看维基百科中的图表,您会看到ConcreteComponent和Decorator继承自同一个超类/接口Component。也就是说,这两个类具有相同的实现方法。
However, in the Decoratorclass, you'd see an arrow back to the Component, which means you use Componentsomewhere in the Decoratorclass. In this case, you use the Componentas a datatype of a constructor in the Decorator. That is the big trick. Without this trick, you won't be able to plug a new object to an existing object.
但是,在Decorator类中,您会看到返回Component的箭头,这意味着您在Decorator类中的某处使用Component。在这种情况下,您将Component用作Decorator 中构造函数的数据类型。这就是大把戏。没有这个技巧,您将无法将新对象插入现有对象。
After that, you can create subclasses inheriting from the Decoratorclass. Because all classes have the same root, every single classes can freely plugin without any order.
之后,您可以创建继承自Decorator类的子类。因为所有的类都有相同的根,所以每个类都可以自由地插入,没有任何顺序。
回答by Levent Divilioglu
A - Decorator Pattern
A - 装饰者模式
A.1 - Use Case of Decorator Pattern
A.1 - 装饰模式的用例
Decorator pattern is used for extending a legacy functionality without changing the legacy class. Let's say, we have a concrete class that implements an interface. And we need to extend the functionality of the existing method however because that the existing class, and its methods are already used by other classes, thus we don't want to make a change in the existing classes. But we also need extended functionality on newer class, then how do we solve this problem?
装饰器模式用于在不更改遗留类的情况下扩展遗留功能。假设我们有一个实现接口的具体类。但是我们需要扩展现有方法的功能,因为现有类及其方法已经被其他类使用,因此我们不想对现有类进行更改。但是我们还需要在较新的类上扩展功能,那么我们如何解决这个问题呢?
1- We can't change the existing legacy code
2- We want to extend the functionality
So we use decorator pattern, wrap the existing class inside the decorators.
所以我们使用装饰器模式,将现有的类包装在装饰器中。
B - Basic GoF Decorator Pattern Example
B - 基本的 GoF 装饰器模式示例
Here we have a simple interface and an implementation/concrete class. The interface has one simple method, which is getMessageOfTheDay
and it returns a String
. Assume that there are lots of other classes using this method. So if we want to make a change in the implementation/concrete class, it will affect the old legacy code. We want to change it for only the new classes so we use the decorator pattern.
这里我们有一个简单的接口和一个实现/具体类。该接口有一个简单的方法,即getMessageOfTheDay
它返回一个String
. 假设有很多其他类使用这种方法。因此,如果我们要对实现/具体类进行更改,则会影响旧的遗留代码。我们只想为新类更改它,因此我们使用装饰器模式。
Here is a trivial example of Gang Of Four Decorator Design pattern;
这是四人组装饰设计模式的一个简单例子;
B.1 - Greeter.java
B.1 - Greeter.java
public interface Greeter {
String getMessageOfTheDay();
}
B.2 - BasicGreeter.java
B.2 - BasicGreeter.java
public class BasicGreeter implements Greeter {
@Override
public String getMessageOfTheDay() {
return "Welcome to my server";
}
}
B.3 - Abstract Decorator Class: GreeterDecorator.java
B.3 - 抽象装饰器类:GreeterDecorator.java
public abstract class GreeterDecorator implements Greeter {
protected Greeter greeter;
public GreeterDecorator(Greeter greeter) {
this.greeter = greeter;
}
public String getMessageOfTheDay() {
return greeter.getMessageOfTheDay();
}
}
B.4 - Concrete Decorator Class: StrangerDecorator.java
B.4 - 具体装饰器类:StrangerDecorator.java
public class StrangerDecorator extends GreeterDecorator {
public StrangerDecorator(Greeter greeter) {
super(greeter);
}
@Override
public String getMessageOfTheDay() {
return "Hello Stranger " + super.getMessageOfTheDay();
}
}
B.5 - Demo Code: DecoratorDemo .java
B.5 - 演示代码:DecoratorDemo .java
public class DecoratorDemo {
public static void main(String[] args) {
Greeter greeter = new BasicGreeter();
String motd = greeter.getMessageOfTheDay();
System.out.println(motd);
Greeter newGreeter = new StrangerDecorator(greeter);
String newMotd = newGreeter.getMessageOfTheDay();
System.out.println(newMotd);
Greeter muchNewGreeter = new StrangerDecorator(new StrangerDecorator(greeter));
String newestMotd = muchNewGreeter.getMessageOfTheDay();
System.out.println(newestMotd);
}
}
Take a look at those examples. The abstract decorator class is needed to wrap the original contract and implementation. Using the abstract decorator, you can create newer multiple decorators but in this example, BasicGreeteris wrapped inside the abstract decorator and we have only created on new decorator class which is StrangeGreeter. Please notify that decorator classes can be used like a train, we can wrap a decorator inside another decorator or the same. The functionality is extendable but the original class is preserved without any modification.
看看这些例子。需要抽象装饰器类来包装原始契约和实现。使用抽象装饰器,您可以创建更新的多个装饰器,但在本例中,BasicGreeter被包裹在抽象装饰器中,我们只在新的装饰器类StrangeGreeter 上创建。请注意装饰器类可以像火车一样使用,我们可以将装饰器包装在另一个装饰器中或相同的装饰器中。功能是可扩展的,但原始类保留而无需任何修改。
C - OutputStream Demo
C - 输出流演示
Let's take a look at this example. We want to write a string to file with OutputStream. Here is the demo code;
让我们来看看这个例子。我们想用 OutputStream 将一个字符串写入文件。这是演示代码;
C.1 - Sample OutputStream Demo To Write A File
C.1 - 用于写入文件的示例 OutputStream 演示
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
public class FileWriterDemo {
public static void main(String[] args) throws IOException {
File file = new File("./normal.txt");
file.createNewFile();
OutputStream oStream = new FileOutputStream(file);
String content = "I love Commodore 64";
oStream.write(content.getBytes());
oStream.close();
}
}
C.2 - JSON Decorator Output: normal.txt
C.2 - JSON 装饰器输出:normal.txt
There will be a new file with name "normal.txt" created under the project folder and the content will be;
项目文件夹下会新建一个名为“normal.txt”的文件,内容为;
I love Commodore 64
D - JSON OutputStream Decorator Demo
D - JSON OutputStream 装饰器演示
Now, I want to create a JSON wrapper format, which is as follows;
现在,我想创建一个 JSON 包装器格式,如下所示;
{
data: <data here>
}
What I want is to write the content inside a simple one field JSONformat. How can we achieve this goal? There are many trivial ways. However, I will use the GoF Decorator Patternby writing a JSONDecoratorwhich extends the OutputStreamclass of Java;
我想要的是将内容写入简单的单字段JSON格式。我们怎样才能实现这个目标?有很多琐碎的方法。但是,我将通过编写扩展Java的OutputStream类的JSONDecorator来使用GoF 装饰器模式;
D.1 - JSON Decorator for OutputStream: JSONStream.java
D.1 - 输出流的 JSON 装饰器:JSONStream.java
public class JSONStream extends OutputStream {
protected OutputStream outputStream;
public JSONStream(OutputStream outputStream) {
this.outputStream = outputStream;
}
@Override
public void write(int b) throws IOException {
outputStream.write(b);
}
@Override
public void write(byte[] b) throws IOException {
String content = new String(b);
content = "{\r\n\tdata:\"" + content + "\"\r\n}";
outputStream.write(content.getBytes());
}
}
D.2 - JSON Decorator Demo: JSONDecoratorDemo.java
D.2 - JSON 装饰器演示:JSONDecoratorDemo.java
public class JSONDecoratorDemo {
public static void main(String[] args) throws IOException {
File file = new File("./json.txt");
file.createNewFile();
OutputStream oStream = new FileOutputStream(file);
JSONStream js = new JSONStream(oStream);
String content = "I love Commodore 64";
js.write(content.getBytes());
js.close();
oStream.close();
}
}
D.3 - JSON Decorator Output: json.txt
D.3 - JSON 装饰器输出:json.txt
{
data:"I love Commodore 64"
}
Actually, OutputStreamitself a Decorator Pattern, it is the abstract decorator and concrete decorator in here is the JSONStreamclass.
实际上,OutputStream本身就是一个装饰器模式,它是抽象装饰器,而具体装饰器在这里是JSONStream类。