意图:

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

动机:

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

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

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

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

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

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

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 cpu
void visitCPU( CPU* cpu ) {
std::cout << Visitor::getName() << " is checking CPU's circuits.(" << cpu->getName()<<")" << std::endl;
} // checking videoCard
void visitVideoCard( VideoCard* videoCard ) {
std::cout << Visitor::getName() << " is checking VideoCard's circuits.(" << videoCard->getName()<<")" << std::endl;
} // checking mainboard
void 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 videoCard
void visitVideoCard( VideoCard* videoCard ) {
std::cout << Visitor::getName() << " is checking VideoCard's function.(" << videoCard->getName()<< ")" << std::endl;
} // checking mainboard
void 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;
}

运行截图:

参考资料:

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

最新文章

  1. Microservice 微服务的理论模型和现实路径
  2. virtualbox桥接网络配置--CentOS
  3. Golang下的Log处理
  4. Learning Roadmap of Deep Reinforcement Learning
  5. [ActionScript] AS3 绘制虚线
  6. Ubuntu 之 initramfs 报错解决之一
  7. UML类图、接口、包、关系
  8. 在线office文档编辑NTKO使用心得
  9. 矢量量化(VQ)
  10. 【2017-06-05】Jquery.ajax
  11. windows server 2003安装 SQL server 2008r2 版本的步骤
  12. Got permission denied while trying to connect to the Docker daemon socket at
  13. Python 进程管理工具 Supervisor 使用教程
  14. docker被屏蔽后下载方法
  15. 与图论的邂逅01:树的直径&amp;基环树&amp;单调队列
  16. 16.求Sn=a+aa+aaa+aaaa.......之值
  17. Redis常用操作-------Key(键)
  18. 修改Linux的基本配置
  19. Jenkins 快速搭建
  20. LeetCode: Sum Root to Leaf Numbers 解题报告

热门文章

  1. Linux下SSH工具 PAC Manager的安装
  2. Hive 安装
  3. 05 JDK1.5 Lock锁
  4. eclipse修改默认注释
  5. [译]用R语言做挖掘数据《六》
  6. [转]OData – the best way to REST–实例讲解ASP.NET WebAPI OData (V4) Service &amp; Client
  7. 使用StackPanel进行简单地布局
  8. 以太坊-windows-私有链-搭建(非源码)
  9. 新建Java Web项目
  10. SecureCRT介绍