博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
c++设计模式-—访问者模式
阅读量:4212 次
发布时间:2019-05-26

本文共 3684 字,大约阅读时间需要 12 分钟。

访问者模式

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

是基于Windows Shell开发的一个项目,在一个容器中存储了很多的Shell Items,同时定义了对Items的操作,由于项目一直都在进行后期扩展,对Items的操作在后期都需要进行扩展的;而现在的做法是,定义一个操作类,该操作类中定义了一个集合,该集合存放Items,在该操作类中扩展对应的操作方法。现在想想如果使用访问者模式也是可以的,由于Items集合是固定的,当需要扩展集合的操作时,只需要添加对应的访问者即可。

 

UML类图

Visitor(访问者):为该对象结构中ConcreteElement的每一个类声明一个Visit操作。该操作的名字和特征标识了发送Visit请求给该访问者的那个类。这使得访问者可以确定正被访问元素的具体的类。这样访问者就可以通过该元素的特定接口直接访问它。

ConcreteVisitor(具体访问者):实现每个由Visitor声明的操作。每个操作实现本算法的一部分,而该算法片段乃是对应于结构中对象的类。ConcreteVisitor为该算法提供了上下文并存储它的局部状态。这一状态常常在遍历该结构的过程中累积结果。
Element(元素):定义一个Accept操作,它以一个访问者为参数。
ConcreteElement(具体元素):实现Accept操作,该操作以一个访问者为参数。
ObjectStructure(对象结构):能够枚举它的元素,同时提供一个高层的接口以允许该访问者访问它的元素。

 

使用场合

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

 

代码实现:

#include
#include
using namespace std;class ConcreteElementA;class ConcreteElementB;#define SAFE_DELETE(p) if(p){delete p;p=NULL;}class Visitor{public: virtual void VisitConcreteElementA(ConcreteElementA* pElementA) = 0; //访问元素A virtual void VisitConcreteElementB(ConcreteElementB* pElementB) = 0; //访问元素B};class ConcreteVisitor1 :public Visitor{public: void VisitConcreteElementA(ConcreteElementA* pElementA); void VisitConcreteElementB(ConcreteElementB* pElementB);};void ConcreteVisitor1::VisitConcreteElementA(ConcreteElementA* pElementA) //注意这里是元素将元素自己推送过来的{ //根据传进来的ElementA,可以对ConcreteElementA中的element进行操作 cout<<"访问者1访问元素A"<
VisitConcreteElementA(this);}class ConcreteElementB:public Element{public: void Accept(Visitor* pVisitor);};void ConcreteElementB::Accept(Visitor* pVisitor){ pVisitor->VisitConcreteElementB(this);}//ObjectStruct类,能枚举它的元素,可以提供一个高层的接口以允许访问者访问它的元素class ObjectStruct{public: void Attach(Element* pElement); void Detach(Element* pElement); void Accept(Visitor* pVisitor);private: vector
elements;};void ObjectStruct::Attach(Element * pElement){ elements.push_back(pElement);}void ObjectStruct::Detach(Element *pElement){ vector
::iterator it = find(elements.begin(),elements.end(),pElement); if (it != elements.end()) { elements.erase(it); }}void ObjectStruct::Accept(Visitor* pVisitor){ //为每一个element设置visitor,进行对应的操作 for (vector
::const_iterator it = elements.begin(); it != elements.end(); ++it) { (*it)->Accept(pVisitor); }}int main(int argc,char* argv[]){ ObjectStruct* pObject = new ObjectStruct(); //提供的一个高层接口 ConcreteElementA* pElementA = new ConcreteElementA(); //元素A ConcreteElementB* pElementB = new ConcreteElementB(); //元素B pObject->Attach(pElementA); pObject->Attach(pElementB); ConcreteVisitor1* pVisitor1 = new ConcreteVisitor1(); ConcreteVisitor2* pVisitor2 = new ConcreteVisitor2(); pObject->Accept(pVisitor1); pObject->Accept(pVisitor2); SAFE_DELETE(pVisitor2); SAFE_DELETE(pVisitor1); SAFE_DELETE(pElementB); SAFE_DELETE(pElementA); SAFE_DELETE(pObject); /** 最终输出: 访问者1访问元素A 访问者1访问元素B 访问者2访问元素A 访问者2访问元素B */}

总结

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

设计模式中经常说的一句话是:发现变化并封装之。是否采用访问者模式,就要看“变化”是什么。访问者模式中,“变化”是具体访问者,其次是对象结构;但是,如果具体元素也会发生改变,就万万不能使用访问者模式,因为这样“牵一发而动全身”,后期的维护性就太差了。

你可能感兴趣的文章
反病毒专家谈虚拟机技术 面临两大技术难题
查看>>
几种典型的反病毒技术:特征码技术、覆盖法技术等
查看>>
Software Security Testing软件安全测试
查看>>
SQL注入漏洞全接触--进阶篇
查看>>
SQL注入漏洞全接触--高级篇
查看>>
SQL注入法攻击一日通
查看>>
论文浅尝 | 通过共享表示和结构化预测进行事件和事件时序关系的联合抽取
查看>>
论文浅尝 | 融合多粒度信息和外部语言知识的中文关系抽取
查看>>
论文浅尝 | GMNN: Graph Markov Neural Networks
查看>>
廖雪峰Python教程 学习笔记3 hello.py
查看>>
从内核看epoll的实现(基于5.9.9)
查看>>
python与正则表达式
查看>>
安装.Net Framework 4.7.2时出现“不受信任提供程序信任的根证书中终止”的解决方法
查看>>
input type=“button“与input type=“submit“的区别
查看>>
解决Github代码下载慢问题!
查看>>
1.idea中Maven创建项目及2.对idea中生命周期的理解3.pom文件夹下groupId、artifactId含义
查看>>
LeetCode-栈|双指针-42. 接雨水
查看>>
stdin,stdout,stderr详解
查看>>
Linux文件和设备编程
查看>>
文件描述符
查看>>