设计模式之访问者模式(C++)

news2024/12/23 9:17:43

作者:翟天保Steven
版权声明:著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处

一、访问者模式是什么?

       访问者模式是一种行为型的软件设计模式,表示一个作用于某对象结构中的各元素的操作。使得在不改变各元素类的前提下,能定义作用于这些元素的操作。

       该模式适合数据结构相对稳定且算法又易变化的系统。数据结构是被访问者,算法操作相当于访问者。

       访问者模式的优点:

  1. 良好扩展性。扩展对元素的操作,只需要添加访问者。
  2. 满足单一职责原则。相关的操作封装为一个访问者,使得访问者职责单一。
  3. 解耦。数据结构自身和作用于它的操作解耦合。

       访问者模式的缺点:

  1. 不易增加元素类。每增加一个元素类,访问者的接口和实现都要进行变化。
  2. 违背了依赖倒置原则。访问者依赖的是具体元素而不是抽象元素。
  3. 破坏封装。访问者可以获取被访问元素的细节。

二、访问者模式

2.1 结构图

       客户端即Main主函数,对象结构中存放了被访问的元素集合以及遍历各个元素的方法,使得抽象访问者可以依次与具体元素对接,完成访问。

2.2 代码示例

       场景描述:市长视察学校和企业。

//Visitor.h
/****************************************************/
#pragma once
#include <iostream>
#include <vector>
#include <string>
#include <algorithm>

using namespace std;

class Visitor;

// 抽象元素类-地点(被访问)
class Place 
{
public:
	// 构造函数
	Place(string name) : m_name(name) {}

	// 接受访问
	virtual void accept(Visitor* visitor) = 0;

	// 获取名字
	string getName() {
		return m_name;
	}

private:
	string m_name;
};

// 具体元素类-学校
class School : public Place 
{
public:
	// 构造函数
	School(string name) : Place(name) {}

	// 接受访问
	virtual void accept(Visitor* visitor);

};

// 具体元素类-企业
class Enterprise : public Place 
{
public:
	// 构造函数
	Enterprise(string name) : Place(name) {}

	// 接受访问
	virtual void accept(Visitor* visitor);

};

// 抽象访问者
class Visitor 
{
public:
	// 访问学校
	virtual void visitSchool(School* school) = 0;

	// 访问企业
	virtual void visitEnterprise(Enterprise* enterprise) = 0;

};

// 具体访问者-市长
class Mayor : public Visitor 
{
public:
	// 访问学校
	virtual void visitSchool(School* school) {
		cout << "市长参观了:" << school->getName() << endl;
		cout << "对老师和学生表达了诚挚的慰问。" << endl;
	}

	// 访问企业
	virtual void visitEnterprise(Enterprise* enterprise) {
		cout << "市长参观了:" << enterprise->getName() << endl;
		cout << "对企业的发展表示肯定。" << endl;
	}

};

// 访问行为类
class Visiting
{
public:
	// 添加被访问地点
	void add(Place* place) {
		places.push_back(place);
	}

	// 删除被访问地点
	void remove(Place* place) {
		places.erase(std::remove(places.begin(), places.end(), place), places.end());
	}

	// 进行访问
	void accept(Visitor* visitor) {
		for (auto place : places) {
			place->accept(visitor);
		}
	}

private:
	std::vector<Place*> places;
};
//Visitor.cpp
/****************************************************/
#include "Visitor.h"

// 接受访问
void School::accept(Visitor* visitor) {
	visitor->visitSchool(this);
}

// 接受访问
void Enterprise::accept(Visitor* visitor) {
	visitor->visitEnterprise(this);
}
//main.cpp
/****************************************************/
#include <iostream>
#include <string>
#include "Visitor.h"

using namespace std;

int main() 
{
	Visiting *visiting = new Visiting();
	Place *school = new School("东华大学");
	Place *enterprise = new Enterprise("华为");
	Visitor *mayor = new Mayor();

	// 添加被访问对象
	cout << "首日,";
	visiting->add(school);
	visiting->add(enterprise);
	// 安排市长进行访问
	visiting->accept(mayor);
	// 次日行程,删除某个被访问对象后再次访问
	cout << "次日,";
	visiting->remove(school);
	visiting->accept(mayor);

	// 删除
	delete visiting;
	delete school;
	delete enterprise;
	delete mayor;
	visiting = nullptr;
	school = nullptr;
	enterprise = nullptr;
	mayor = nullptr;

	return 0;
}

       程序结果如下。

       访问者模式使得访问操作与被访问元素解耦,同样是访问学校和企业,不同的访问者来干的事情和目的是不一样的,而这个不同的内容就可以在访问者类中实现。不过该模式不太适合增加新的元素,就像添加一个新的被访问对象-派出所,那每个访问者都要添加访问派出所的操作,违反了开闭原则。

三、总结

       我尽可能用较通俗的话语和直观的代码例程,来表述我对访问者模式的理解,或许有考虑不周到的地方,如果你有不同看法欢迎评论区交流!希望我举的例子能帮助你更好地理解访问者模式。

       如果文章帮助到你了,可以点个赞让我知道,我会很快乐~加油!

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

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

相关文章

函函函函函函函函函函函数——one

&#x1f929;本文作者&#xff1a;大家好&#xff0c;我是paperjie&#xff0c;感谢你阅读本文&#xff0c;欢迎一建三连哦。 &#x1f970;内容专栏&#xff1a;这里是《C知识系统分享》专栏&#xff0c;笔者用重金(时间和精力)打造&#xff0c;基础知识一网打尽&#xff0c;…

java: Compilation failed: internal java compiler error

问题描述&#xff1a; 今天学习一个新的框架 Jbolt-v3.0&#xff0c;然后将它通过 IDEA 导入&#xff0c;运行报错&#xff0c;如下显示&#xff1a; 接着我尝试了百度上的解决方案&#xff0c;依然没有解决&#xff0c;遂即记录一下。 原因分析&#xff1a; 出现这种报错的原…

聚观早报|飞猪:五一出游需求爆发;​特斯拉一季度盈利同比跌20%

今日要闻&#xff1a;飞猪&#xff1a;五一出游需求爆发&#xff1b;特斯拉一季度盈利同比暴跌20%&#xff1b;郑渊洁永远不再发表作品&#xff1b;KargoBot推出无人化自动驾驶卡车&#xff1b;中国6G通信技术研发取得重要突破 飞猪&#xff1a;五一出游需求爆发 4 月 19 日&a…

requests实现系统模拟登录

文章目录 requests模拟登录QWebEngine登录存储数据PySide2使用QWebEngineView报错extension_system_qt.cpp(122) failed to parse extension manifest requests模拟登录 使用requests发送post请求&#xff1b;获取响应头中的Set-Cookie的值&#xff1b;将该Cookie值存入浏览器…

图像ROI与mask掩码与图像几何变换

图像ROI与mask掩码与图像几何变换 感兴趣区域ROI: ⚫ ROI—(region of interest)—感兴趣区域 ⚫ 形状可有矩形&#xff0c;圆形&#xff0c;椭圆形等 ⚫ 能够确定分析重点&#xff0c;减少处理时间&#xff0c;提高精度 使用Rect起点终点范围 示例代码&#xff1a; import…

条码控件Aspose.BarCode入门教程(8):C#从图像中读取条形码

Aspose.BarCode for .NET 是一个功能强大的API&#xff0c;可以从任意角度生成和识别多种图像类型的一维和二维条形码。开发人员可以轻松添加条形码生成和识别功能&#xff0c;以及在.NET应用程序中将生成的条形码导出为高质量的图像格式。 Aspose API支持流行文件格式处理&am…

【对话ChatGPT】如何看待java行业内卷的问题?

本文首发自「慕课网」&#xff0c;想了解更多IT干货内容&#xff0c;程序员圈内热闻&#xff0c;欢迎关注"慕课网"&#xff01; 作者&#xff1a;ccLoveStudy 当今大环境&#xff0c;编程行业火热&#xff0c;而java行业更是首当其冲&#xff0c;但是为此&#xff0…

( “树” 之 Trie) 208. 实现 Trie (前缀树) ——【Leetcode每日一题】

知识点回顾 &#xff1a; Trie&#xff0c;又称前缀树或字典树&#xff0c;用于判断字符串是否存在或者是否具有某种字符串前缀。 ❓208. 实现 Trie (前缀树) 难度&#xff1a;中等 Trie&#xff08;发音类似 “try”&#xff09;或者说 前缀树 是一种树形数据结构&#xff…

基于ArcGIS Pro、R、INVEST等多技术融合下生态系统服务权衡与协同动态分析实践应用

生态系统服务是指生态系统所形成的用于维持人类赖以生存和发展的自然环境条件与效用&#xff0c;是人类直接或间接从生态系统中得到的各种惠益。联合国千年生态系统评估&#xff08;Millennium ecosystem assessment&#xff0c;MA&#xff09;提出生态系统服务包括供给、调节、…

SequoiaDB分布式数据库2023.3月刊

本月看点速览 赋能行业&#xff0c;参编《分布式数据库金融应用发展报告》 脱颖而出&#xff0c;入选2022专精特新黑马大赛年度十强 激烈角逐&#xff0c;成功晋级全国信创优秀解决方案决赛 新穗新彩&#xff0c;多家权威媒体走进巨杉 青杉计划2023持续进行&#xff0c;一起…

Java中字符串的初始化详解

前言 在深入学习字符串类之前&#xff0c;我们先搞懂JVM是怎样处理新生字符串的。当你知道字符串的初始化细节后&#xff0c;再去写String s "hello"或String s new String("hello")等代码时&#xff0c;就能做到心中有数。 首先得搞懂字符串常量池的概…

【流畅的Python学习笔记】2023.4.24

此栏目记录我学习《流畅的Python》一书的学习笔记&#xff0c;这是一个自用笔记&#xff0c;所以写的比较随意&#xff0c;随缘更新 用bisect来管理已排序的序列 bisect 模块包含两个主要函数&#xff0c;bisect 和 insort&#xff0c;两个函数都利用二分查找算法来在有序序列…

【Golang开发入门】你会真的会用Go写“Hello world“吗?

博主简介&#xff1a;努力学习的大一在校计算机专业学生&#xff0c;热爱学习和创作。目前在学习和分享&#xff1a;数据结构、Go&#xff0c;Java等相关知识。博主主页&#xff1a; 是瑶瑶子啦所属专栏: Go语言核心编程近期目标&#xff1a;写好专栏的每一篇文章 目录 一、Go项…

Linux下版本控制器(SVN) -命令行客户端

文章目录 进阶知识-Linux下版本控制器(SVN)5、命令行客户端5.1 创建两个工作区目录模拟两个开发人员5.2 检出5.3 添加5.4 提交5.5 查看服务器端文件内容5.6 更新操作5.7 冲突5.7.1 过时的文件5.7.2 冲突的产生5.7.3 冲突的表现5.7.4 冲突的手动解决5.7.5 冲突的半自动解决5.7.6…

ERTEC200P-2 PROFINET设备完全开发手册(10)

10. 固化程序 固件在SPI Flash的结构 由于绝大多数的设计都是使用SPI Flash&#xff0c;因此这里只介绍SPI Flash的烧写。ERTEC200P-2的固件在SPI Flash中的Layout如下图所示&#xff1a; 其中ROM Header&#xff1a;格式如下图所示&#xff1a; Firmware Binary: 协议栈固件…

【TypeScript】TS中type和interface在类型声明时的区别

🐱 个人主页:不叫猫先生 🙋‍♂️ 作者简介:2022年度博客之星前端领域TOP 2,前端领域优质作者、阿里云专家博主,专注于前端各领域技术,共同学习共同进步,一起加油呀! 💫优质专栏:vue3从入门到精通、TypeScript从入门到实践 📢 资料领取:前端进阶资料可以找我免…

RxJava中DISPOSED状态的被观察者任务执行onError/onSuccess导致的崩溃问题

RxJava中写了doOnError但还是导致应用崩溃问题记录 一、问题背景1.1 崩溃堆栈1.2 写demo代码复现相同逻辑 二、问题等价还原-复现2.1 代码位置&#xff1a;io.reactivex.internal.operators.single.SingleCreate.Emitter#onError 三、修复方法3.1 方案一&#xff1a;设置全局的…

springboot +flowable,处理 flowable 的用户和用户组(二)

一.简介 对于flowable是什么以及关于此框架的具体信息可以参看此项目的官方文档&#xff1a;https://www.flowable.org/docs/userguide/index.html Flowable is a light-weight business process engine written in Java.这是官网文档对此框架的完美解释&#xff1a;Flowable…

4·26世界知识产权日,Adobe助力认知和解决知识产权的那些事

2023年是中国与世界知识产权组织(WIPO)合作50周年&#xff0c;在第23个世界知识产权日来临之际&#xff08;每年4月26日定为世界知识产权日&#xff09;&#xff0c;让我们先来了解一下知识产权的相关知识吧&#xff01; ①“知识产权”的定义是什么&#xff1f; 知识产权是指…

FVM初启,Filecoin生态爆发着力点在哪?

Filecoin 小高潮 2023年初&#xff0c;Filecoin发文分享了今年的三项重大变更&#xff0c;分别是FVM、数据计算和检索市场的更新&#xff0c;这些更新消息在发布后迅速吸引了市场的广泛关注。 特别是在3月14日&#xff0c;Filecoin正式推出了FVM&#xff0c;这一变革使得File…