意图:

表示一个作用于某对象结构的各元素的操作。它使你可以再不改变各元素的类的前提下定义作用于这些元素的新操作。

动机:

之前在学校的最后一个小项目就是做一个编译器,当时使用的就是访问者模式。

在静态分析阶段,将源程序表示为一个抽象语法树,编译器需要在抽象语法树的基础上实施某些操作以进行静态语义分析。可能需要定义许多操作以进行类型检查、代码优化、流程分析、检查变量是否在使用前被赋值,等等。

这个需求的特点是:要求对不同的节点进行不同的处理。

常规设计方法:不同的节点封装不同的操作。

缺点是,节点类型过多,将操作分散在各个节点类中会导致整个系统难以理解、维护和修改。增加新的操作要修改和重新编译所有的类。

改进:节点类独立于作用于其上的操作。

1 将相关操作封装在一个独立的对象(Visitor)中,并在遍历抽象语法树时将此对象传递给当前访问的元素。

2 当一个节点接受一个访问者时,该元素向访问者发送一个包含自身类信息的请求。该请求同时也将该元素本身作为一个参数。

3 访问者将对该元素执行该操作。

适用性:

在下列情况下使用Visitor模式:

一个对象结构包含很多类对象

需要对其中的对象进行很多不同的并且不相关的操作

对象很少改变,经常需要对其上的操作进行修改或新增

需要注意的一点是,如果对象结果和接口经常改变,那么会导致需要重定义所有访问者的接口,会导致很大的代价。所以这种情况还是在对象类中定义操作比较好。

结构:

协作:

示例代码:

背景:假设你的电脑出现问题了 ,拿到售后那边检测,售后告诉你必须拆机检测,检测过程通过两个技术人员依次负责不同功能的检测。

分析:本例中,两个负责不同功能检测的技术人员就是Visitor,而电脑的各个部件就是elements。

特点:电脑的部件是固定的,不会有太大的改变,但是如果一种检测方式没有找出问题的话,那么就需要增加检测项。符合访问者模式的特点。

//visit.h#ifndef VISITOR_H
#define VISITOR_H#include <iostream>
#include <string>
#include <vector>class Element;
class CPU;
class VideoCard;
class MainBoard;/*------------------*/
class Visitor {
public:Visitor(std::string name) {visitorName = name;}virtual void visitCPU( CPU* cpu ) {};virtual void visitVideoCard( VideoCard* videoCard ) {};virtual void visitMainBoard( MainBoard* mainBoard ) {};std::string getName() {return this->visitorName;};
private:std::string visitorName;
};class Element {
public:Element( std::string name ) {eleName = name;}virtual void accept( Visitor* visitor ) {};virtual std::string getName() {return this->eleName;}
private:std::string eleName;
};/*----------- Elements -------------*/class CPU : public Element {
public:CPU(std::string name) : Element(name) {}void accept(Visitor* visitor) {visitor->visitCPU(this);}
};class VideoCard : public Element {
public:VideoCard(std::string name) : Element(name) {}void accept(Visitor* visitor) {visitor->visitVideoCard(this);}
};class MainBoard : public Element {
public:MainBoard(std::string name) : Element(name) {}void accept(Visitor* visitor) {visitor->visitMainBoard(this);}
};/*----------- ConcreteVisitor -------------*/class CircuitDetector : public Visitor {
public:CircuitDetector(std::string name) : Visitor(name) {}// checking cpuvoid visitCPU( CPU* cpu ) {std::cout << Visitor::getName() << " is checking CPU's circuits.(" << cpu->getName()<<")" << std::endl;}// checking videoCardvoid visitVideoCard( VideoCard* videoCard ) {std::cout << Visitor::getName() << " is checking VideoCard's circuits.(" << videoCard->getName()<<")" << std::endl;}// checking mainboardvoid visitMainBoard( MainBoard* mainboard ) {std::cout << Visitor::getName() << " is checking MainBoard's circuits.(" << mainboard->getName() <<")" << std::endl;}};class FunctionDetector : public Visitor {
public:FunctionDetector(std::string name) : Visitor(name) {}virtual void visitCPU( CPU* cpu ) {std::cout << Visitor::getName() << " is check CPU's function.(" << cpu->getName() << ")"<< std::endl;}// checking videoCardvoid visitVideoCard( VideoCard* videoCard ) {std::cout << Visitor::getName() << " is checking VideoCard's function.(" << videoCard->getName()<< ")" << std::endl;}// checking mainboardvoid visitMainBoard( MainBoard* mainboard ) {std::cout << Visitor::getName() << " is checking MainBoard's function.(" << mainboard->getName() << ")"<< std::endl;}
};/*------------------------*/class Computer {
public:Computer(CPU* cpu,VideoCard* videocard,MainBoard* mainboard) {elementList.push_back(cpu);elementList.push_back(videocard);elementList.push_back(mainboard);};void Accept(Visitor* visitor) {for( std::vector<Element*>::iterator i = elementList.begin(); i != elementList.end(); i++ ){(*i)->accept(visitor);}};
private:std::vector<Element*> elementList;
};#endif
// main.cpp#include "visitor.h"int main() {CPU* cpu = new CPU("Intel CPU");VideoCard* videocard = new VideoCard("XXX video card");MainBoard* mainboard = new MainBoard("HUAWEI mainboard");Computer* myComputer = new Computer(cpu, videocard, mainboard);CircuitDetector* Dan = new CircuitDetector("CircuitDetector Dan");FunctionDetector* Tom = new FunctionDetector("FunctionDetector Tom");std::cout << "\nStep 1: Dan is checking computer's circuits." << std::endl;myComputer->Accept(Dan);std::cout << "\nStep 2: Tom is checking computer's functions." << std::endl;myComputer->Accept(Tom);system("Pause");return 0;
}

运行截图:

参考资料:

《设计模式:可复用面向对象软件的基础》

转载于:https://www.cnblogs.com/suzhou/p/designpattern17visitor.html

设计模式(17) 访问者模式(VISITOR) C++实现相关推荐

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

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

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

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

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

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

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

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

  5. [设计模式] 23 访问者模式 visitor Pattern

    在GOF的<设计模式:可复用面向对象软件的基础>一书中对访问者模式是这样说的:表示一个作用于某对象结构中的各元素的操作.它使你可以在不改变各元素的类的前提下定义作用于这些元素的新操作.访问 ...

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

    设计模式:访问者(Visitor)模式 一.前言    什么叫做访问,如果大家学过数据结构,对于这点就很清晰了,遍历就是访问的一般形式,单独读取一个元素进行相应的处理也叫作访问,读取到想要查看的内容+ ...

  7. 北风设计模式课程---访问者模式(Visitor)

    北风设计模式课程---访问者模式(Visitor) 一.总结 一句话总结: 设计模式是日常问题的经验总结方案,所以学好设计模式对日常出现的问题可以有很好的解决. 访问者设计模式有点神似 抽象工厂模式, ...

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

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

  9. Java设计模式(访问者模式-迭代器模式-观察者模式-中介者模式)

    Java设计模式Ⅶ 1.访问者模式 1.1 访问者模式概述 1.2 代码理解 2.迭代器模式 2.1 迭代器模式概述 2.2 代码理解 3.观察者模式 3.1 观察者模式概述 3.2 代码理解 4.中 ...

最新文章

  1. (转)Ubuntu10.04各文件夹的作用
  2. 计算机视觉与图像处理相关的国内外重要期刊汇总
  3. [实战虚拟化]无需借助虚机安装,就能从VHD原生启动
  4. 自动化工具之二:win32gui
  5. 【Android NDK 开发】JNI 引用 ( 弱全局引用 | NewWeakGlobalRef | DeleteWeakGlobalRef )
  6. Java断言(assert)
  7. UBUNTU 12.04 下配置 HAXM 加速 ANDROID模拟器
  8. 二分+01分数规划+最大化平均值 Dropping tests POJ - 2976
  9. CentOS - 修改主机名教程(将 localhost.localdomain 改成其它名字)
  10. 使用VS code 创建 Azure Functions,从blob触发,解析,发送至Service Bus
  11. linux bug定位神器——lsof | grep 简直不能太好用
  12. ffmpeg对amr格式编解码
  13. 简述计算机绘图的应用领域试卷,计算机绘图试卷A(标准答案)
  14. 如何在App中实现朋友圈功能之一朋友圈实现原理浅析——箭扣科技Arrownock
  15. charset参数 sqluldr2_sqluldr2使用几例
  16. 第二十章 齐桓公大婚冤家又聚首 宋闵公嘲笑重臣丢君命(
  17. 三子棋小游戏(超详细)
  18. 开发Java程序的工具
  19. 【转】CMNET和CMWAP区别
  20. (11)EKF - (3) EKF3匹配度和Lane切换

热门文章

  1. 2020idea插件怎么同步_没有用过这些插件,别说你在用vscode
  2. php实时上传多张图片,PHP实现多张图片上传预览功能
  3. 人人开源 VUE项目报错./src/assets/scss/index.scssModule build failed: Error: ENOENT: no such file or direct
  4. android 控件 margin,Android MarginDesign控件TabLayout导航栏使用详解
  5. 3 配置ftp文件服务器,03-FTP和TFTP配置
  6. word文档保存到服务器,读取SQL表数据保存到Word并将Word文档保存到服务器代码
  7. linux dhcp 负载均衡,dhcp双机负载均衡
  8. 小猴吃桃matlab,看图写话:小猴吃桃精彩选篇
  9. 灰色关联与TOPSIS法 —— matlab
  10. python基础入门(4)之布尔值