Double dispatch and Visitor patterns

      惯例, 先帖参考[1][2][3][4].

      记得第一次看<Design Patterns>的时候, 被类与类之间的引用调用设计弄得不是一般的糊涂. 很多情况下是你引用我, 我引用他, 他调用你... 最后总结出一条正确且无聊的规律: 给我你的引用, 我就能完全控制你...

      2年后...

      设计的一个原则就是封装变化. 所以为了应对访问方式的多样化, 我们封装了对对象的访问方式(Object.Accept(Visitor)). 很多问题, 都有它的本质, 即便是一类问题的解决方案, 也许也只是解决范围内的冰山一角. [2],[3]都对Visitor做了较深的挖掘, 可以看出, visitor pattern某种程度上来说仅仅是Double dispatch的子集.

      为了封装变化, 现在的主宰方式当然是类化, 调用虚方法; 子类化, 重载虚方法, 注入新类. 典型情况下, 如果我们的设计比较符合Liskov Substitution Principle,

那么类似下面的方法形式我们是可以接受的, 88%的问题也可以通过这种方式解决. 

 

public void DoSome(IProcess iPos)
{
    iPos.StepOne();
    
this.FollowOne();
    iPos.StepTwo();
    
this.FollowTwo();
    
    iPos.StepLastStepNine();
}

      这样的设计虽然通过每一个子方法的合适重载版本, 可以得到符合设计的整体逻辑, 但是, 这样其实存在调用框架的限制, 类似于Template pattern. 只有在抽象足够得体的情况下(框架稳定), 才能很好的满足诡异的变化.

      假如存在这样的需求, 当X情况下, 我们需要参数和本类的一种协作, 在XX情况下, 需要另外一种完全不同的协作方式... 即, 在不同的前提情况, 我们不能取得一致的抽象框架. 这时候, 我们可以考虑使用double dispatch:

 

interface IProcess
{
    
void StepOne();
    
void StepTwo();
    
    
void StepTen();
    
    
void Execute(MainCls);
}

class ProcessOne : IProcess
{
    

    
public void Execute(MainCls mCls)
    {
        StepOne();
        mCls.FollowTwo();
    }
}

class ProcessTwo : IProcess
{
     
    
    
public void Execute(MainCls mCls)
    {
        mCls.FollowOne();
        StepTen();
        
    }
}


class MainCls
{
    
public void DoSome(IProcess iPos)
    {
        iPos.Execute(
this);
    }
}

      Double dispatch, 顾名, 我们把调用作了再一次的dispatch, dispatch到了参数方法调用中.

      显而易见, 这样的做法最大的缺点就是参数类耦合了调用类. 在iPos.Execute(this)中, 对于iPos的Execute方法, 当然可以应用重载机制, 但Execute(this)对于方法参数的匹配应用的却是方法复写机制, 所以想提取MainCls到接口参数来解除依赖, 需要多考虑是否合理. 这样做法的最大优点就是调用类完全不依赖于参数类型, 方便调用方法的逻辑变化.

      另, [2]很值得一读.

 

-----------------------------------------

Ref:

[1], http://msdn.microsoft.com/en-us/magazine/cc546578.aspx

[2], http://www.cnblogs.com/idior/articles/325036.html

[3], http://blog.csdn.net/chaocai2004/archive/2009/02/19/3911753.aspx

[4], http://www.garyshort.org/blog/archive/2008/02/11/double-dispatch-pattern.aspx

 

posted @ 2009-07-02 17:41  Tyrael  阅读(252)  评论(0编辑  收藏  举报