【问题标题】:Decorator Pattern: restrict wrapping装饰器模式:限制包装
【发布时间】:2011-03-23 16:56:14
【问题描述】:

TL;DR:
如何避免装饰链中某些类的重复?

加长版
我正在尝试实现Head First Design Patterns一书中描述的装饰器模式。他们举的例子是一家类似星巴克的咖啡店的收银机,里面的饮料和各种调味品都是等级的,系统的目的就是计算价格。

我从 iBeverage 接口开始,公开了公共方法 getName()getPrice()

iBeverage 的实现是各种饮料类(尽管有一个名为 Beverage 的共享基类;它们是 SlowDripCoffeeLatteCappuccino )和各种调味品。

调味品实现为iBeverageDecorators(扩展iBeverage 的接口)。在他们的构造函数中,他们接受一个 iBeverage 的实例,该实例存储在内部。对 getName() 和 getPrice() 的调用被实现为“在 child 上调用 getPrice(),添加自己的价格,返回值。”

如何制作高豆焦糖拿铁的示例:

 $drink = new SoyMilk(new CaramelSyrup(new Latte(Beverage::TALL)));
 $price = $drink->getPrice();`

我的问题:我如何限制 - 仅对于某些装饰器 - 它们最终进入调用堆栈的总次数?例如:如果商店想将糖浆限制为每种饮料三种,或者他们想确保员工在订单中只添加一种牛奶怎么办?

我的基本直觉是添加一些反射,以便在构建过程中我们可以检查整个对象图并确定它是否是装饰器的有效目标......这是正确的方法吗?或者我在这里应用的模式不适合这个任务?非常感谢任何建议。

这只是我打算让自己去做和发现的事情。

【问题讨论】:

  • 是的。因为有了这种设计,糖也将成为一种饮料。
  • 呵呵,我不同意,因为你不能点“糖”。你可以点的是一种含糖的饮料——因此它仍然是一种饮料。
  • 如果我正确理解了这个设计 - Sugar implements IBeverageDecoratorIBeverageDecorator extends IBeverage。因此,糖在这里是一种饮料。顺便说一句,我的观点是,饮料中调味品的简单聚合将轻松解决整个问题,无需所有这些模式(“饮料装饰器”,哦,我的),也无需做简单的事情(可选调味品限制,唯一性检查和调味品)兼容性检查等)。让我们也考虑一下 DB 表示 - Beverage "one-to-many" Condiment 很自然。

标签: oop decorator


【解决方案1】:

通常这应该是一个问题,您可以手动构建您的链(您对其进行硬编码),或者您有一个构建器将装饰器添加到您可以控制的链中。

我不会在装饰器类本身中为此添加任何代码,因为这样您就会将有关此的规则传播到各处,并使其不灵活且难以维护。

您使用的示例是关于能够应对变化的规则和成分。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2023-01-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-05-07
    • 2021-06-05
    • 1970-01-01
    相关资源
    最近更新 更多