有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java装饰器模式问题

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

地铁商店:

组件-->;次三明治

混凝土构件-->;15cmSub,30cmSub

装饰器-->;成分

混凝土装饰工-->;白奶酪,黄奶酪,果酱,鸡肉

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

  1. 如果成分组合无效怎么办?例如,地铁政策规定同一辆地铁里不能有两种奶酪。现在让我们想象一下,有10000种可能的配料组合,只有一种是无效的。这是否完全打破了装饰模式

  2. 如果有两种成分是相互依赖的呢。例如,如果您点的是莴苣,那么您需要一些其他种类的蔬菜来制作“有效”Sub.

  3. 什么时候使用decorator模式而不是带有成分数组列表的SubSandwich类更好?我知道这里的成分没有添加行为,这使得Subway示例不准确,但让我们假设它们添加了行为

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


共 (4) 个答案

  1. # 1 楼答案

    装饰器模式的意图和应用程序的意图不匹配。装饰器模式不适合您的用例

    enter image description here

    资料来源:https://en.wiki2.org/wiki/Decorator_pattern

    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

    在Decorator的意图中,您已经错过了“独立地”“这一点。若你们想建立相互关系或相互排斥,装饰师是并没有用的

    另一方面,Builder_pattern适合您的要求,因为您可以设置强制&;用于构建对象的可选参数

    您可以浏览以下问题:

    When would you use the Builder Pattern?

    Builder Pattern in Effective Java

  2. # 2 楼答案

    1. 模式并不适用于所有用例。decorator模式实际上对构建多组件结构没有多大用处,因为它将所有内容组合成一个对象,只有一个接口。这只适用于新行为仅仅是“装饰”的情况

      一个很好的例子是^{},它通过在所有方法周围包装synchronized块来“装饰”它们

      对于您描述的用例,您可能仍然可以使用装饰器,但是每个装饰步骤都必须检查是否可以应用,如果不可以,则抛出

      我真的不知道为什么这类例子如此流行。我从来没有见过像这样使用装饰图案。它不是为添加组件而设计的

    2. 见1。这甚至可能不可能,因为莴苣装饰者不能强制执行之后还有另一个装饰者。这显然不是对该模式的良好使用

    3. 如果你更喜欢它或者它更好用。比如三明治工厂

    4. 因为这是装饰师的把戏。它装饰现有事物的行为。您不想添加新接口。当你是中间人时,这一点很有用:

      例如,库A生成ListItem对象,您希望使用库B来显示它们。你既不能改变A生产什么,也不能改变B消费它们的方式。但是,当您不喜欢例如A如何实现B用于显示的toString()方法时,您可以简单地包装一个新的toString()方法。它仍然是aListItem,所以B不会注意到,就像a也不会注意到任何东西一样

  3. # 3 楼答案

    其原始结构中的模式无法解决任何实际问题。你需要把它们与一般的坚实原则结合起来。对于示例问题,您可以在装饰器之上实现构建器模式。你会有一些DSL类型的代码,例如

    Builder.aPizza().withCheeze(someCheeze).addTopping(someTopping).and(someOtherTopping).build();
    

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

  4. # 4 楼答案

    1. What if there is an invalid combination of ingredients? For example, Subway policy says that there can't be two kinds of cheeses in the same sub.

    那么装饰图案可能不是你想要的。Decorator是在不改变界面的情况下编写行为。这并不是关于连接属性,它也不能很好地实现这一点,因为用户(通常)只能直接使用最外层的装饰器实例。如果您需要知道SubWithProvolone是否包装了SubWithTurkey或任何其他特定类型的子对象,那么您就做错了

    我所知道的最好的例子是Java I/O类InputStreamOutputStreamReader、和Writer及其所有子类。任何InputStream都可以通过使用BufferedInputStream来进行缓冲;任何InputStream都可以通过用InputStreamReader装饰来用作Readeretc

    但是如果你开始加入一些规则,比如“一个BufferedWriter不能被另一个BufferedWriter装饰”(假设),那么它就会崩溃——没有好的方法来执行它,事实上,没有真正的需要这个规则。如果您试图对一种情况进行建模,而这种情况确实需要关于如何组合组件的规则,那么Decorator并不是一个很好的选择

    1. What if two ingredients are dependant. For example, if you order lettuce THEN you need some other kind of vegetable to make a "valid" Sub.

    这与#1基本上是同一个问题。您可能会拼凑一些东西来解决这个问题,以及前一个问题,但如果这些问题出现,那么Decorator就不适合这种情况

    1. When is it better to use the decorator pattern instead of a SubSandwich class with an ArrayList of Ingredient? I know here the Ingredients don't add behaviour, which makes the Subway example not accurate, but let's assume they do.

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

    1. Why extending? Why not using interfaces?

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

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