2017-04-22 59 views
7

从“头先:设计模式”书中的装饰模式用例使我有这个问题。我会尽力把它写下来:使用列表而不是装饰模式?

这是一个咖啡厅系统与一些咖啡和大量的调味品 你可以把它们(需支付额外费用),你需要能够订购 和为了避免产生总的混乱(例如布尔值来追踪 调味品),使用Decorator Pattern来装饰任何调味品的咖啡。我们有一个抽象的饮料 类,每种类型的咖啡,混凝土构件和各调味品 混凝土装饰包裹起来的饮料,如:

Beverage Class Diagram

因此,我们有以下过程返回咖啡成本:

Coffee Cost Delegation

我的问题是:为什么不使用列表,而不是装饰实现这个?我们可以在每个饮料中列出调味品列表,并通过遍历列表来计算成本。要订购的咖啡,我们就只需要一次实例并添加所需的调味品,避免类似的声明:

// Using second image example 
Beverage beverage = new DarkRoast(beverage); 
beverage = new Mocha(beverage); 
beverage = new Whip(beverage); 

此外,我们将有想放弃的折扣,咖啡不包括它的调味品操作更加灵活,一旦我们不会让装饰者包装咖啡。这是一个长期研究的问题,我知道我错过了一些东西,或者我错了,所以如果你对此有任何想法,我很想知道并进一步讨论它。

+0

这不是关于折扣或税款清单,您必须扣除或按成本添加。这是关于您使用装饰模式处理的行为。而且,相信我,用列表而不是继承来处理这些行为是很困难的。 – freedev

+0

你能用这个案例举个例子吗?或者可能是另一个随机情况我真的无法想象发生这种情况的情况。 – Paternostro

+4

这似乎是一个更好的[softwareengineering.stackexchange.com](https://softwareengineering.stackexchange.com)的问题。就我个人而言,我认为这是Decorator的一个可怕的用法(维基百科也有类似的例子,我认为),绝对可以用一个更易于管理的方式用列表解决。 'java.io.InputStream'是装饰器的一个例子,它运行良好。但是,您已经可以看到有一位用户不同意我的观点,这就是为什么这可能与SO无关。 – Radiodef

回答

1

您应该区分数据和行为。

装饰器是一个间接处理一个非常具体的问题层。数据(根据类型,合同,协议等)保持不变,但您在实施方面获得更多灵活性。使用装饰器,您可以重新使用现有功能并开始添加更改 - 与适配器配合使用后,您可以慢慢地从pone API迁移到其他适配器并保持兼容。

列表只应该负责以特定方式访问所包含的数据。对数据执行任务/处理列表中包含的数据应该由具有不同职责的函数/对象/类完成。

+0

最后一段对我来说没有意义。 _handling data_如何不在其上执行任务? –

+0

我有一点更具体。 –

1

您所讲的是一种计算饮料总成本的方法。更笼统地说,您提出了一种替代方法来合并&,通过将它们添加到列表中来执行Decorator模式假定的每个派生对象的主要行为。这也不是一个面向对象的方法。

但是Decorator Pattern的原意去了更广泛的视角,除此之外。它是动态添加扩展功能到对象。这意味着我有一些对象O1 &我希望它将其转换成另一个对象O2具有扩展功能&还没有那些2是可以互换的。

所以这是我们如何能够管理对象演进Object Lifecycle。希望你明白了。 :))

1

Decorator模式是关于在运行时使用附加功能装饰(增强)对象。

假设你已经有一个类,我们称之为A类,它实现了一个接口IA。现在,如果需要添加一个我们希望它有一个方法的附加功能,someAlignFeatureToA()这在A中不存在。现在您可以选择扩展类A。另一种方法是Composition,应该比Inheritance更受青睐。您可以将A类别的对象包装到另一个类别B中,并且AIA表示相同Interface。这种方式对于客户端代码来说很容易接受类B的对象,因为它具有与A相同的接口。(假设代码写得很好,取决于抽象(接口IA),而不是具体的类类别A)。

这样,继承链不会太长,您可以轻松地在runtimw中添加其他功能。