在GOF的《设计模式:可复用面向对象软件的基础》一书中对访问者模式是这样说的:表示一个作用于某对象结构中的各元素的操作。它使你可以在不改变各元素的类的前提下定义作用于这些元素的新操作。访问者模式把数据结构和作用于结构上的操作之间的耦合解脱开,使得操作集合可以相对自由地演化。该模式的目的是要把处理从数据结构分离出来。访问者模式让增加新的操作很容易,因为增加新的操作就意味着增加一个新的访问者。访问者模式将有关的行为集中到一个访问者对象中。

 

初次接触,定义会显得晦涩并且难于理解,没关系,LZ来陪着各位一起一点一点分析定义中所提到的关键点。

先来看第一句话,说是一个作用于某对象结构中的各元素的操作,这里提到了三个事物,一个是对象结构,一个是各元素,一个是操作。那么我们可以这么理解,有这么一个操作,它是作用于一些元素之上的,而这些元素属于某一个对象结构。

好了,最关键的第二句来了,它说使用了访问者模式之后,可以让我们在不改变各元素类的前提下定义作用于这些元素的新操作。这里面的关键点在于前半句,即不改变各元素类的前提下,在这个前提下定义新操作是访问者模式精髓中的精髓。

 Visitor接口:它定义了对每一个元素(Element)访问的行为,它的参数就是可以访问的元素,它的方法个数理论上来讲与元素个数(Element的实现类个数)是一样的,从这点不难看出,访问者模式要求元素类的个数不能改变(不能改变的意思是说,如果元素类的个数经常改变,则说明不适合使用访问者模式)。

                  ConcreteVisitor:具体的访问者,它需要给出对每一个元素类访问时所产生的具体行为。

                  Element接口:元素接口,它定义了一个接受访问者(accept)的方法,其意义是指,每一个元素都要可以被访问者访问。

                  ConcreteElement:具体的元素类,它提供接受访问方法的具体实现,而这个具体的实现,通常情况下是使用访问者提供的访问该元素类的方法。

                  ObjectStructure:这个便是定义当中所提到的对象结构,对象结构是一个抽象表述,具体点可以理解为一个具有容器性质或者复合对象特性的类,它会含有一组元素(Element),并且可以迭代这些元素,供访问者访问。

在上面五个角色当中,最重要的就是最后一个,所谓的访问者模式,就是为了让访问者可以方便的访问对象结构而存在的。关于访问者模式的例子,很多文章和文献使用男人和女人的例子,所以LZ这里就不重复了。

#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
using namespace std;class Visitor;// Element object
class Element
{public: virtual void Accept(Visitor *pVisitor) = 0;
};class ConcreteElementA : public Element
{private:string m_name; public: ConcreteElementA();string getName(){return m_name;}void Accept(Visitor *pVisitor);
};class ConcreteElementB : public Element
{private:string m_name; public: ConcreteElementB();string getName(){return m_name;}void Accept(Visitor *pVisitor);
};class Visitor
{public:virtual void VisitConcreteElementA(ConcreteElementA *pElementA) = 0;virtual void VisitConcreteElementB(ConcreteElementB *pElementB) = 0;
};class ConcreteVisitor1 : public Visitor
{public:void VisitConcreteElementA(ConcreteElementA *pElementA);void VisitConcreteElementB(ConcreteElementB *pElementB);
};void ConcreteVisitor1::VisitConcreteElementA(ConcreteElementA *pElementA)
{cout << "Visitor1 vist " << pElementA->getName() << endl;
}void ConcreteVisitor1::VisitConcreteElementB(ConcreteElementB *pElementB)
{cout << "Visitor1 vist " << pElementB->getName() << endl;
}class ConcreteVisitor2 : public Visitor
{public:void VisitConcreteElementA(ConcreteElementA *pElementA);void VisitConcreteElementB(ConcreteElementB *pElementB);
};void ConcreteVisitor2::VisitConcreteElementA(ConcreteElementA *pElementA)
{cout << "Visitor2 vist " << pElementA->getName() << endl;
}void ConcreteVisitor2::VisitConcreteElementB(ConcreteElementB *pElementB)
{cout << "Visitor2 vist " << pElementB->getName() << endl;
}ConcreteElementA::ConcreteElementA()
{m_name = "ConcreteElementA";
}void ConcreteElementA::Accept(Visitor *pVisitor)
{pVisitor->VisitConcreteElementA(this);
}ConcreteElementB::ConcreteElementB()
{m_name = "ConcreteElementB";
}void ConcreteElementB::Accept(Visitor *pVisitor)
{pVisitor->VisitConcreteElementB(this);
}// ObjectStructureÀ࣬ÄÜö¾ÙËüµÄÔªËØ£¬¿ÉÒÔÌṩһ¸ö¸ß²ãµÄ½Ó¿ÚÒÔÔÊÐí·ÃÎÊÕß·ÃÎÊËüµÄÔªËØ
class ObjectStructure
{public:void Attach(Element *pElement);void Detach(Element *pElement);void Accept(Visitor *pVisitor);private:vector<Element *> elements;
};void ObjectStructure::Attach(Element *pElement)
{elements.push_back(pElement);
}void ObjectStructure::Detach(Element *pElement)
{vector<Element *>::iterator it = find(elements.begin(), elements.end(), pElement);if (it != elements.end()){elements.erase(it);}
}void ObjectStructure::Accept(Visitor *pVisitor)
{// Ϊÿһ¸öelementÉèÖÃvisitor£¬½øÐжÔÓ¦µÄ²Ù×÷for (vector<Element *>::const_iterator it = elements.begin(); it != elements.end(); ++it){(*it)->Accept(pVisitor);}
}int main()
{ObjectStructure *pObject = new ObjectStructure;ConcreteElementA *pElementA = new ConcreteElementA;ConcreteElementB *pElementB = new ConcreteElementB;pObject->Attach(pElementA);pObject->Attach(pElementB);ConcreteVisitor1 *pVisitor1 = new ConcreteVisitor1;ConcreteVisitor2 *pVisitor2 = new ConcreteVisitor2;pObject->Accept(pVisitor1);pObject->Accept(pVisitor2);if (pVisitor2) delete pVisitor2;if (pVisitor1) delete pVisitor1;if (pElementB) delete pElementB;if (pElementA) delete pElementA;if (pObject) delete pObject;return 0;
}

输出:

Visitor1 vist ConcreteElementA
Visitor1 vist ConcreteElementB
Visitor2 vist ConcreteElementA
Visitor2 vist ConcreteElementB

Visitor(访问者):为该对象结构中ConcreteElement的每一个类声明一个Visit操作。该操作的名字和特征标识了发送Visit请求给该访问者的那个类。这使得访问者可以确定正被访问元素的具体的类。这样访问者就可以通过该元素的特定接口直接访问它。
ConcreteVisitor(具体访问者):实现每个由Visitor声明的操作。每个操作实现本算法的一部分,而该算法片段乃是对应于结构中对象的类。ConcreteVisitor为该算法提供了上下文并存储它的局部状态。这一状态常常在遍历该结构的过程中累积结果。
Element(元素):定义一个Accept操作,它以一个访问者为参数。
ConcreteElement(具体元素):实现Accept操作,该操作以一个访问者为参数。
ObjectStructure(对象结构):能够枚举它的元素,同时提供一个高层的接口以允许该访问者访问它的元素。

使用场合

  1. 一个对象结构包含很多类对象,它们有不同的接口,而你想对这些对象实施一些依赖于其具体类的操作;
  2. 需要对一个对象结构中的对象进行很多不同的并且不相关的操作,而你想避免让这些操作“污染”这些对象的类。Visitor使得你可以将相关的操作集中起来定义在一个类中;
  3. 当该对象结构被很多应用共享时,用Visitor模式让每个应用仅包含需要用到的操作;
  4. 定义对象结构的类很少改变,但经常需要在此结构上定义新的操作。改变对象结构类需要重定义对所有访问者的接口,这可能需要很大的代价。如果对象结构类经常改变,那么可能还是在这些类中定义这些操作较好

总结

访问者模式的基本思想如下:首先拥有一个由许多对象构成的对象结构,就是上面代码中的ObjectStructure,这些对象的类都拥有一个Accept方法用来接受访问者对象;访问者是一个接口,它拥有一个Visit方法,这个方法对访问到的对象结构中不同类型的元素做出不同的操作;在对象结构的一次访问过程中,我们遍历整个对象结构,对每一个元素都实施Accept方法,在每一个元素的Accept方法中回调访问者的Visit方法,从而使访问者得以处理对象结构的每一个元素。我们就可以针对对象结构设计不同的访问者类来完成不同的操作。

Visitor 模式在不破坏类的前提下,为类提供增加新的新操作。Visitor 模式的关键是双分
派(Double-Dispatch)的技术【注释 1】。C++语言支持的是单分派。
在 Visitor 模式中 Accept()操作是一个双分派的操作。具体调用哪一个具体的 Accept
()操作,有两个决定因素:1)Element 的类型。因为 Accept()是多态的操作,需要具
体的 Element 类型的子类才可以决定到底调用哪一个 Accept()实现;2)Visitor 的类型。
Accept()操作有一个参数(Visitor* vis),要决定了实际传进来的 Visitor 的实际类别才可
以决定具体是调用哪个 VisitConcrete()实现。

转载于:https://www.cnblogs.com/diegodu/p/4453793.html

[设计模式] 23 访问者模式 visitor Pattern相关推荐

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

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

  2. 设计模式:访问者模式(Visitor Pattern)

    访问者模式(Visitor Pattern): 封装一些作用于某种数据结构的各元素的操作,它可以在不改变数据结构的前提下定义作用于这些元素的新的操作. 主要将数据结构与数据操作分离,解决数据结构和操作 ...

  3. java 访客模式,设计模式 - 访客模式( Visitor Pattern)

    设计模式 - 访客模式( Visitor Pattern) 在Visitor模式中,我们使用一个访问者类来更改元素类的执行算法. 通过这种方式,元素的执行算法可以随着访问者的变化而变化. 此模式属于行 ...

  4. 设计模式之访问者模式(Visitor)

    访问者模式(Visitor) 在访问者模式(Visitor Pattern)中,我们使用了一个访问者类,它改变了元素类的执行算法.通过这种方式,元素的执行算法可以随着访问者改变而改变 主要将数据结构与 ...

  5. 设计模式之访问者模式(Visitor)摘录

    23种GOF设计模式一般分为三大类:创建型模式.结构型模式.行为模式. 创建型模式抽象了实例化过程,它们帮助一个系统独立于如何创建.组合和表示它的那些对象.一个类创建型模式使用继承改变被实例化的类,而 ...

  6. 【设计模式】—— 访问者模式Visitor

    对于某个对象或者一组对象,不同的访问者,产生的结果不同,执行操作也不同.此时,就是访问者模式的典型应用了. 应用场景 1 不同的子类,依赖于不同的其他对象 2 需要对一组对象,进行许多不相关的操作,又 ...

  7. 设计模式(17) 访问者模式(VISITOR) C++实现

    意图: 表示一个作用于某对象结构的各元素的操作.它使你可以再不改变各元素的类的前提下定义作用于这些元素的新操作. 动机: 之前在学校的最后一个小项目就是做一个编译器,当时使用的就是访问者模式. 在静态 ...

  8. C++设计模式23——访问者模式

    https://blog.csdn.net/CoderAldrich/article/details/83270301 访问者模式 在GOF的<设计模式:可复用面向对象软件的基础>一书中对 ...

  9. 40访问者模式(Visitor Pattern)

    类层次结构的变化:     类层次结构中可能经常由于引入新的操作,从而将类型变得脆弱...                             动机:     在软件构建过程中,由于需求的改变,某 ...

最新文章

  1. python flask高级编程之restful_('Python Flask高级编程之RESTFul API前后端分离精讲',),全套视频教程学习资料通过百度云网盘下载...
  2. 谈API网关的背景、架构以及落地方案--转
  3. 送书 | 经典框架Kaldi配套的语音识别实战
  4. 【Python学习笔记】异常处理try-except
  5. 23-初识正则表达式
  6. java基础——构造函数小知识点
  7. [置顶] 自己动手写Web容器之TomJetty之六:动态页面引入
  8. Unity 导出Supermap exe
  9. Wscript.Shell 对象详细介绍(编写.VBS)
  10. GitHub 新手使用手册
  11. sql转java对象_关于hibernate中使用sql语句时,类对象的转换问题。
  12. CPDA|数据分析师成长之路如何起步?
  13. 各国货币json文件
  14. 03筑基期——循环、嵌套循环、循环跳转、随机数(算法基础又篇)
  15. 巧用头条号及悟空问答引流
  16. OPPO系统推送SDK集成踩坑思路
  17. 图表Chart.js入门教程
  18. 云服务器远程一键登录出现SSH connection failed: All configured authentication methods failed *解决办法。
  19. 机器人编程趣味实践14-机器人三维仿真(Gazebo+TurtleBot3)
  20. 无人驾驶—激光雷达与相机

热门文章

  1. pytorch图像预处理
  2. Java实现对字符串的快速排序-程序解读
  3. oracle数据库集群采用的是形式,铁道部采用Oracle集群数据库进行TMIS系统“三级建库”...
  4. linux基础命令_Linux编程基础:常用命令
  5. FLOPs衡量模型复杂度
  6. Python学习入门基础教程(learning Python)--5.6 Python读文件操作高级
  7. Extjs的打印解决方案
  8. c语言括号匹配输出个数字,C程序括号匹配检查(带详细注释)
  9. vs2008与oracle数据库连接
  10. angular4 浏览器兼容