通过阅读各位前辈写的博文,像吕震宇idior,李建忠WebCast等,对Visitor模式有一定的了解,有感而记录下来,以备忘。

  Visitor Pattern 假设了这样一个场景,在一个类型层次中,如果类型的个数稳定,且对类型操作不稳定(根据需求可能会变化)。在该模式中有个Double Dispatch的概念,即Element抽象一次,Visitor抽象一次多态。还有一次编译时多态(overload)。在Element中有Accept方法,留出以后可能扩展的操作,在ConcreteElement中,有如下关键点

public override void Accept(Visitor v)
{
v.Visit(this);
}

将具体的Element传递到Visitor中,并通过overload确定调用Visit的那个版本重载。该模式将元素的数据结构和对其的操作分离,以后需要添加额外操作添加新的Visitor实现即可。缺点就是类型的个数不变,如果需要添加新类型元素,那么Visitor抽象也需要修改。所以一般抽象的是稳定的,封装的是变化点。

2、方法的重载中,参数的类型是否可以在run-time时,实现绑定呢?在idior的文章中有详细解释,在该文中,去掉Element抽象中的Accept方法,由Visitor中的一个方法Visit(Element e)作为入口,然后动态调用具体的目标重载方法。文中解释过,GOF设计模式,是十几年前的作品,那个时候没有元数据和Reflection,overload是发生在编译时,所以Visitor模式需要double-dispatch。并给出了一个使用反射的方法,如下:

public int Visit(Expression e)
{
Type[] types = new Type[] { e.GetType() };
MethodInfo mi = this.GetType().GetMethod("Visit", types);
if (mi==null)
throw new Exception("UnSupported!");
else
return (int)mi.Invoke(this,new object[]{e});
}

该方法作为入口,动态调用具体的重载方法。这里对我很有启发,reflection如果在循环中可能会对性能有影响,故考虑缓存优化一下,如下:

    class EvaluateVisitor
{
Dictionary<Type, Func<EvaluateVisitor, Expression, int>> cache = new Dictionary<Type, Func<EvaluateVisitor, Expression, int>>();
/// <summary>
/// 根据实际的Type,动态生成一个(对目标方法Visit(XXXExpression e)的直接调用)委托
/// </summary>
/// <param name="type"></param>
/// <returns></returns>
private Func<EvaluateVisitor, Expression, int> BuildFunc(Type type)
{//(inst,e)=>inst.Visit((XXXExpression)e);
MethodInfo mi = this.GetType().GetMethod("Visit", new Type[] { type });
if (mi == null)
throw new Exception("UnSupported!"); LE.ParameterExpression paramExp = LE.Expression.Parameter(typeof(Expression), "e");
LE.ParameterExpression instance = LE.Expression.Parameter(this.GetType(), "inst");
LE.MethodCallExpression methodCallExp = LE.Expression.Call(instance, mi, LE.Expression.Convert(paramExp, type));
var lambda = LE.Expression.Lambda<Func<EvaluateVisitor, Expression, int>>(methodCallExp, instance, paramExp);
return lambda.Compile();
}
private Func<EvaluateVisitor, Expression, int> GetTargetVisit(Type type)
{
Func<EvaluateVisitor, Expression, int> result;
if (!cache.TryGetValue(type, out result))
{
result = BuildFunc(type);
cache.Add(type,result);
} return result;
} public int Visit(ConstantExpression e)
{
return e.Constant;
}
public int Visit(SumExpression e)
{
return Visit(e.Left) + Visit(e.Right);
} public int Visit(Expression e)
{
//Type[] types = new Type[] { e.GetType() };
//MethodInfo mi = this.GetType().GetMethod("Visit", types);
//if (mi == null)
// throw new Exception("UnSupported!");
//else
// return (int)mi.Invoke(this, new object[] { e });
Type t = e.GetType();
var target = GetTargetVisit(t);//在run-time,获取对目标方法的调用
return target(this, e);
}
}

在这里,对于每一个类型对应重载方法,做一个cache,根据type动态生成一个委托,该委托去调用目标方法(Visit)。这样不用每次都去反射了,提高性能。从这里看出NET3.0之后Expression Tree功能很强大,它允许我们在run-time时候动态生成一个委托,而调用委托的性能和直接调用Method几乎一样。有兴趣的同学可以参考我之前的文章《让CLR帮我写代码》。

3、在.NET中,ExpressionVisitor类用来操作Expression Tree的,也是一个visitor模式的应用,大家有兴趣可以去看看。

先写到这里了,欢迎大家交流,不正之处,还请指正,谢谢!

学习Visitor Pattern 有感而发!override and overload的更多相关文章

  1. 由override 和 overload 引发的学习感悟

    工作已三年的我,竟然面试的时候去裸考了.想当然的认为有很多东西会在工作中不知不觉积累下来,现在想想,真是扯淡... 我的三年的工作经验是开发测试的工作,主要负责测试用例的自动化实现,稍深一些的是自动化 ...

  2. C#设计模式之二十二访问者模式(Visitor Pattern)【行为型】

    一.引言   今天我们开始讲"行为型"设计模式的第九个模式,该模式是[访问者模式],英文名称是:Visitor Pattern.如果按老规矩,先从名称上来看看这个模式,我根本不能获 ...

  3. C#设计模式之二十一访问者模式(Visitor Pattern)【行为型】

    一.引言 今天我们开始讲“行为型”设计模式的第九个模式,该模式是[访问者模式],英文名称是:Visitor Pattern.如果按老规矩,先从名称上来看看这个模式,我根本不能获得任何对理解该模式有用的 ...

  4. 【设计模式】行为型09访问者模式(Visitor Pattern)

    学习地址:https://blog.csdn.net/u012124438/article/details/70537203(参考了很多博客,只有这个讲明白了核心点) 访问者模式(Visitor  P ...

  5. 深入浅出设计模式——访问者模式(Visitor Pattern)

    模式动机 对于系统中的某些对象,它们存储在同一个集合中,且具有不同的类型,而且对于该集合中的对象,可以接受一类称为访问者的对象来访问,而且不同的访问者其访问方式有所不同,访问者模式为解决这类问题而诞生 ...

  6. 乐在其中设计模式(C#) - 访问者模式(Visitor Pattern)

    原文:乐在其中设计模式(C#) - 访问者模式(Visitor Pattern) [索引页][源码下载] 乐在其中设计模式(C#) - 访问者模式(Visitor Pattern) 作者:webabc ...

  7. 第23章 访问者模式(Visitor Pattern)

    原文 第23章 访问者模式(Visitor Pattern) 访问者模式 导读:访问者模式是我个人认为所有行为模式中最为复杂的一种模式了,这个模式可能看一遍会看不懂,我也翻了好几个例子,依然不能很好的 ...

  8. 设计模式之十五:訪问者模式(Visitor Pattern)

    訪问者模式(Visitor Pattern)是GoF提出的23种设计模式中的一种,属于行为模式. 据<大话设计模式>中说算是最复杂也是最难以理解的一种模式了. 定义(源于GoF<De ...

  9. 二十四种设计模式:访问者模式(Visitor Pattern)

    访问者模式(Visitor Pattern) 介绍表示一个作用于某对象结构中的各元素的操作.它使你可以在不改变各元素的类的前提下定义作用于这些元素的新操作. 示例有一个Message实体类,某些对象对 ...

随机推荐

  1. SQL语句中使用条件逻辑

    select name, sal, case when sal >= 4000 then 'Good' when sal <= 2000 then 'Bad' else 'Ok' end ...

  2. SVN服务器使用(一)

    源代码版本控制软件很多,像VSS,SVN还有其他的软件,各有优缺点.Subversion是优秀的版本控制工具,下面主要介绍这个软件的使用. Subversion下载地址: http://subvers ...

  3. Centos 6.4上面用Shell脚本一键安装mysql 5.6.15

    Centos 6.4上面用Shell脚本一键安装mysql 5.6.15  #!/bin/bash if [ `uname -m` == "x86_64" ];then machi ...

  4. Matlab使用心得

    1..*和*的区别 .*只能用于两个同型矩阵相乘,且是相对应的元素做乘法运算,其运算规则和我们线性代数里的乘法规则是不一样的:而*用于两个矩阵相乘,如mxn,nxk两个矩阵相乘,它的运算规则和线性代数 ...

  5. BZOJ 4004 [JLOI 2015] 装备购买 解题报告

    哎这个题 WA 了无数遍...果然人太弱... 首先我们把这些装备按照花费从小到大排序,然后依次考虑是否能买这个装备. 至于这样为什么是对的,好像有一个叫拟阵的东西可以证明,然而我不会.TATQAQ ...

  6. 各大搜索引擎的User-Agent

    baidu:Mozilla/5.0 (compatible; Baiduspider/2.0; +http://www.baidu.com/search/spider.html) Google:Moz ...

  7. Yours 的博客开张啦!

    虽然申请博客已经1个月了,但是一直没有来写,没办法,题都刷不完,哪有心思写啊``` 现在集训终于完了,有了属于自己的时间了.所以该把以前做的题,学的算法好好的整理整理了.一来顺顺思路,二来也可以给后来 ...

  8. [jobdu]包含min函数的栈

    老题,两个stack.其中一个维护min值就行了. #include <iostream> #include <stack> using namespace std; int ...

  9. 二维图形的矩阵变换(二)——WPF中的矩阵变换基础

    原文:二维图形的矩阵变换(二)--WPF中的矩阵变换基础 在前文二维图形的矩阵变换(一)——基本概念中已经介绍过二维图像矩阵变换的一些基础知识,本文中主要介绍一下如何在WPF中进行矩阵变换. Matr ...

  10. Bamboo简介

    前言     前面介绍了JIRA管理平台,那么本篇就来介绍关于自动编译项目的工具-Bamboo. 正题 1.简介 Atlassian Bamboo 是一款持续集成构建服务器软件(Build Serve ...