【发布时间】:2011-03-23 16:56:14
【问题描述】:
TL;DR:
如何避免装饰链中某些类的重复?
加长版
我正在尝试实现Head First Design Patterns一书中描述的装饰器模式。他们举的例子是一家类似星巴克的咖啡店的收银机,里面的饮料和各种调味品都是等级的,系统的目的就是计算价格。
我从 iBeverage 接口开始,公开了公共方法 getName() 和 getPrice()。
iBeverage 的实现是各种饮料类(尽管有一个名为 Beverage 的共享基类;它们是 SlowDripCoffee、Latte 和 Cappuccino )和各种调味品。
调味品实现为iBeverageDecorators(扩展iBeverage 的接口)。在他们的构造函数中,他们接受一个 iBeverage 的实例,该实例存储在内部。对 getName() 和 getPrice() 的调用被实现为“在 child 上调用 getPrice(),添加自己的价格,返回值。”
如何制作高豆焦糖拿铁的示例:
$drink = new SoyMilk(new CaramelSyrup(new Latte(Beverage::TALL)));
$price = $drink->getPrice();`
我的问题:我如何限制 - 仅对于某些装饰器 - 它们最终进入调用堆栈的总次数?例如:如果商店想将糖浆限制为每种饮料三种,或者他们想确保员工在订单中只添加一种牛奶怎么办?
我的基本直觉是添加一些反射,以便在构建过程中我们可以检查整个对象图并确定它是否是装饰器的有效目标......这是正确的方法吗?或者我在这里应用的模式不适合这个任务?非常感谢任何建议。
这只是我打算让自己去做和发现的事情。
【问题讨论】:
-
是的。因为有了这种设计,糖也将成为一种饮料。
-
呵呵,我不同意,因为你不能点“糖”。你可以点的是一种含糖的饮料——因此它仍然是一种饮料。
-
如果我正确理解了这个设计 -
Sugar implements IBeverageDecorator和IBeverageDecorator extends IBeverage。因此,糖在这里是一种饮料。顺便说一句,我的观点是,饮料中调味品的简单聚合将轻松解决整个问题,无需所有这些模式(“饮料装饰器”,哦,我的),也无需做简单的事情(可选调味品限制,唯一性检查和调味品)兼容性检查等)。让我们也考虑一下 DB 表示 -Beverage "one-to-many" Condiment很自然。