1- We can't change the existing legacy code
2- We want to extend the functionality
所以我们使用装饰器模式,将现有的类 Package 在装饰器中。
B -基础GoF装饰模式示例
这里我们有一个简单的接口和一个implementation/concrete类。接口有一个简单的方法,它是getMessageOfTheDay,它返回一个String。假设有很多其他的类使用这个方法。所以如果我们想在implementation/concrete类中做一个改变,它会影响旧的遗留代码。我们只想为新的类改变它,所以我们使用装饰器模式。 下面是一个Gang Of Four Decorator Design模式的小例子;
B.1 -Greeter.java
public interface Greeter {
String getMessageOfTheDay();
}
B.2 -BasicGreeter.java
public class BasicGreeter implements Greeter {
@Override
public String getMessageOfTheDay() {
return "Welcome to my server";
}
}
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 -混凝土装饰类: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代码: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);
}
}
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演示: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();
}
}
8条答案
按热度按时间bakd9h0s1#
InputStream
是一个抽象类。大多数具体实现,如BufferedInputStream
,GzipInputStream
,ObjectInputStream
等,都有一个构造函数,它接受相同抽象类的示例。这是装饰器模式的识别关键(这也适用于接受相同接口示例的构造函数)。当使用这样的构造函数时,所有方法都将委托给 Package 的示例,并改变方法的行为方式。例如,预先在内存中缓冲流,预先解压缩流或以不同的方式解释流。有些甚至有额外的方法,最终也会进一步委托给 Package 的示例。这些方法用额外的行为装饰 Package 的示例。
假设我们在一个Gzip文件中有一堆序列化的Java对象,并且我们希望快速读取它们。
首先打开它的一个inputstream:
我们想要速度,所以让我们在内存中缓冲它:
文件是gzip的,所以我们需要ungzip它:
我们需要反序列化这些Java对象:
现在我们终于可以使用它了:
这样做的好处是,你可以自由地使用一个或多个不同的装饰器来装饰流,以满足你的需要。这比为每个可能的组合(如
ObjectGzipBufferedFileInputStream
,ObjectBufferedFileInputStream
,GzipBufferedFileInputStream
,ObjectGzipFileInputStream
,ObjectFileInputStream
,GzipFileInputStream
,BufferedFileInputStream
等)使用一个类要好得多。请注意,当你要关闭流时,只关闭 outermost 装饰器就足够了。它会将close调用一直委托到底部。
另请参见:
yduiuuwa2#
在学习java IO类之前,让我们先了解一下Decorator模式的组件。
Decorator模式有四个组成部分(维基百科)
1.* 组件:* 组件 * 为可以动态添加责任的对象定义接口
1.ConcreteComponent: 它只是 Component 接口的一个实现
1.*Decorator:Decorator 有一个 Component 的引用,也符合 Component 接口,Decorator本质上是 Package Component
1.*ConcreteDecorator:ConcreteDecorator 只是将职责添加到原始的 Component。
现在让我们将这些概念Map到java.iopakge类。
InputStream:
这个抽象类是表示输入字节流的所有类的超类。
需要定义InputStream子类的应用程序必须始终提供返回输入的下一个字节的方法。
public abstract int read()
是一个抽象方法。FileInputStream:
FileInputStream从文件系统中的文件获取输入字节。哪些文件可用取决于主机环境。
FileInputStream用于阅读原始字节流,如图像数据。对于读取字符流,请考虑使用FileReader。
InputStream的所有ConcreteComponents示例:
FilterInputStream:
FilterInputStream包含一些其他输入流,它将其用作其基本数据源,可能会在此过程中转换数据或提供其他功能。
请注意
FilterInputStream
实现了InputStream
=〉*Decorator实现了UML图中所示的组件 *。BufferedInputStream
BufferedInputStream向另一个输入流添加功能-即缓冲输入以及支持mark和reset方法的能力。
所有 ConcreteDecorators 的示例:
工作示例代码:
我已经使用
BufferedInputStream
来读取一个单词的每个字符,这些字符存储在文本文件a.txt中何时使用此模式:
1.应该动态地添加/删除对象职责和行为
1.具体的实现应该与责任和行为脱钩
1.当动态添加/删除职责时,子类化的成本太高
byqmnocz3#
在.NET中,有一堆流装饰器,如BufferedStream,CryptoStream,GzipStream等。所有这些都装饰
Stream
类。zvms9eto4#
A -装饰器模式
A.1 -装饰器模式用例
装饰器模式用于在不改变遗留类的情况下扩展遗留功能。例如,我们有一个实现接口的具体类。但是我们需要扩展现有方法的功能,因为现有类及其方法已经被其他类使用,因此我们不想在现有类中进行更改。但是我们也需要在新类上扩展功能。那么我们怎么解决这个问题呢?
所以我们使用装饰器模式,将现有的类 Package 在装饰器中。
B -基础GoF装饰模式示例
这里我们有一个简单的接口和一个implementation/concrete类。接口有一个简单的方法,它是
getMessageOfTheDay
,它返回一个String
。假设有很多其他的类使用这个方法。所以如果我们想在implementation/concrete类中做一个改变,它会影响旧的遗留代码。我们只想为新的类改变它,所以我们使用装饰器模式。下面是一个Gang Of Four Decorator Design模式的小例子;
B.1 -Greeter.java
B.2 -BasicGreeter.java
B.3 -抽象装饰类:GreeterDecorator.java
B.4 -混凝土装饰类:StrangerDecorator.java
B.5 - Demo代码:java
看一下这些例子。需要抽象装饰器类来 Package 原始合约和实现。使用抽象装饰器,您可以创建新的多个装饰器,但在这个例子中,BasicGreeter被 Package 在抽象装饰器中,我们只创建了新的装饰器类StrangeGreeter。请注意装饰器类可以像火车一样使用。我们可以将一个装饰器 Package 在另一个装饰器中,或者 Package 在同一个装饰器中。2功能是可扩展的,但是原始的类被保留而没有任何修改。
C - OutputStream Demo
让我们来看看这个例子。我们想用OutputStream写一个字符串到file。下面是演示代码;
C.1 -OutputStream写文件示例
C.2 - JSON装饰器输出:normal.txt
将在项目文件夹下创建一个名为“normal.txt”的新文件,内容为:
D - JSON OutputStream Decorator Demo
现在,我想创建一个JSON Package 器格式,如下所示;
我想要的是把内容写在一个简单的一个字段JSON格式里面,怎么样才能达到这个目的呢?有很多琐碎的方法,不过我会使用 *GoF装饰器模式 *,写一个JSONDecorator,它扩展了Java的OutputStream类;
D.1 -输出流的JSON装饰器:JSONStream.java
D.2 - JSON Decorator演示:JSONDecoratorDemo.java
D.3 - JSON装饰器输出:json.txt
实际上,OutputStream本身就是一个装饰器模式,它是抽象的装饰器,这里的具体装饰器是JSONStream类。
mrphzbgm5#
当java.io您操作输入/输出流时,在www.example.com类中使用装饰器模式(同样适用于读取器和写入器)。
inputstream、bytearrayinputstream、stringbuilderinputstreams等都是based元素。Filterinputstream是decorator类的基类。过滤器输入流(如bufferedinputstream)可以在读取或写入流时做其他事情。
它们是通过封装流构建的,本身就是流。
我想不出在www.example.com中有任何类实现了这种模式java.net,但我想你已经被告知这个包,因为它与www.example.com紧密相连java.io(例如socket.getInputStream)。
实际上,这里有一个来自O 'Relly(pdf on uwosh.edu | archive.org,slides on slideshare.net)的课程,解释了如何在java.io中实现装饰器。
1szpjjfi6#
修饰输入/输出流的一种方法是对其应用压缩/解压缩。例如,参见
java.util.zip
中的类。这样的修饰流可以与“常规”输入/输出流完全相同的方式使用,压缩/解压缩完全透明地执行。r9f1avp57#
装饰器模式用于向现有对象(例如在库中定义的类)添加功能。然后您可以“装饰”它以满足您的需求。如果您有兴趣了解更多关于模式的信息,我推荐Gang of Four的“设计模式”。
p1tboqfb8#
好吧,我可能迟到了,但这个问题永远不会过时。理解Decorator的关键点是,它让你能够将一个对象插入到一个现有对象到另一个现有对象等等。在构造函数中实现这种模式很流行。例如,
如果你查看维基百科中的图表,你会看到 ConcreteComponent 和 Decorator 继承自同一个超类/接口 Component。也就是说,这两个类具有相同的实现方法。
然而,在 Decorator 类中,你会看到一个指向 Component 的箭头,这意味着你在 Decorator 类中的某个地方使用了 Component。在这种情况下,你在 Decorator 中使用了 Component 作为构造函数的数据类型。这是一个大技巧。没有这个技巧,你将无法将新对象插入到现有对象中。
之后,您可以创建继承 Decorator 类的子类。因为所有类都有相同的根,所以每个类都可以自由插入,没有任何顺序。