享受代码,享受人生

SOA is an integration solution. SOA is message oriented first.
The Key character of SOA is loosely coupled. SOA is enriched
by creating composite apps.
posts - 207, comments - 2305, trackbacks - 146, articles - 44
  博客园 :: 首页 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理

用Visitor解决水果篮问题

Posted on 2005-06-15 17:13 idior 阅读(2300) 评论(17)  编辑 收藏 所属分类: Design
 

n久没更新blog(忙于考试), 今天看到Allen Lee的一篇随笔忍不住手痒.

具体问题的描述见Allen Lee的随笔.

下面给出我的方案.

1. 需要动态为类添加新的方法.

2. 有一个篮子.(objectstruct)

这两点显然符合了Visitor模式的应用背景.



 

先说一下用法:

如果你要为Apple添加新的行为 XXX.

       public static void Main(string[] args)
        {
            Apple apple = new Apple();
            Orange orange = new Orange();
            Banana banana = new Banana ();
            FruitBasket fb = new FruitBasket();
            fb.Add(apple);
            fb.Add(orange);
            fb.Add(banana);        

            fb.Accept(new XXXVisitor());       

         }

如果要为AppleOrange都添加Core(去核)的功能

fb.Accpet(new CoreVisitor());

所有新的功能无非是添加一个XXXVisitor,并在其中给予具体实现.

上层的结构不需要发生任何变化.

这里主要给出一个解决思路. 有关Visitor模式的介绍请见我以前的随笔.为什么会构造成这样你会从中找到答案.

下面简要给出一些代码:

  1 public abstract class Fruit

    2 {

    3     public void Print()

    4     {

    5     }

    6 

    7     public abstract void Accept(IFruitVisitor fv);

    8 }

    9 

   10 public class Apple : Fruit

   11 {

   12     public override void Accept(IFruitVisitor fv)

   13     {

   14         AppleVisitor av = fv as AppleVisitor; //need cast here

   15 

   16         if (av != null)

   17         {

   18             av.Visit(this);

   19         }

   20     }

   21 }

   22 

   23 public interface AppleVisitor

   24 {

   25     void Visit(Apple apple);

   26 }

   27 

   28 public class XXXVisitor : AppleVisitor, IFruitVisitor//想为谁添加功能就实现谁的visitor接口 

   29 {

   30     public void Visit(Apple n)

   31     {

   32         // TODO:  Add some unique method for apple here

   33     }

   34 

   35     //public void Visit(Orange e)

   36     //{

   37     //   // TODO:  Add some unique method for orange here

   38     //}

   39     //public void Visit(Banana g)

   40     //{

   41     //   // TODO:  Add some unique method for banana here

   42     //}

   43 }

   44 

   45 public class CoreVisitor : AppleVisitor, OrangeVisitor, IFruitVisitor

   46 {

   47    //同时为Apple 和Orange 添加去核的功能
   48     public void Visit(Apple n)

   49     {

   50         // TODO:  Add some core method for apple here

   51     }

   52 

   53     public void Visit(Orange e)

   54     {

   55         // TODO:  Add some core method for orange here

   56     }

   57 

   58     //public void Visit(Banana g)

   59     //{

   60     //   // TODO:  Add some unique method for banana here

   61     //}

   62 }

Feedback

#1楼    回复  引用    

2005-06-15 17:39 by tony [未注册用户]
用什么画的类图,看着这么爽

#2楼    回复  引用    

2005-06-15 17:42 by idior [未注册用户]
上面的两段乱码注释分别是:
L28 // 想为谁添加功能就实现谁的visitor接口
L47 //同时为Apple 和Orange 添加去核的功能

#3楼    回复  引用    

2005-06-16 02:14 by sigh [未注册用户]
vs.net 2005 b2

#4楼    回复  引用    

2005-06-16 08:02 by Ninputer [未注册用户]
这个和普通Visitor有一样的缺点,就是增加水果造成的代码修改量很大。

#5楼    回复  引用    

2005-06-16 09:35 by fadingflower [未注册用户]
这是Visitor模式本身的缺陷,你说的增加水果造成的代码修改是增多了,但是解决了由于水果中方法的动态增加的问题,这我觉得个人认为何者轻何者重了

#6楼    回复  引用    

2005-06-16 09:52 by idior [未注册用户]
新增水果的代码并不算大, 尤其重要的一点在于新增水果在这个设计中并不破坏原有的设计.而且如果新增水果不增加方法的话根本不增加任何代码.

#7楼    回复  引用  查看    

2005-06-16 10:36 by ZendyHu      
水果篮的这个问题的本质是什么??

本质就是,由第三方发起的行为呼叫。被呼叫者需要执行这个呼叫的具体实现... 但是呼叫又被分为不同种类的,被呼叫者可以相应某些呼叫,有些不能相应某些呼叫。 从本质上说,这就是先订约,后被呼叫的逻辑。每种呼叫就是每个事件的触发,所以用简单的 事件模式就可以实现.而C#的Delegate 是对事件模式的纯技术升华的高级产物。

于是问题就归结为:水果篮有削皮的事件,去核的事件...添加水果到水果篮的时候,只要让水果自己把自己的特色行为挂接到水果篮的哪个事件中就可以了,就这么简单........(当然也可以把这个挂接操作有一个专门的Control类来实现,这样水果就不用认识水果篮了,达到了降低关联性的目的)


从实用性来看,通过Delegate,可以达到代码的可维护性和可扩展性...

#8楼    回复  引用    

2005-06-16 11:13 by idior [未注册用户]
delegate 的层次太低 仅仅是函数级的复用 而且delegate仅限于.net.
delegate的优点是灵活方便.
这里visitor达到的是类级的复用.
在dp中有很多这样的体现.
stratage commander bridge more and more.
他们都是将一个方法包装为一个对象, 从而大大提高了复用性.

#9楼    回复  引用  查看    

2005-06-16 11:20 by ZendyHu      
To idior :

delegate 的层次太低是指什么层次,技术?

你所指的复用是指希望复用什么?能达到什么目的呢?




#10楼    回复  引用    

2005-06-16 12:46 by idior [未注册用户]
简而言之 就是你需要为delegate指定一个对象的方法。
而不是指定一个对象就可以。
层次低 是因为它是函数级的。

如果你能理解这些模式的话,就会明白我的意思。
stratage commander bridge more and more.

#11楼    回复  引用    

2005-06-16 12:49 by idior [未注册用户]
看看这段代码:
fb.Accept(new XXXVisitor());
新增功能就在XXXVisitor中,是以类为级别的复用。

#12楼    回复  引用  查看    

2005-06-16 13:02 by ZendyHu      
照你的逻辑,以后我们就要抛弃事件机制,因为它引用的只是一个对象的方法 或者纯粹一个静态方法.

照你的逻辑,以后每个事件声明,都需要声明一个接口了

说句冒犯的话:
你严重玷污了delegate设计思想,它的思想本质是:把动作行为和对象主体 完全的解偶...。也就是说delegate只关心动作本身,不关心动作的对象主体是什么。
想一下,你做的Visitor,是不是相当于一个delegate?有了Visitor,重用在哪里?只是多了Fruit和IFruitVisitor的关联而已。
请看我刚刚写的这篇文章:http://www.cnblogs.com/caomao/archive/2005/06/16/175339.html

#13楼 [楼主]   回复  引用  查看    

2005-06-16 15:36 by idior      
我不指望所有人能理解我的解决方案.但是有关delegate我的理解不会比你浅.

http://www.cnblogs.com/idior/archive/2005/02/03/101510.aspx

http://www.cnblogs.com/idior/archive/2005/04/25/144573.html

http://www.cnblogs.com/idior/articles/100666.html

#14楼    回复  引用  查看    

2005-07-29 17:34 by 吕震宇      
不错的思路,但是感觉仍然有坏味道需要处理一下。

问题出在XXXVisitor上面。在你的设计中,不同的访问策略对应不同的类XXXVisitor,而该XXXVisitor根据策略实现不同的接口。但是问题在于你永远无法预知所有客户提出的访问要求,可能只处理苹果,也可能只处理桔子,也可能苹果桔子一起处理....如此一来,该设计将造成XXXVisitor类的急剧膨胀(排列组合可以算出来)。

时间原因,无法仔细设计解决办法。思考中...

#15楼    回复  引用  查看    

2005-07-30 09:40 by 吕震宇      
整理思路后,发现和Allen Lee随笔中HolyFire的回复不谋而合。我比较赞同HolyFire的做法。另外,感觉如果能借助Spring.net的威力通过XML配置文件实现自由组合Job及其顺序应当更灵活一些。

#16楼 [楼主]   回复  引用  查看    

2005-07-30 10:50 by idior      
吕兄很久没有更新了啊.

#17楼    回复  引用  查看    

2005-11-29 14:11 by 玉开      
感觉visitor不太适合做这件事,因为水果篮中的问题中水果是不定的,随时可能加入新的水果,使用visitor必然会改变已有的visitor,违背了ocp呀。

不好意思,班门弄斧,我没有更好的观点,思考中.......

标题  
姓名  
主页
Email (博主才能看到) 
验证码 *  看不清,换一张 [登录][注册]
内容(请不要发表任何与政治相关的内容)  
  登录  使用高级评论  新用户注册  返回页首  恢复上次提交      
该文被作者在 2006-09-07 16:55 编辑过


相关链接: