首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >装饰图案问题

装饰图案问题
EN

Stack Overflow用户
提问于 2016-06-05 16:31:32
回答 4查看 1K关注 0票数 2

最近,我读到了关于装饰设计模式的文章,但是留下了一些我在网上找不到的未回答的问题。我不打算显示代码,因为我不想让这个问题变得比实际更复杂。我只举一个例子:

地铁商店:

组件--> SubSandwich

ConcreteComponent ->15 15cmSub,30 15cmSub

装饰器->成分

ConcreteDecorator ->白奶酪,黄奶酪,果酱,鸡肉。

这就是地铁商店的工作方式。选择你的核心砂子大小,然后添加所有你喜欢的配料。但我还有一些问题:

  1. 如果成分组合无效怎么办?例如,地铁的政策说,不可能有两种奶酪在同一潜艇。现在,让我们假设有10000种可能的组合,而只有一个是无效的。这完全打破了装饰的模式吗?
  2. 如果有两种成分是依赖的。例如,如果你点了生菜,那么你需要一些其他种类的蔬菜来做一个“有效”的子菜。
  3. 什么时候使用装饰模式比使用成分为SubSandwich的ArrayList类更好呢?我知道这里的成分并没有增加行为,这使得地铁的例子不准确,但让我们假设它们确实如此。
  4. 为什么要扩展?为什么不使用接口呢?
EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2016-06-05 17:24:51

  1. 如果成分组合无效怎么办?例如,地铁的政策说,不可能有两种奶酪在同一潜艇。

那么装饰模式可能不是你要找的东西。修饰器是指在不改变界面的情况下进行合成行为。它不是关于连接属性,而且它不能很好地工作,因为只有最外层的装饰实例(通常)可以直接提供给用户。如果您需要知道SubWithProvolone是否包装了SubWithTurkey --或者其他特定类型的子包--那么您就做错了。

我所知道的最好的示例是Java /O类InputStreamOutputStreamReaderWriter及其所有子类。任何InputStream都可以通过装饰BufferedInputStream来缓冲;任何InputStream都可以用InputStreamReader装饰成Reader;等等。

但是,如果你开始加入规则,比如“BufferedWriter不能被另一个BufferedWriter修饰”(假设的),那么它就会崩溃--只是没有好的方法来执行它,而且实际上,对该规则没有真正的需要。如果您试图对这样的情况进行建模,对于如何组合组件这样的规则是真正需要的,那么Decorator并不是一个很好的匹配。

  1. 如果有两种成分是依赖的。例如,如果你点了生菜,那么你需要一些其他种类的蔬菜来做一个“有效”的子菜。

这与#1的问题本质上是一样的,你也许可以一起解决这个问题和前一个问题,但是如果这些问题本身就出现了,那么Decorator就不适合这种情况了。

  1. 什么时候使用装饰模式比使用成分为SubSandwich的ArrayList类更好呢?我知道这里的成分并没有增加行为,这使得地铁的例子不准确,但让我们假设它们确实如此。

你问题的其他方面有点宽泛,但这个问题太宽泛了。我们回答有关编程细节的具体问题。

  1. 为什么要扩展?为什么不使用接口呢?

你问的是错误的二分法。Java区分接口和纯抽象类是一种肤浅的语言设计细节,主要用于支持Java对实现的单个继承的限制。如果您的问题被重定向到C++,那么接口和纯粹的抽象类之间并没有很大的差别,而设计模式也同样适用于这些类。您可以围绕作为Java接口的基本类型实现Decorator模式。

尽管如此,我前面提到的Java I/O类确实使用了类而不是接口。有优点也有缺点,但优点之一是它允许他们使用模板方法模式来提供更容易实现的具体实现类。然而,即使在那里,也可以为此目的提供抽象基类,即使装饰器类型被声明为接口。

票数 1
EN

Stack Overflow用户

发布于 2016-06-05 16:53:05

其原有结构中的模式并没有解决任何实际问题。你需要把它们和一般的坚实的原则结合起来。对于示例问题,可以在Decorator之上实现Builder模式。你会有一些DSL类型的代码。

代码语言:javascript
运行
复制
Builder.aPizza().withCheeze(someCheeze).addTopping(someTopping).and(someOtherTopping).build();

使用这种模式/样式,您可以验证对象的中间状态,甚至可以在调用build()方法的最后阶段验证。

票数 4
EN

Stack Overflow用户

发布于 2016-06-05 17:04:03

  1. 模式并不适用于每个用例。实际上,装饰器模式对于构建一个多组分结构并没有多大用处,因为它将所有的东西组合成一个只有一个接口的对象。只有在新的行为仅仅是“装饰”的情况下,这种做法才能奏效。 一个很好的例子是Collections.synchronizedList(List list),它通过包装一个synchronized块来“装饰”所有方法。 您可能仍然可以在您描述的用例中使用一个装饰器,但是每个装饰步骤都必须检查它是否可以应用,如果不是,则抛出。 老实说,我甚至不知道为什么这类例子如此受欢迎。我还没见过像这样的装饰图案。它不是为添加组件而制作的。
  2. 请参见1。这甚至可能是不可能的,因为生菜装饰师不能强制之后还有另一个装饰师。这显然不是一个好的模式使用。
  3. 在你更喜欢或者更好的情况下。就像三明治工厂。
  4. 因为这就是装潢师的诀窍。它装饰着现存事物的行为。您不想添加新的界面。一个有用的地方是当你是中间人的时候: 例如,库A生成ListItem对象,您希望使用库B来显示它们。你既不能改变A生产什么,也不能改变B消耗它们的方式。但是,当您不喜欢A如何实现B用来显示的toString()方法时,您可以简单地包装一个新的toString()方法。它仍然是一个ListItem,所以B不会注意到,就像A也没有注意到任何东西一样。
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/37644223

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档