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

意图:

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

 

动机:

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

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

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

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

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

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

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

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

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

 

适用性:

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

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

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

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

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

 

结构:

clipboard

 

协作:

clipboard[1]

 

示例代码:

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

分析:本例中,两个负责不同功能检测的技术人员就是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;
}

 

 

运行截图:

clipboard[2]

 

 

 

参考资料:

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

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/575457.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

云服务器的主机名是否可以修改??

云服务器的主机名是否可以修改&#xff1f; 1 要是自己建的虚拟机等&#xff0c;这可以随便改&#xff0c;不影响。 2 要是云服务器&#xff0c;阿里云 华为云等&#xff0c;因为是项目上服务器厂商给提供的服务器信息&#xff0c;所以遇到问题需要改主机名时&#xff0c;为了…

CSS简介、行内样式、内部样式、外部样式、注释、引入其他CSS文件

CSS的发展历程&#xff1a; 起初是没有css的&#xff0c;只有少量样式是可以写在html标签中&#xff0c;这样代码格外显得臃肿&#xff0c;此时CSS就出现了。 初识CSS&#xff1a; CSS(Cascading Style Sheets),被称为CSS样式表或者层叠样式表&#xff0c;主要用于设置HTML页…

CISCO PVST+配置和结果验证 per vlan spanning tree(51cto 实验10)

1. 实验线路连接图使用Cisco Packet Tracer6.0 构建拓扑结构图 2. 实验内容(1) 参阅教材中内容&#xff0c;完成PVST的配置内容。(2) 在各台交换机上使用show spanning-tree vlan 10 和show spanning-tree vlan 20 命令&#xff0c;查看根桥信息、各端口角色和各端口状态。(3) …

http://mirrors.aliyuncs.com/centos/7/extras/x86_64/repodata/repomd.xml: [Errno 12] Timeout on http:/

对于这个点&#xff0c;我的情况是【errno12】&#xff0c; 众多帖子里还是请求404错误居多&#xff0c;情况不一样。我的安装阿里yum配置过程没问题&#xff0c;然后想起之前有过这样&#xff0c;怀疑是dns解析不到mirrors.aliyuncs.com这种地址&#xff0c;所以在dns文件里加…

Android网络课程笔记-----本地音乐播放

1. 本地音乐播放 多媒体&#xff1a; 图片&#xff1a;拍、图片查、图片编辑、摄像、图像处理算法 音频&#xff1a;录、回、编辑、MediaRecorde、MediaPlayer 视频&#xff1a;录、回、编辑、VideoView2. MediaPlayer的使用方法 MediaPlayer的声明周期转载…

CSS设置字体大小、字体粗细、字体风格

font-size:设置字体大小: 该属性值的单位可以使用相对单位和绝对单位&#xff0c;推荐使用px。(浏览器能够识别的最小像素是12px) p{font-size:20px;}常见尺寸单位&#xff1a; font-family:设置字体: 如果需要设置多个字体样式&#xff0c;则属性值可以写多个中间用逗号隔…

css设置字体颜色、文本对齐方式、首行缩进、文本装饰、列表样式、鼠标样式、禁止文本域拖拽、轮廓线、块级元素对齐方式、文字溢出设置

color:设置字体颜色: 取值方式有&#xff1a;1.颜色值red,green等 、2.十六进制#FF0000,#FF2313等、3.RGB代码rgb(225,225,112)或rgb(100%,55%,0%)&#xff0c;取值范围0-225&#xff0c;0%-100%&#xff0c;rgba是rgb的扩展&#xff0c;其中第四个参数设置的是透明度&#xf…

数字图像的5种增强处理

数字图像的5种增强处理#include<iostream>#include<cmath>using namespace std;int main(){ int i,j,n,m,w,a[100][100],x[100][100],max[100][100][20],b[100][100],k,p,u; cout<<"输入矩阵行列数:"; cin>>n>>m; cout<<"输…

css中标签显示模式、块元素、行内元素、行内块元素、显示模式转换

标签显示模式display: HTML标签一般分为块标签&#xff08;块元素&#xff1a;block-level&#xff09;和行内标签&#xff08;行内元素&#xff1a;inline-level&#xff09;两种类型&#xff0c;但是还有第三种说法行内块元素&#xff1a;table-row-group&#xff1a;设置元…

mysql 介绍 怎么下载 驱动jar包 各种细节问题大详解

对碰到的问题做个记录总结。 1 MySQL 的官网下载地址&#xff1a;http://www.mysql.com/downloads/版本说明。 1. MySQL Community Server 社区版本&#xff0c;开源免费&#xff0c;但不提供官方技术支持。 2. MySQL Enterprise Edition 企业版本&#xff0c;需付费&#xff…

css书写规范、行高

css书写规范&#xff1a; 空格规范&#xff1a; 选择器与花括号{之间必须包含空格&#xff0c;属性冒号&#xff1a;后面和属性值必须包含空格 .text {font-size: 16px;}选择器规范&#xff1a; 当有多个选择器同时出现时&#xff0c;每个选择器必须独占一行 .box,.nav,.mai…

CSS中的层叠性、继承性、优先级、权重

css三大特性&#xff1a; 三大特性&#xff1a;层叠性、继承性、优先级 层叠性&#xff1a; 指多种css样式的叠加&#xff0c;是浏览器处理多种css样式冲突的能力&#xff0c;如果给一个元素通过不同或者相同的选择器设置相同的属性但属性值不同时&#xff0c;权重相同的情况…

Nifi 怀疑出个bug 流程中的实时数据结果痕迹没有不是实时的,是之前的。以及相应解决办法。

1 在 Nifi 中做数据处理&#xff0c;有一个半小时之前执行过的流程&#xff0c;因为没设置好执行的时间&#xff0c;结果把读的数据库的表持续读成数据流 流到文件里&#xff0c;结果生成大量文件&#xff0c;一个文件就存着一张表的结果。 2 然后过了三十分钟吧&#xff0c;…

There is insufficient memory for the Java Runtime Environment to continue. NIFI 启动时报 jvm内存溢出

Nifi 突然启动报错。之前正常&#xff0c;停了两天再起就jj了。。 Nifi 解压路径还有log文件夹&#xff0c; 里面有各种日志文件可看。他把错误集中另存为了一个文件&#xff1a; 打开里面一通查看&#xff0c;调整。描述是java的运行环境jvm内存超出了&#xff0c;帖子…

CSS中盒子模型、嵌套盒子中垂直外边距塌陷问题解决方案、标准盒模型、怪异盒模型

盒子模型&#xff08;Box Model&#xff09;&#xff1a; 指把HTML页面中的元素看作是一个矩形的盒子&#xff0c;也称容器&#xff0c;这个盒子从内到外由&#xff1a;元素的内容&#xff08;content&#xff09;、内边距&#xff08;padding&#xff09;、边框&#xff08;b…

servlet/filter/listener/interceptor区别与联系(转)

由于最近两个月工作比较清闲&#xff0c;个人也比较“上进”&#xff0c;利用工作空余时间&#xff0c;也继续学习了一下&#xff0c;某天突然想起struts2和struts1的区别的时候&#xff0c;发现为什么struts1要用servlet&#xff0c;而struts2要用filter呢&#xff1f;一时又发…

Eclipse和IDEA 简单对比说明

Eclipse和IDEA Eclipse 当下最流行的IDE&#xff08;集成开发环境&#xff09;当属eclipse和idea莫属&#xff0c;不少新手都在问这两个ide哪个更好&#xff0c;今天给大家说一下自己这些年来使用这两款开发环境的心得。 一般情况下&#xff0c;问这个问题大多是新手&#xff0…

CSS中文档流之普通流,浮动及定位、浮动特性及清除浮动的方式、定位模式,子绝父相搭配定位方式、z-index层级

文档流&#xff1a; 普通流&#xff08;normal flow&#xff09;&#xff1a; 字面意思是普通流或者标准流&#xff0c;也就是常说的文档流&#xff0c;指网页内标签正常是从上到下&#xff0c;从左到右排列的意思&#xff0c;css的定位机制有3种&#xff1a;普通流&#xff…

VScode中常用element语法

Element语法&#xff1a; 熟练掌握element语法可以大大提高开发效率&#xff0c;建议在平时练习时留意element语法&#xff0c;下面是常用VScode中element语法&#xff1a; 1、快速生成HTML骨架&#xff1a;!Enter或Tab键 2、快速生成带有id或者class名的标签&#xff1a;标签…