Dar*_*der 54 .net java io design-patterns decorator
我在维基百科中读到,Decorator模式用于.Net和Java IO类.
任何人都能解释一下这是如何使用的吗?它有一个可能的例子,它有什么好处?
维基百科上有一个Windows窗体的例子,但我想知道Java IO类是如何发生的.
Bal*_*usC 136
InputStream
是一个抽象类.最喜欢的具体实现BufferedInputStream
,GzipInputStream
,ObjectInputStream
等有一个构造函数中的一个实例相同的抽象类.这是装饰器模式的识别键(这也适用于采用相同接口实例的构造函数).
当使用这样的构造函数时,所有方法都将委托给包装的实例,并改变方法的行为方式.例如,事先在内存中缓冲流,预先解压缩流或以不同方式解释流.有些甚至还有其他方法最终也会进一步委托给包装的实例.这些方法用额外的行为装饰包装的实例.
假设我们在Gzip文件中有一堆序列化的Java对象,我们希望快速读取它们.
首先打开它的输入流:
FileInputStream fis = new FileInputStream("/objects.gz");
Run Code Online (Sandbox Code Playgroud)
我们想要速度,所以让它在内存中缓冲:
BufferedInputStream bis = new BufferedInputStream(fis);
Run Code Online (Sandbox Code Playgroud)
该文件是gzip压缩的,所以我们需要解压缩它:
GzipInputStream gis = new GzipInputStream(bis);
Run Code Online (Sandbox Code Playgroud)
我们需要反序列化这些Java对象:
ObjectInputStream ois = new ObjectInputStream(gis);
Run Code Online (Sandbox Code Playgroud)
现在我们终于可以使用它了:
SomeObject someObject = (SomeObject) ois.readObject();
// ...
Run Code Online (Sandbox Code Playgroud)
好处是您可以使用一个或多个装饰器来自由地装饰流以满足您的需求.这比具有每一个可能的组合就像一个类好得多ObjectGzipBufferedFileInputStream
,ObjectBufferedFileInputStream
,GzipBufferedFileInputStream
,ObjectGzipFileInputStream
,ObjectFileInputStream
,GzipFileInputStream
,BufferedFileInputStream
,等.
请注意,当您即将关闭流时,只需关闭最外面的装饰器即可.它会将关闭呼叫一直委托给底部.
ois.close();
Run Code Online (Sandbox Code Playgroud)
Rav*_*abu 14
让我们在浏览java IO类之前了解Decorator模式的组件.
装饰者模式有四个组成部分
只要在设计时完成一些基础工作,装饰器模式可用于静态地(或在某些情况下)在运行时扩展(装饰)某个对象的功能,而与同一类的其他实例无关.这是通过设计一个包装原始类的新Decorator类来实现的.
现在让我们将这些概念映射到java.io pacakge类.
零件:
此抽象类是表示输入字节流的所有类的超类.
需要定义InputStream子类的应用程序必须始终提供返回输入的下一个字节的方法.
public abstract int read()
是一种抽象的方法.
ConcreteComponent:
FileInputStream从文件系统中的文件获取输入字节.可用的文件取决于主机环境.
FileInputStream用于读取原始字节流,例如图像数据.要读取字符流,请考虑使用FileReader.
InputStream的所有ConcreteComponents的示例:
AudioInputStream, ByteArrayInputStream, FileInputStream, FilterInputStream,
InputStream, ObjectInputStream, PipedInputStream, SequenceInputStream,
StringBufferInputStream
Run Code Online (Sandbox Code Playgroud)
装饰:
FilterInputStream包含一些其他输入流,它将其用作其基本数据源,可能会沿途转换数据或提供其他功能.
请注意,FilterInputStream
implements InputStream
=> Decorator实现了Component,如UML图所示.
public class FilterInputStream
extends InputStream
Run Code Online (Sandbox Code Playgroud)
ConcreteDecorator:
BufferedInputStream将功能添加到另一个输入流 - 即缓冲输入并支持标记和重置方法的功能.
所有ConcreteDecorators的示例:
BufferedInputStream, CheckedInputStream, CipherInputStream, DataInputStream,
DeflaterInputStream, DigestInputStream, InflaterInputStream,
LineNumberInputStream, ProgressMonitorInputStream, PushbackInputStream
Run Code Online (Sandbox Code Playgroud)
工作示例代码:
我曾经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);;
}
Run Code Online (Sandbox Code Playgroud)
何时使用此模式:
装饰器模式用于扩展传统功能,而无需更改传统类。假设我们有一个实现接口的具体类。而且我们需要扩展现有方法的功能,因为现有类及其方法已经被其他类使用,因此我们不想更改现有类。但是我们还需要在较新的类上扩展功能,那么我们如何解决这个问题?
1- We can't change the existing legacy code
2- We want to extend the functionality
Run Code Online (Sandbox Code Playgroud)
因此,我们使用装饰器模式,将现有的类包装在装饰器中。
在这里,我们有一个简单的接口和一个实现/具体类。接口有一个简单的方法,getMessageOfTheDay
它返回一个String
。假设使用此方法还有很多其他类。因此,如果我们要更改实现/具体类,它将影响旧的遗留代码。我们只想为新类更改它,所以我们使用装饰器模式。
这是四个装饰器设计模式的简单示例;
public interface Greeter {
String getMessageOfTheDay();
}
Run Code Online (Sandbox Code Playgroud)
public class BasicGreeter implements Greeter {
@Override
public String getMessageOfTheDay() {
return "Welcome to my server";
}
}
Run Code Online (Sandbox Code Playgroud)
public abstract class GreeterDecorator implements Greeter {
protected Greeter greeter;
public GreeterDecorator(Greeter greeter) {
this.greeter = greeter;
}
public String getMessageOfTheDay() {
return greeter.getMessageOfTheDay();
}
}
Run Code Online (Sandbox Code Playgroud)
public class StrangerDecorator extends GreeterDecorator {
public StrangerDecorator(Greeter greeter) {
super(greeter);
}
@Override
public String getMessageOfTheDay() {
return "Hello Stranger " + super.getMessageOfTheDay();
}
}
Run Code Online (Sandbox Code Playgroud)
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);
}
}
Run Code Online (Sandbox Code Playgroud)
看一下这些例子。需要抽象装饰器类来包装原始协定和实现。使用抽象装饰器,可以创建较新的多个装饰器,但是在此示例中,BasicGreeter被包装在抽象装饰器内部,并且我们仅在新的装饰器类StrangeGreeter上创建了它。请通知装饰器类可以像火车一样使用,我们可以将装饰器包装在另一个装饰器中。该功能是可扩展的,但原始类将保留而无需任何修改。
让我们看一下这个例子。我们要使用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();
}
}
Run Code Online (Sandbox Code Playgroud)
在项目文件夹下将创建一个名为“ normal.txt”的新文件,其内容为:
I love Commodore 64
Run Code Online (Sandbox Code Playgroud)
现在,我想创建一个JSON包装器格式,如下所示;
{
data: <data here>
}
Run Code Online (Sandbox Code Playgroud)
我想要的是将内容编写为简单的一个字段JSON格式。我们如何实现这个目标?有许多简单的方法。但是,我将通过编写扩展Java 的OutputStream类的JSONDecorator来使用GoF Decorator模式。
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());
}
}
Run Code Online (Sandbox Code Playgroud)
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();
}
}
Run Code Online (Sandbox Code Playgroud)
{
data:"I love Commodore 64"
}
Run Code Online (Sandbox Code Playgroud)
实际上,OutputStream本身就是一个装饰器模式,它是抽象装饰器,而具体装饰器在这里是JSONStream类。
当您操作输入/输出流时,在 java.io 类中使用装饰器模式(这同样适用于读取器和写入器)。
inputstream、bytearrayinputstream、stringbuilderinputstreams 等都是基础元素。Filterinputstream 是装饰器类的基类。过滤器输入流(例如 bufferedinput 流)在读取流或写入流时可以执行其他操作。
它们是通过封装流而构建的,并且本身就是流。
new BufferedReader( new FileInputStream() ).readLine();
Run Code Online (Sandbox Code Playgroud)
我想不出任何在 java.net 中实现此模式的类,但我认为您已被告知此包,因为它与 java.io 紧密相关(例如,socket.getInputStream)。
实际上,这里有 O'Relly 的课程(uwosh.edu | archive.org 上的 pdf,slideshare.net 上的幻灯片)解释了装饰器是如何在 java.io 中实现的。