First we try, then we trust

  博客园 :: 首页 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::
  183 随笔 :: 111 文章 :: 2985 评论 :: 339 引用

终于有时间写点什么了,可以前酝酿好的东西似乎一下子都忘记了。这几天看了wayfarer的《《让僵冷的翅膀飞起来》系列之三——从Adapter模式到Decorator模式》后,感觉这样的文章真应当多发一些,激发思路。只是本来想用高级评论,却发现默认高级评论使用的是CuteEditor,在我的机器上根本无法使用,鼠标始终是沙漏(不知道是不是跟防火墙有关),而自己又无法选择使用什么编辑器编辑高级评论,所以才不得不写篇文章说说我的想法,看来又要有劳dudu了。

当初提出使用Decorator模式的是我,可现在提出异议的又是我,不要说我胡搅蛮缠,讨论中才能增长经验呀。wayfarer与idior的评论对我有很大启发,但我发现现在似乎有些问题没有定义清楚,导致在探讨解决办法时模棱两可。第一,原有设计是否不允许有任何变动。wayfarer的文章中,似乎默认是不允许对原有系统进行任何修改,而是通过增加新代码的方式提供新功能。否则以下的设计就应当能够解决问题了:

第二,新增加的Resize方法是否与RM或MPEG的具体实现纠缠不清。如果Resize的实现相对独立,只要针对抽象VideoMedia中的方法和属性就可以完成所有功能,那么使用Decorator模式无疑是个不错的选择,丑陋的"if (!(vedio is RM))"也可以不用出现在代码当中(具体可以参考wayfarer的原文)。设计如下:

因为SizeDecorator中的Resize方法只针对VideoMedia中的抽象方法执行操作,所以系统也就没有必要判断VideoMedia具体是RM还是MPEG,多态性自动替我们解决了这个问题。

但是,正如wayfarer和idior所说的,Decorator并不适合为一个对象添加新功能。否则当对一个VideoMedia应用多个Decorator时,从类型上讲用户只能看到最后一次Decorate时加入的新功能,以前的Decorator所起的作用被"屏蔽"了。

除此之外,如果Resize方法依赖于具体的VideoMedia类型,那恐怕带来的就是灾难了。因为在编写Resize方法时,必须清楚的知道你是对RM操作还是对MPEG操作,VideoMedia类型的_video也就形同虚设,丑陋的"if (!(vedio is RM))"也必不可免了。在这种情况下,还不如使用"类适配器模式"好(可以参考《《《让僵冷的翅膀飞起来》系列之二——从实例谈Adapter模式)。

第三,Visitor模式是否可行?其实,如果将条件限定为不允许改变任何原有代码的化,Visitor模式根本没有用武之地。因为Visitor模式象踢皮球一样需要一个"回传"功能,才能针对具体类型具体操作。可添加"回传(允许被Visit)"功能必须修改VideoMedia、RM与MPEG,这样就违反了规则。

所以,我们应将尽量"针对抽象编程"。这样可以防止Resize方法过分依赖于具体。否则,不管使用哪种模式,都会"牺牲"大量的代码。除此之外,当我们必须了解类型信息时,同时又要保证类型匹配(RMDecorator只能装饰RM)时,可以考虑使用抽象工厂(取其意),将RMDecorator、与RM认为是一个产品族。

另外,如果需要动态为现有对象添加多个方法时,是否可以考虑使用DynamicProxy,借助Mixin机制为一个类动态添加行为。但是我刚刚开始学习DynamicProxy、AOP和Mixin,感觉在需要我们了解具体类型后再进行操作的场合下,这些机制似乎帮不了什么太大的忙。如果有这方面的高手,还望指点一二。

posted on 2005-01-14 15:05 吕震宇 阅读(4261) 评论(8)  编辑 收藏 所属分类: 设计模式随笔系列

评论

#1楼  2005-01-14 17:31 idior [未注册用户]
visit模式的前提是要在原来的类中要有accept方法,这个个人觉得如果自己觉得初始定义不清楚的情况下,不妨留这么一个口子.

还有就是一个普遍的问题:
需要动态改变现有代码时采用什么办法?

这里可以深入研究下去,我个人就打算在考完试后研究研究

所涉及到的问题有:
1.通过不同的改变可以区分模式的种类,比如改变现有方法可以使用Decrator,添加新方法可以使用Adaptor,预留扩展又可以使用Visit
以及Bridge等等.

2.改变的方法,一种是oo的方法,partitial class是不是可以实现?
以及更加深入的DynamicProxy,和Aop的相关概念,这是一个比较复杂的问题.




  回复  引用    

#2楼  2005-01-14 17:33 idior [未注册用户]
如果有这方面的高手,还望指点一二。
同上
  回复  引用    

#3楼  2005-01-14 19:36 wayfarer      
Visitor模式,我正在写,不过前提就要变了,马上就可以写好了。

关于那个丑陋的if语句。对于Resize,是不需要的,如你所说,多态自动解决。但对于Play语句就必须了。因为,我的前提是不能改变Play的行为。如果不判断类型,那么本来是RM类型,可是你传递进来的确实MPEG,那就糟糕了,此时原本RM的Play就被你改成MPEG方法了。

所以,我才说if语句是无奈之举。归根结底,还是用类的Adaptor模式比较好。

但我在系列之二中,所举的例子其实并不能体现Adaptor模式的价值。我会在系列之五中,为媒体播放器引入收音机功能,来体现Adaptor模式的真正价值。

  回复  引用  查看    

#4楼 [楼主] 2005-01-15 11:30 吕震宇      
好,期待下一篇作品!
  回复  引用  查看    

#5楼  2005-01-17 16:10 baryon [未注册用户]
>>>但是,正如wayfarer和idior所说的,Decorator并不适合为一个对象添加新功能。否则当对一个VideoMedia应用多个Decorator时,从类型上讲用户只能看到最后一次Decorate时加入的新功能,以前的Decorator所起的作用被"屏蔽"了。

--------
I think that is not right.
you can read this article to understand it.
http://comcamp.myrice.com/techarticles/pattern/0002.htm

  回复  引用    

#6楼 [楼主] 2005-01-17 18:02 吕震宇      
@baryon

如果没有理解错的化,我想问题的焦点在于是否会出现"屏蔽"问题。在你所推荐的文章中,这种屏蔽似乎不存在,因为可以这样使用:

new CFlatIconButtonDecorator( new CEditDecorator( new CComboBoxTreeItem( ) ) ) ;

似乎得到的控件既可以有编辑框又可以有按钮。但是我还是坚持我的观点,理由如下:

1、在你给出的例子中,我没有看到任何新功能的添加。从UML图上看,不管是Edit还是Combox,还是其它的Decorator,都只有一个Operation方法。Decorator并没有添加任何的新方法,例如Click什么的。所以当然不会出现屏蔽问题。

2、为了增加Decorator的适用性,Decorator可以包含一个类型为CPropTreeItem的对象,而此对象仅仅定义了Operation方法。另外作为客户端CPropTreeControl也仅仅针对抽象编程,即CPropTreeItem,所以也只能看到Operation方法。任何新加入的方法若不经过类型转换就无法访问到。可一旦类型转换后,就犯了Decorator的忌讳。很难让下一个Decorator继续操作了。

不知道有没有写清楚。
  回复  引用  查看    

#7楼  2005-01-17 19:05 柳三公子      
就个人认为,Decorator中添加新功能不太明智。而且想解决这个“屏蔽”问题好像是没什么很好的方法的。
  回复  引用  查看    

#8楼  2006-11-14 10:49 小峰      
@idior

1.通过不同的改变可以区分模式的种类,比如改变现有方法可以使用Decrator,添加新方法可以使用Adaptor,预留扩展又可以使用Visit
以及Bridge等等.


学习
  回复  引用  查看    


标题  
姓名  
主页
Email (博主才能看到) 
验证码 *  看不清,换一张 [登录][注册]
内容(请不要发表任何与政治相关的内容)  
  登录  使用高级评论  新用户注册  返回页首  恢复上次提交      
该文被作者在 2005-01-14 15:17 编辑过
"五向定位"职业成长路线公开课(上海、南京、大连)
Google站内搜索


相关链接: