作者FTM (....)
看板OOAD
标题Re: [模式] 装饰者模式(decorator)只有一种结构吗?
时间Mon Jan 14 17:15:32 2013
或许回归到 Decorator Pattern 的 Intent 来看会较清楚
Intent of Decorator (from GoF Book):
Attach additional responsibility to an object dynamically.
Decorators provide a flexible alternative to subclassing for
extending functionality.
由上得知, 使用 Decortor 所欲表达物件关系/行为是:
* 系统中有一种特殊的 Object, 姑且称之为 Component
* Component 常常有额外附加 responsibility 的需要
* 额外附加 responsibility 的动作需要能动态给定
(因此直接 subclassing 并不适宜)
有了以上理解後, 再回头看看 Decorator 结构上的两个重点
1. Decorator
decorates (as an aggregation) a Component
Decorator 包装了 component, 透过这层包装
Decorator 可在正式将责任交付给 component 之前(或之後)
额外进行所欲附加的行为
2. Decorator
is a Component
为了确保 Client 仍可正常使用 "包装" 後的 Component
Decorator 必须也符合 Component 所制定的 Interface
这可透过 Inheritance 达成 (Decorator extends Component)
-----------------------------------------------------------------------
最後, 原 Po 的例子中
使用 Component aggregate a list of Decorator 的形式来表达此一关系
并使用 Iteation 的方式来执行附加的 responsibility
在此例中似乎是 OK 的, 但回归到 Decorator 的 Intent, 有两点关键不同
1. 附加 Responsibility 的弹性
在原 Po 例子中, 主餐 (Component) 决定了"如何附加 Responsibility"
(使用 Iteration)
这限制了附加 Responsibility 的弹性
使用 Decorator Pattern 时
"如何附加 Responsibility" 完全由 Decorator 透过 override 决定
2. Component 的实做不会因为 Decorator 的采用而有所改变
在原 Po 例子中, 需要修改 "主餐 Class" 才能完成欲达成目标
但使用 Decorator Pattern
完全不用 修改 "主餐 Class" (Component)
即可达到为 Component 动态附加 Responsibility 的果效.
--
我个人的感觉是
此例似乎无法很自然的与 Decorator Pattern 的 Intent 呼应
所以可能会有许多 Alternative Design 的想像空间
我建议参考 GoF Book 中例子, 或许会有更深的体会
※ 引述《worldxxi ()》之铭言:
: 谢谢q大的回覆,但是我还是不太懂,先说一下,我并没有一定要说我的想法
: 比较好,只是想了解一下差异,在您比较两者差异的时候我的想法被当作
: 不能有输入,似乎不太公平,如果要比较应该有同样的立足点,同时,我修改class名称
: 让它看起来比较舒服,我直接修改在下面(引文中修改)。
: P.S.
: 会一直有疑问是因为我总觉得,两者的结构是完全等价的,但是可以用多型解决的问题
: 以那麽多前人的经验不可能硬要弄出新的pattern,所以somehow我的想法一定有缺陷无法
: 应付变动,而我就是想要知道那个问题是什麽?
: ※ 引述《qrtt1 (有些事,有时候。。。)》之铭言:
: price=130;
: foreach(decorator in list){
: price = decorator.cost(price);
: }
: return price;
: abstract class Decorator
: class 味增汤 : Decorator
: //handle price
: return newPrice;
: //实际使用长成这样
: main(){
: unDecorator = new 某主餐();
: unDecorator.addDecorator(new 味增汤);
: unDecorator.addDecorator(new 优惠时段);
: : 我想这世上没有一定得用什麽样的解法的规则。
: : 学习这些『前人』设计上的经验,
: : 只是辅助我们在遇到问题时多一个选项可以考虑。
: : 依你的想法修改後,问题的复杂点会集中到每一个
: : ConcreteComponent 的 behavior,
: : 也就是 猪排.cost();
: : 现在你想得只是单纯的『加法』将 list 内的副餐『加』起来那麽单纯。
: : 如果出现了例外的情况,例如:麦当当晚间,二人同行第二套半价。
: : 虽然这个 bussiness logic 不是一种『餐』,
: : 但毫无疑问的,它的责任落在 cost mehtod!
: //ConcreteComponent不动(我的表达不好,这其实是我原本的意思)
: public int cost() {
: price = 130;
: foreach(decorator in list){
: price = decorator.cost(price);
: }
: return price;
: }
: //假设有两个Decorator装饰,先用味增汤装饰,再用优惠装饰
: //味增汤的cost
: public int cost(price){
: //传进来的price现在是130
: return price + 20;
: }
: //优惠的cost
: public int cost(price){
: //传进来的price现在是150
: return price * 0.5;
: }
: 所以并不会有因为不同情况或需求,导致所有事情的责任都落在
: ConcreteComponent的cost上面。
: 我会说等价的原因是因为在直观上:
: 1. 不停用new包装的过程等於就是让我想法中的decorator list不断增加
: 2. Decorator Pattern在呼叫cost时,是利用继承架构得知目前要呼叫的
: 实际上是哪个cost,而我的想法只是明确的指出是谁做。
: : 当你有多种 ConcreteComponent 要套新的规则时,
: : 你都得针对每一个 ConcreteCompoent 去修改它。
: : 用 Decorator 你就用装饰的角度来看它:
: : 餐点 = new 优惠时段的(new 含泡菜的(new 含味噌汤的(new 排餐主餐())))
: : 结帐金额 = 餐点.cost()
: : 对整体来说,只要各别维护不同餐点的单价,与优惠策略的选择:
: : *. 早餐优惠
: : *. 晚餐优惠
: : *. 寿星优惠
: : *. VIP 优惠
: : *. 消费总金额优惠
: : *. 组合套餐优惠
: : 动态地多 wrapper 一层上去,维护范围相较起来单纯,
: : 会改到的是各别的装饰者、实体、最终结帐的 caller。
: : 整体来说,这比较符合 OCP 原则。
: : 学习 design pattern 单纯看结构可能没 fu,
: : 但代入了『改变』後,
: : 评估怎麽做对『既有』程式影响最小
: : 才是我们希望得到的。
: : 其它参考文章:
: : http://webptt.com/cn.aspx?n=bbs/java/M.1243696485.A.DD1.html
--
※ 发信站: 批踢踢实业坊(ptt.cc)
◆ From: 140.116.72.58
※ 编辑: FTM 来自: 140.116.72.58 (01/14 17:17)
1F:推 worldxxi :感谢mars90226, qrtt1, FTM,我想我可能真的需要看 01/14 17:33
2F:→ worldxxi :GoF的书才能理解 F大的解释让我好像有点感觉但又很 01/14 17:37
3F:→ worldxxi :很模糊 我试试看研究StreamDecorator的例子 01/14 17:42
4F:→ worldxxi :我好像找到我卡住的点了 就是我的例子中Decorator只 01/14 17:45
5F:→ worldxxi :用到price,如果功能上差异很大就必须动到Component 01/14 17:47
6F:→ worldxxi :增加Decorator才会用到的member 01/14 17:50
7F:→ qrtt1 :很好的切入点,希望 worldxxi 早日打通盲点 :) 01/14 18:06
8F:→ qrtt1 :上班後累了,如果有闲。假日再继续讨论orz 01/14 18:07
9F:推 LUCENE :推~ 05/14 12:57