无环的访问者模式,是来改进原有访问者模式的不足之处的,是Robert C. Martin首次提出的。我们知道访问者模式的优点是为被访问继承体系动态添加行为,而无须改变继承体系。但是GOF访问者模式的缺点是形成了一个循环依赖,强烈的耦合了两个继承体系,使得我们修改任何一方都会对另一方造成影响,所以GOF提出,被访问者的继承体系必须是稳定的,否则,一旦被访问的继承体系修改了,两边都要改。

GOF访问者模式的UML类图。从图中可以看到循环依赖,一旦被访者体系发生变化,则访问者体系就要修改,这是难以接受的。

  Robert C. Martin提出了一种无环的访问者模式来改进原有的不足,通过改进后,循环依赖被打破了,也不要求被访问层次必须是
稳定的,即使是被访问者继承层次修改了,也不需要修改访问者层次,只需要扩展一下即可,而且访问者可以自由组合较之以前更

为灵活方便。但是也是有代价的,有一个向下的转换,性能会稍有损失,但相对于改进的好处来说,这点损失几乎可以忽略了。

  从上图我们可以看到,循环依赖被打破了,访问者基类不再依赖于被访问者的具体类型了,只是依赖于一个空的访问者基类,因此它是稳定的。通过多重继承,我们可以自由的组合访问者,比以前将访问函数放到一个类中更灵活。下面看看c++中具体的实现吧。

///////////////访问者基类
template<typename T>
struct Visitor
{
virtual void Visit( T&) = ;
}; struct VistorToken
{
virtual ~VistorToken(){}
}; /////////////////被访问者基类
struct Base
{
virtual void Accept(VistorToken&) = ;
virtual ~Base(){}
}; /////////////////具体的被访问者
struct AV;
typedef Visitor<AV> AVVisitor; struct BV;
typedef Visitor<BV> BVVisitor; struct AV : public Base
{
double val;
void Accept(VistorToken& v)
{
if (AVVisitor* ev = dynamic_cast<AVVisitor*>(&v))
ev->Visit(*this);
}
}; struct BV : public Base
{
double val;
void Accept(VistorToken& v)
{
if (BVVisitor* ev = dynamic_cast<BVVisitor*>(&v))
ev->Visit(*this);
}
}; ////////////////////////具体的自定义访问者
struct CustomerVisitor : public VistorToken, public AVVisitor, public BVVisitor
{
void Visit(AV& a)
{
std::cout << "from AV: " << a.val << std::endl;
}
void Visit(BV& b)
{
std::cout << "from BV: " << b.val << std::endl;
}
};

测试程序:

void OtherVisitor()
{
AV a; a.val = 10.1;
BV b; b.val = 9.2;
CustomerVisitor v;
Base* b1 = &a;
Base* b2 = &b;
b1->Accept(v);
b2->Accept(v);
}

  不知道无环的访问者模式我讲清楚没有,可能有点难理解,没关系,自己动手实践一下,再回过头来看介绍也许就明白了怎么回事了。

  c++11 boost技术交流群:296561497,欢迎大家来交流技术。

无环的visitor模式的更多相关文章

  1. UVA_1025 a Spy in the Metro 有向无环图的动态规划问题

    应当认为,有向无环图上的动态规划问题是动态规划的基本模型之一,对于某个模型,如果可以转换为某一有向无环图的最长.最短路径问题,则可以套用动态规划若干方法解决. 原题参见刘汝佳紫薯267页. 在这个题目 ...

  2. Visitor模式,Decorator模式,Extension Object模式

    Modem结构 Visitor模式 对于被访问(Modem)层次结构中的每一个派生类,访问者(Visitor)层次中都有一个对应的方法. 从派生类到方法的90度旋转. 新增类似的Windows配置函数 ...

  3. [转帖]MerkleDAG全面解析 一文读懂什么是默克尔有向无环图

    MerkleDAG全面解析 一文读懂什么是默克尔有向无环图 2018-08-16 15:58区块链/技术 MerkleDAG作为IPFS的核心数据结构,它融合了Merkle Tree和DAG的优点,今 ...

  4. Behavioral模式之Visitor模式

    1.意图 表示一个作用于某对象结构中的各元素的操作.它使你能够在不改变各元素的类的前提下定义作用于这些元素的新操作. 2.别名 无 3.动机 考虑一个编译器.他将源程序表示为一个抽象语法树.该编译器须 ...

  5. 完成C++不能做到的事 - Visitor模式

    拿着刚磨好的热咖啡,我坐在了显示器前.“美好的一天又开始了”,我想. 昨晚做完了一个非常困难的任务并送给美国同事Review,因此今天只需要根据他们提出的意见适当修改代码并提交,一周的任务就完成了.剩 ...

  6. 有向无环图的应用—AOV网 和 拓扑排序

    有向无环图:无环的有向图,简称 DAG (Directed Acycline Graph) 图. 一个有向图的生成树是一个有向树,一个非连通有向图的若干强连通分量生成若干有向树,这些有向数形成生成森林 ...

  7. JavaScript + SVG实现Web前端WorkFlow工作流DAG有向无环图

    一.效果图展示及说明 (图一) (图二) 附注说明: 1. 图例都是DAG有向无环图的展现效果.两张图的区别为第二张图包含了多个分段关系.放置展示图片效果主要是为了说明该例子支持多段关系的展现(当前也 ...

  8. 湖南省第十二届大学生计算机程序设计竞赛 B 有向无环图 拓扑DP

    1804: 有向无环图 Time Limit: 5 Sec  Memory Limit: 128 MBSubmit: 187  Solved: 80[Submit][Status][Web Board ...

  9. javascript实现有向无环图中任意两点最短路径的dijistra算法

    有向无环图 一个无环的有向图称做有向无环图(directed acycline praph).简称DAG 图.DAG 图是一类较有向树更一般的特殊有向图, dijistra算法 摘自 http://w ...

随机推荐

  1. mgo中DBRef-数据添加测试

    2014-1-25 在设计mongo数据库时遇到这样一个问题,日志信息表需要引用人员信息表的数据.如果是结构化数据库,基本上不用想太多的东西.由于刚接触非结构化数据库,按着书上的理解由于日志数量较多, ...

  2. set QUOTED_IDENTIFIER ON事故记录

    作业执行失败: 看了一下执行脚本 delete  top(8000) from "interface"."完成" where  loggid in( selec ...

  3. VC++ list函数详解

    在使用之前,需要完成两件事: (1)  #include <list> (2)  using namespace std; 声名变量:   list<int>  intlist ...

  4. 4.Mybatis的输入映射(parameterType类型解析)

    前面提到过Mybatis可以对输入的参数进行映射,那么现在我们来看一下输入映射,关于输入映射大概可以分为几种情况来学习: 1.基本的类型 2.实体类 3.包装类 1.参数是基本的类型(int,Stri ...

  5. js模拟import方法导入外部文件

    function Import() { for( var i=0; i<arguments.length; i++ ) { var file = arguments; if ( file.mat ...

  6. 计算机病毒实践汇总四:netcat使用方法

    在尝试学习分析的过程中,判断结论不一定准确,只是一些我自己的思考和探索.敬请批评指正! 1. netcat概述 (1)特性 "TCP/IP协议栈瑞士军刀",可以被用在支持端口扫描. ...

  7. 开发中用到的开源框架汇总(Updating)

    SuperWebSocket SuperSocket NPOI 官网:http://npoi.codeplex.com/ 实例讲解:http://www.cnblogs.com/yutian/p/52 ...

  8. 学习笔记008之Task

    栈 为后进先出 如何实现一个弹出窗体.

  9. 使用Aspose插件将程序中的表格,导出生成excel表格

    http://www.cnblogs.com/lanyue52011/p/3372452.html这个是原文地址 /// <summary> /// 点击按钮,将内存表导出excel表格! ...

  10. iOS页面间传值的方式(Delegate/NSNotification/Block/NSUserDefault/单例)

    iOS页面间传值实现方法:1.通过设置属性,实现页面间传值:2.委托delegate方式:3.通知notification方式:4.block方式:5.UserDefault或者文件方式:6.单例模式 ...