星辰.Net技术社区论坛

首页 » .NET » 设计模式GOF » Double Dispatch And Visitor Pattern
admin - 2008-6-26 15:04:00
1 Override VS. OverloadíS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
多态可以说是面向对象世界中一件锋利的武器, 封装变化是它的能力的体现。但是你听说过几种多态?íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
Simple Polymorphism the object whose method is called is decided run-time.íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
    multi- polymorphism the object which method is called íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
is decided upon the type of the argument
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi

íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
如果你对这两句描述不是很清楚, 那你知道overrideoverload吗?Simple Polymorphism 就意味使用了override, multi- polymorphism则意味着使用了overload

íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi

前者可能你比较熟悉,后者呢?两者又有什么不同?什么情况下我们会需要后者呢?你见过它们同时出现吗?

íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi

多态是用于封装变化的,比如常见的那个ShapeíS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
Draw的例子。Client不用考虑具体是哪个Shape,通过多态自然能调用到相应的那个ShapeDraw方法(whose method)。但是这时我们只有一个变化的对象――Shape 如果画的地方也变呢?比如我可以画在屏幕上, 也可以画到打印机上。现在我们有两个同时会变的因素, 那么Draw方法又通过什么来实现封装变化呢? Simple Polymorphism 显然是不够用了,multi- polymorphism 自然也该出场了。

íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi

就从一个游戏开始吧,在这个游戏中有一个怪物开门的场景。怪物有很多种,本游戏的出场人物包括了矮人和泰坦,门也有两种 :一种普通的木头门, 还有就是很重的铁门。

íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi

现在怪物和门登场了

íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi

interface Monster {}

íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi

íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
class Drawf : Monster {}

íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi

íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
class Giant : Monster {}íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
class DooríS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
{íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
public virtual void OpenBy(Monster monster)íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
{íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
Console.WriteLine("Who are u?");íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
}íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
public virtual void OpenBy(Drawf dwarf)íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
{íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
Console.WriteLine("It's slowly opened");íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
}

íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi

íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
public virtual void OpenBy(Giant giant)íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
{íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
Console.WriteLine("It's just easily broken...Crasp!");íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
}íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
}

íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi

íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
class HeavyDoor : DooríS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
{íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
public override void OpenBy(Drawf dwarf)íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
{íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
Console.WriteLine("It won't open");íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
}

íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi

íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
public override void OpenBy(Giant giant)íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
{íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
Console.WriteLine("It's slowly opened");íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
}íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
    }

íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi

这里为了同时封装两种变化(怪物和门),我也同时使用了override overloadíS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi

íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi

接着怪物开始开门了

íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi

íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
class GameíS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
{íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
static void Main()íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
{íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
Door ironDoor = new HeavyDoor();íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
ironDoor.OpenBy(new Drawf());íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
ironDoor.OpenBy(new Giant());íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
        }íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
    }

íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi

íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
答案也很明显

íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi

íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi

这个例子同时应用了两种多态,íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
但是却只体现了第一种多态封装变化的效果!如何将两者都体现出来?看下面的测试

íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi

class GameíS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
{íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
static void Main()íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
{

íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi

íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
Door ironDoor = new HeavyDoor();íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
List<Monster> monsters = new List<Monster>();íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
monsters.Add(new Drawf());íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
monsters.Add(new Giant());

íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi

íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
foreach (Monster m in monsters)íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
ironDoor.OpenBy(m);íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
}íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
}

íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi

现在你能猜到结果吗?仔细想想别急着看答案

íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi

íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi

íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
很正常?Ok. 你可以直接去看下一节的内容了,如果猜错了请先复习一下下面的基础知识吧.

íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
你肯定听说过所谓的动态绑定,通常意义上的多态也就是通过它实现的,简而言之――the object whose method is called is decided run-time . 重点就在于这个run-time . 而第二种多态――the object which method is called íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
is decided upon the type of the argument
这里面可没有出现run-time 倒不是说它不支持,而是不一定,不过在c++, javac# 中都不支持。 现在你可以理解为什么前面的答案出乎你的意料了。因为后者方法是静态绑定的, 也就是在编译期就确定了将要执行哪个Draw方法,而在编译期,编译器显然只能将monsters集合中的对象判断为Monster类型,从而去执行 void OpenBy(Monster monster)方法。íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
2 Visitor Pattern without Double DispatchíS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi

íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi

íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi

íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
通过上一节的例子和解释, 你应该对override, overload 以及他们各自的绑定机制――动态绑定和静态绑定有所了解。

íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi

íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
接下来看一个更具实际意义的例子。假设我想做一个计算器,那么肯定要先建立一个表达式系统。

íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi

abstract class ExpressioníS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
{íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
public abstract int Evaluate();íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
}

íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi

íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
class ConstantExpression : ExpressioníS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
{
      íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
        int constant;íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
public override int Evaluate()íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
{íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
return constant;íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
}íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
}

íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi

íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
class SumExpression : ExpressioníS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
{íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
Expression left, right;íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
public override int Evaluate()íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
{íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
return left.Evaluate() + right.Evaluate();íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
}íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
    }

íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi

这里利用多态很好的实现了表达式计算的任务但是把计算的功能放在表达式中并不是一个良好的设计,随着表达式的类型越来越复杂,可能我们需要对表达式进行语法分析,进行类型检查, 设置判断表达式中有多少个常量,多少个变量。如果把这些功能都放在表达式中,一方面不符合责任分离的原则,二来一旦有了新的功能需求我们就要修改所有的表达式对象,维护的恶梦就这样开始了。

íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi

íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
于是我就想到了用Visitor模式将计算的功能从Express类中分离出来。(将过多没有密切联系的功能从原来的对象中脱离出来,避免对象过于庞大,这是使用Visitor模式的最重要的原因)。下面是代码实现,请耐心看完。íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi

íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi

abstract class Expression { }

íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi

íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
class ConstantExpression : ExpressioníS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
{íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
private int constant;íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
public int ConstantíS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
{íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
get { return constant; }íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
}

íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi

íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
public ConstantExpression(int con)íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
{íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
constant = con;íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
}íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
}

íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi

íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
class SumExpression : ExpressioníS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
{íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
private Expression left, right;íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
public Expression RightíS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
{íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
get { return right; }íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
}íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
public Expression LeftíS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
{íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
get { return left; }íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
}

íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi

íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
public SumExpression(Expression left, Expression right)íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
{íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
this.left = left;íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
this.right = right;íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
}íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
}íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
class EvaluateVisitoríS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
{íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
public int Visit(ConstantExpression e)íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
{íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
return e.Constant;íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
}íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
public int Visit(SumExpression e)íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
{íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
return Visit(e.Left) + Visit(e.Right);íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
}íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
}

íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi

íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
class ProgramíS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
{íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
static void Main()íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
{íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
ConstantExpression constExp = new ConstantExpression(10);
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
SumExpression sumExp = new SumExpression(new ConstantExpression(1),íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
new ConstantExpression(1));

íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi

íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
EvaluateVisitor evalVisitor = new EvaluateVisitor();íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
Console.WriteLine(evalVisitor.Visit(constExp));íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
Console.WriteLine(evalVisitor.Visit(sumExp));íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
}íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
    }íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi

íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi

看完上面的代码,可能很多人会有疑问了。 你这里用的是什么Visitor模式?Accept方法呢?IVisitor接口呢? 怎么Visit方法还有返回值?怎么和《Design Pattern》上的Visitor模式完全不是一回事?

íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi

为什么要和书上的一样呢?你难道没发现以上的疑问都体现了这个版本的优点?没有Accpet方法意味着在最初的设计中我根本不需要为以后是否需要使用Visitor模式做考虑。没有IVisitor接口,意味着我可以随意的定义我的Visit方法,而不需要一个统一的形式,比如这里为了计算方便我让Visit方法有了返回值。既然这个版本的Visitor模式这么好,怎么Gof没有想到? 呵呵,露馅了,因为上面的代码根本无法通过编译íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi

íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi

íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
class EvaluateVisitoríS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
{íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
public int Visit(ConstantExpression e)íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
{íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
return e.Constant;íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
}íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
public int Visit(SumExpression e)íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
{íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
return Visit(e.Left) + Visit(e.Right);íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
}íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
    }

íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi

联系第一节介绍的内容,你就会发现尽管e.Left在运行期是ConstantExpression类型,但是由于Overload的方法是静态绑定的, 而在编译期e.LeftExpress类型, 但是我们根本没有提供Visit(Expression e)这样的方法, 编译自然出错了。íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi

íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
3 Visitor Pattern with Double DispatchíS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi

íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
回过头去看看传统的Visitor模式又是什么样子的呢?

íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi

abstract class ExpressioníS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
{íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
public abstract void Accept(Visitor v); íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
}

íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi

class ConstantExpression : ExpressioníS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
{íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
private int constant;íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
public int ConstantíS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
{íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
get { return constant; }íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
}

íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi

íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
public ConstantExpression(int con)íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
{íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
constant = con;íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
}

íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi

íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
public override void Accept(Visitor v)íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
{íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
v.Visit(this);íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
}íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
}

íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi

class SumExpression : ExpressioníS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
{íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
private Expression left, right;íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
public Expression RightíS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
{íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
get { return right; }íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
}

íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi

íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
public Expression LeftíS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
{íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
get { return left; }íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
}

íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi

íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
public SumExpression(Expression left, Expression right)íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
{íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
this.left = left;íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
this.right = right;íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
}

íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi

íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
public override void Accept(Visitor v)íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
{íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
v.Visit(this);íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
}íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
}

íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi

íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi

interface VisitoríS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
{íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
void Visit(ConstantExpression e);íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
void Visit(SumExpression e);íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
}

íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi

class EvaluateVisitor : VisitoríS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
{íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
private int result;íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
public int Result { get { return result; } }

íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi

íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
public void Visit(ConstantExpression e)íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
{íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
result=e.Constant;íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
}

íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi

íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
public void Visit(SumExpression e)íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
{íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
e.Left.Accept(this);íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
int lefeRe = this.result;íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
e.Right.Accept(this);íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
int rightRe = this.result;íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
result = lefeRe + rightRe;íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
}íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
}

íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi

class ProgramíS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
{íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
static void Main()íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
{íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
ConstantExpression constExp = new ConstantExpression(10);íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
SumExpression sumExp = new SumExpression(new ConstantExpression(1),íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
new ConstantExpression(1));

íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi

íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
EvaluateVisitor evalVisitor = new EvaluateVisitor();íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
constExp.Accept(evalVisitor);íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
Console.WriteLine(evalVisitor.Result);íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
sumExp.Accept(evalVisitor);íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
Console.WriteLine(evalVisitor.Result);íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
}íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
}

íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi

íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi

íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
可以看出这张图和前者相比,复杂了许多。但是只有这样我们才能在C#这种不直接支持Double Dispatch的语言中实现Visitor模式。

íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi

íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
怎么解决的呢? 道理很简单就是用Twice Single Dispatch来模拟Double Dispatch。最能体现Twice Single Dispatch的代码如下:íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
public override void Accept(Visitor v)íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
{íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
v.Visit(this);íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
    }

íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi

其一般形式为:íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
public void MethodA(A a)íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
{íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
a.MethodB(this);íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
    }íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi

íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi

íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
其实说到底,不支持Double Dispatch就是由于不支持方法参数的动态绑定, 那我们就通过两次的O虚方法的动态绑定来模拟它。所以 a 又从方法参数变成了虚方法的拥有者,并把this作为参数传入。

íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi

íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
明白了以上的道理,你也就知道为什么完全同样的Accpet方法没有被提到它们的基类中――-因为方法参数的类型是在编译期决定的。

íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi

íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
看到了传统Visitor模式的解决思路,对于文章一开始的小游戏所引起的问题也就不难解决了。íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi

íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi

4 Visitor Pattern with Reflection

íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi

íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
      íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
    再来看看第二节的模型,实在是很漂亮,让我不忍放弃。Gof 也想不出什么好的办法,只能无奈的采用了第三节的复杂模型。 不过,你记得吗?《Design Pattern》那本书可是十年前的作品。十年前可没有什么元数据,自然也没有Reflection

íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi

通过反射我完全可以在运行期从函数参数中找回失去的类型信息。

íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi

我只要在第二节的EvaluateVisitor类中添加如下的一个方法,就万事告吉了。

íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi

public int Visit(Expression e)íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
{íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
Type[] types = new Type[] { e.GetType() };íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
MethodInfo mi = this.GetType().GetMethod("Visit", types);íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
if (mi==null)íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
throw new Exception("UnSupported!");íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
elseíS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
return (int)mi.Invoke(this,new object[]{e});íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
    }íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi

íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi

  这个方法我个人是比较满意了,你觉得呢?

íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
1
查看完整版本: Double Dispatch And Visitor Pattern