我已经对这种模式进行了研究,我仍然不确定为什么它比我稍后将描述的替代品好100%。我将讨论两种实现流的方法。就我而言,装饰图案和我的方法是同一枚硬币的两面。
我不会在这里描述装饰模式,因为我会假设对此答案感兴趣的人已经熟悉它。
另一种方法是使用列表。列表本质上是有序的,似乎做同样的事情。假设我们有一个输出流,我们将其包装在一个加密流中,我们将其压缩为一个压缩流。
OutputStream stream = new ZipStream(new EncryptStream(new OutputStream(outputLocation)));
stream.write(data);
替代方法是创建输出流,并为其添加拉链和加密器。
OutputStream stream = new OutputStream(outputLocation);
stream.add(new EncyrptStream());
stream.add(new ZipStream());
stream.write(data);
OutputStream.write的代码如下所示:
public void write(String data) {
for(StreamDecorator d : decorators) {
data = d.doMyThing(data);
}
//continue normal write operation
}
我是否正确地说这两种方法是同一枚硬币的两面?如果没有,装饰器模式在哪里比这种方法更有用?
答案 0 :(得分:3)
对我来说大致相同。在您的列表模式中,您最终会调用:
findAll
不同之处仅在于您将使用特定方法而不是构造函数,这在某些情况下可能更好。
答案 1 :(得分:3)
你的例子绕过很多东西。如果你看一下Java的流,你可以看到他们每个人都有一个责任。 FileOutputStream
知道如何将字节写入文件,SocketOutputStream
知道如何将字节写入套接字等。它们可以单独使用或与其他流一起使用,但它们“终止”,即字节不在你的处理之外。
您的Outputstream.write
没有描述“正常写入操作”是什么,但是使用您的列表方法,所有“终止”流都需要有StreamDecorators
列表和相同的代码迭代它们并处理数据。
虽然使用列表(因此成为Chain Of Responsibility)完全不可能这样做,但是作为装饰器做这件事要简单得多,因为类只需要做一件事。
答案 2 :(得分:1)
Kayaman提到了单一责任,但对我来说不仅仅是这个。
装饰器嵌套,这意味着在给定的嵌套级别,存在封装(以及随后的信息隐藏)。这意味着代码更能抵抗变化等。
可能有助于查看两种设计中的耦合:
在Decorator示例中,耦合仅转到单个组件(流包装的对象)。装饰器的目标是增强它包装的对象。它不知道该对象是什么,除了它尊重它可以包装的对象类型(例如,OutputStream
)。
在列表(带add()
)示例中,有更多耦合。流对象需要了解更多(并且可能有更多理由进行更改,重新单一责任)。 Stream必须担心它聚合的任何/所有事情的失败。
我认为如果你试图一直实现你的选择,你会发现它不像Decorator那么干净。正如另一个答案所示,你需要
zipStream.doMyThing(encryptStream.doMyThing(outputStream.doMyThing(data))));
我认为不能轻易编码(对于您的Stream中任意数量的装饰器add()
。)
另一点涉及类型和嵌套。由于类型/子类型可以在Decorator嵌套过程中使用,因此它应该防止不合逻辑的嵌套。目前尚不清楚add()
是否尊重这些打字规则,或者它必须受到更多限制。
如果您开始编写add()
规则的硬编码,最后会使用装饰器的组合类函数(请参阅https://stackoverflow.com/a/6366543/1168342中的计数器示例)。
答案 3 :(得分:0)
你的第一个选择不是“列表”,它是嵌套的构造函数。
无论如何,我认为第一种选择更有意义,因为你想要加密流,然后拉链。
第二种方法看起来就像是在单个流中添加两个流。在这种情况下,数据写在哪里?我想原来的<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<!-- Single menu item
Set id, icon and Title for each menu item
-->
<item android:id="@+id/menu1"
android:icon="@drawable/icon_menu1"
android:title="menu1" />
<item android:id="@+id/menu2"
android:icon="@drawable/icon_menu2"
android:title="menu2" />
.......
</menu>
。
答案 4 :(得分:0)
从功能的角度来看,正如其他人所说,它并不是那么不同。
但是,装饰器模式更好,因为它是已知的东西。因此,当您描述您的设计或将其记录给其他人时,您可以说&#34;并且我在这里使用了装饰模式&#34;。这比他们更简洁,更容易验证和#34;我在这里使用了一个List,在那里我添加了我想要调用的流,我按照这个顺序调用它们。这让我可以等等等等......&#34;
模式背后的所有概念已存在数十年;通过命名它们,我们可以更有效地传达有关概念和意图的信息。