访问者模式【行为模式C++】

1.概述

      访问者模式是一种行为设计模式, 它能将算法与其所作用的对象隔离开来。

      访问者模式主要解决的是数据与算法的耦合问题,尤其是在数据结构比较稳定,而算法多变的情况下。为了不污染数据本身,访问者会将多种算法独立归档,并在访问数据时根据数据类型自动切换到对应的算法,实现数据的自动响应机制,并确保算法的自由扩展。

       访问者模式在实际开发中使用的非常少,因为它比较难以实现并且应用该模式肯能会导致代码的可读性变差,可维护性变差,在没有特别必要的情况下,不建议使用访问者模式。

2.结构

访问者模式结构包括以下几个要素:

  • 抽象访问者(Visitor)角色:可以是接口或者抽象类,定义了一系列操作方法,用来处理所有数据元素,通常为同名的访问方法,并以数据元素类作为入参来确定那个重载方法被调用。
  • 具体访问者(ConcreteVisitor)角色:访问者接口的实现类,可以有多个实现,每个访问者都需要实现所有数据元素类型的访问重载方法。
  • 抽象元素(Element)角色:被访问的数据元素接口,定义了一个接受访问者的方法( accept ),其意义是指,每一个元素都要可以被访问者访问。
  • 具体元素(ConcreteElement)角色: 具体数据元素实现类,提供接受访问方法的具体实现,而这个具体的实现,通常情况下是使用访问者提供的访问该元素类的方法,其accept实现方法中调用访问者并将自己 "this" 传回。
  • 客户端 ( Client ) : 使用容器并初始化其中各类数据元素,并选择合适的访问者处理容器中的所有数据对象。

3.实现

3.1 实例类比

        假如有这样一位非常希望赢得新客户的资深保险代理人。 他可以拜访街区中的每栋楼, 尝试向每个路人推销保险。 所以, 根据大楼内组织类型的不同, 他可以提供专门的保单:

  • 如果建筑是居民楼, 他会推销医疗保险。
  • 如果建筑是银行, 他会推销失窃保险。

  

3.2 实例引入

  访问者模式可以被用于实现 KPI(关键绩效指标)考核系统。在这个场景下,你可以将员工、团队等作为对象结构的元素,而不同的 KPI 考核指标(如工作绩效、创新能力、团队协作等)作为不同的访问者。这样,你就可以灵活地添加新的考核指标,而无需修改对象结构中的元素类。

3.3  结构分析

在这个案例中,代码中的各个结构可以对应到策略模式中的不同角色:

  • 抽象访问者(Visitor)角色:对应代码Visitor接口,用于处理所有员工数据元素。
  • 具体访问者(ConcreteVisitor)角色:对应代码KPIVisitor,访问者具体实现。
  • 抽象元素(Element)角色:对应代码Employee,定义了一个接受访问者的方法( accept ),便于每一个元素都要可以被访问者访问。
  • 具体元素(ConcreteElement)角色::对应代码Manager、Engineer, 具体员工数据元素实现类,提供接受访问方法的具体实现,通常情况下accept实现方法中调用访问者并将自己 "this" 传回。

类图如下:

3.4 具体实现
#include <iostream>
#include <string>
using namespace std;
// 元素接口:员工
// 访问者接口:KPI 考核
class Visitor;
class Engineer;
class Manager;

class Employee {
public:
	virtual void accept(Visitor* visitor) = 0;
};

class Visitor {
public:
	virtual void visit(Engineer* engineer) = 0;
	virtual void visit(Manager* manager) = 0;
};


// 具体元素类:工程师
class Engineer :public Employee {

public:
	void accept(Visitor* visitor) {
		visitor->visit(this);
	}

	// 工程师的特有方法
	void doCoding() {
		std::cout << "工程师正在编码..." << endl;
	}
};

// 具体元素类:项目经理
class Manager :public Employee {

public:
	void accept(Visitor* visitor) {
		visitor->visit(this);
	}

	// 经理的特有方法
	void manageTeam() {
		std::cout << "经理正在管理团队..." << endl;
	}
};

// 具体访问者类:KPI 考核实现
class KPIVisitor :public Visitor {
	
public:
	void visit(Engineer *engineer) {
		std::cout << "工程师的工作绩效考核中..." << endl;
		engineer->doCoding();  // 工程师的特有工作
	}
	
	void visit(Manager* manager) {
		std::cout << "项目经理的工作绩效考核中..." << endl;
		manager->manageTeam();  // 经理的特有工作
	}
};

// 客户端测试

 int main() 
 {
	Employee *engineer = new Engineer();
	Employee *manager = new Manager();

	Visitor *kpiVisitor = new KPIVisitor();

	// 对工程师进行 KPI 考核
	engineer->accept(kpiVisitor);

	// 对经理进行 KPI 考核
	manager->accept(kpiVisitor);
	return 0;
}
3.5 运行结果

4.访问者模式优缺点

优点:

  • 扩展性好。在不修改对象结构中的元素的情况下,为对象结构中的元素添加新的功能。
  • 复用性好。通过访问者来定义整个对象结构通用的功能,从而提高复用程度。
  • 分离无关行为。通过访问者来分离无关的行为,把相关的行为封装在一起,构成一个访问者,这样每一个访问者的功能都比较单一。

缺点:

  • 对象结构变化很困难。在访问者模式中,每增加一个新的元素类,都要在每一个具体访问者类中增加相应的具体操作,这违背了“开闭原则”。
  • 违反了依赖倒置原则。访问者模式依赖了具体类,而没有依赖抽象类。
  • 违反了单一职责原则。访问者模式将相关操作集中到访问者类中,可能导致该类承担过多的责任,违反单一职责原则。
  • 违反了开放封闭原则。如果系统中新增了一个元素类,所有的具体访问者类都需要修改,不符合开闭原则。

5.应用场景

  • 当对象的数据结构相对稳定,而操作却经常变化的时候。
  • 比如,编译器的语法树分析:编译器可以使用访问者模式来遍历语法树,对不同类型的节点执行不同的操作。
  • 需要将数据结构与不常用的操作进行分离的时候。
  • 比如,扫描文件内容这个动作通常不是文件常用的操作,但是对于文件夹和文件来说,和数据结构本身没有太大关系(树形结构的遍历操作),扫描是一个额外的动作,如果给每个文件都添加一个扫描操作会太过于重复,这时采用访问者模式是非常合适的,能够很好分离文件自身的遍历操作和外部的扫描操作。
  • 需要在运行时动态决定使用哪些对象和方法的时候。
  • 比如,对于监控系统来说,很多时候需要监控运行时的程序状态,但大多数时候又无法预知对象编译时的状态和参数,这时使用访问者模式就可以动态增加监控行为。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

画板探秘系列:创意画笔第一期

前言 我目前在维护一款功能强大的开源创意画板。这个画板集成了多种创意画笔&#xff0c;可以让用户体验到全新的绘画效果。无论是在移动端还是PC端&#xff0c;都能享受到较好的交互体验和效果展示。并且此项目拥有许多强大的辅助绘画功能&#xff0c;包括但不限于前进后退、…

抖音24年4月16新规发布,“有效粉丝”少于500无法带货!

我是王路飞。 2024年4月16日&#xff0c;抖音发布了堪称今年“最严新规”。 调整了个人号视频/图文电商带货权限&#xff0c;个人号开通视频/图文的商品推广要求&#xff0c;粉丝要求从“粉丝量>1000”调整为"有效粉丝量>500"。 看似对粉丝数量的要求减少了…

Dynamics 365: 给D365设置一个黑色主题

在领英上看到一个好玩的东西&#xff0c;给D365可以设置暗黑的主题&#xff0c;但是这个目前我试了一下&#xff0c;仍然需要适配&#xff0c;很多地方显示的还是白色的&#xff0c;比如dashbaord里。 具体设置方法&#xff1a; 1. 设置你的D365为New Look新外观 2. 在D365的…

van-uploader 在app内嵌的webview中的一些坑

问题&#xff1a; 部分版本在ios 中没有问题&#xff0c;但是安卓中不触发图片选择和拍照&#xff08;之前是可以的&#xff0c;可能是没有锁定版本&#xff0c;重新发版导致的&#xff09;。在ios中下拉文案是英文&#xff0c;html配置lang等于 zh 也没有用&#xff0c;ios里…

护眼灯什么价位的好?五款性价比高的学生用台灯推荐!

在为学生选择护眼灯时&#xff0c;价格与性价比常常是家长们考虑的重点。价格并非唯一标准&#xff0c;但合适的价位确实能够让我们找到性价比高的产品。今天&#xff0c;我将为大家推荐五款特别适合学生使用的台灯&#xff0c;它们不仅价格适中&#xff0c;而且性能优越&#…

Windows电脑使用Everything+cpolar搭建在线资料库并实现无公网IP管理文件

文章目录 推荐前言1.软件安装完成后&#xff0c;打开Everything2.登录cpolar官网 设置空白数据隧道3.将空白数据隧道与本地Everything软件结合起来总结 推荐 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家…

【办公类-21-15】 20240410三级育婴师 712道单选题(题目与答案合并word)

作品展示 背景需求&#xff1a; 前文将APP题库里的育婴师题目下载到EXCEL&#xff0c;并进行手动整理 【办公类-21-13】 2024045三级育婴师 721道单选题 UIBOT下载整理-CSDN博客文章浏览阅读451次&#xff0c;点赞10次&#xff0c;收藏3次。【办公类-21-13】 2024045三级育婴…

【学习】软件信创测试中,如何做好兼容性适配

在软件信创测试的领域中&#xff0c;兼容性适配是至关重要的一环。如何确保软件在不同的操作系统、硬件设备和软件环境中稳定运行&#xff0c;是每个测试人员需要面对的挑战。本文将从几个方面探讨如何做好兼容性适配&#xff0c;以提高软件的稳定性和用户体验。 首先&#xf…

STM32学习和实践笔记(12):蜂鸣器实验

蜂鸣器主要分为两种&#xff0c;一种是压电式的无源蜂鸣器&#xff0c;一种是电磁式的有源蜂鸣器。 有源和无源是指其内部有没有振荡器。 无源的没有内部振荡器&#xff0c;需要输入1.5-5KHZ的音频信号来驱动压电蜂鸣片发声。 有源的内部有振荡器&#xff0c;因此只需要供给…

真实用户见证:爱校对——让您的文字更准确,工作更轻松

在快节奏的工作和学习中&#xff0c;精确无误的文字输出显得尤为重要。爱校对&#xff0c;一款依托清华大学计算机智能人机交互实验室的技术成果开发的校对工具&#xff0c;旨在帮助用户提升文字质量&#xff0c;确保沟通无误。 主体&#xff1a; 核心技术&#xff1a;爱校对…

COOH-Dextran羧基功能化葡聚糖 水凝胶药物载体

COOH-Dextran羧基功能化葡聚糖 水凝胶药物载体 【中文名称】羧基化葡聚糖 【英文名称】Dextran-COOH 【分 子 量】2K/3k/5K/10K/20K/40K/70K/100K/200k/400k/500k/1000k...... 【结 构 式】 【品 牌】碳水科技&#xff08;Tanshtech&#xff09; 【纯 度】95%以上 【…

【40分钟速成智能风控16】模型训练

目录 ​编辑 模型训练 逻辑回归 XGBoost Wide&Deep 模型部署 模型训练 确定了最终的入模变量&#xff0c;终于进入模型训练的环节了&#xff0c;在这个环节我们需要选定模型结构&#xff0c;调节模型超参数&#xff0c;以及评估模型的效果。为了得到一个兼具区分度和…

MySQL学习笔记3——条件查询和聚合函数

条件查询和聚合函数 一、条件查询语句二、聚合函数1、SUM&#xff08;&#xff09;2、AVG()、MAX()、MIN()3、COUNT&#xff08;&#xff09; 一、条件查询语句 WHERE 和 HAVING 的区别&#xff1a; WHERE是直接对表中的字段进行限定&#xff0c;来筛选结果&#xff1b;HAVIN…

相交链表(双指针)

160. 相交链表 - 力扣&#xff08;LeetCode&#xff09; 题目描述 给你两个单链表的头节点 headA 和 headB &#xff0c;请你找出并返回两个单链表相交的起始节点。如果两个链表不存在相交节点&#xff0c;返回 null 。 图示两个链表在节点 c1 开始相交&#xff1a; 题目数据…

#猫咪养护机模块功能分析

1.供电部分 AC转DC模块 220V交流转12V直流 系统的整体供电模块&#xff0c;可以直接接入220V交流电&#xff0c;并且输出12V直流电&#xff0c;12V直流电一方面供电给TB6600电机驱动板&#xff0c;一方面供电给PTC加热模块&#xff0c;还有一方面接入DCDC直流12转直流5V模块供…

定制Pro版研究区底图,为你的SCI论文增色!

研究区图&#xff08;Research Area Map&#xff09;是一种用于可视化学术研究内容所处地理位置的图表。论文中的研究区图不仅需要准确传达地理和地质数据&#xff0c;还应当在视觉上具有吸引力&#xff0c;以便更好地引起读者的兴趣。经常在高影响力的SCI论文中看到一些非常美…

半导体成品测试详述(Final Test,简称FT)

00、FT的一些概念 半导体成品测试&#xff08;Final Test&#xff0c;简称FT&#xff09;是在芯片封装完成后进行的最后一个测试阶段&#xff0c;其目的是确保芯片在实际应用中的性能和可靠性。FT测试可以包括环境测试、老化测试和应用特定的性能测试。 FT测试主要是为了解决各…

Stable Diffusion AI绘画宝典:从新手到高手,一图胜千言!

在这个数字化时代的浪潮中&#xff0c;人工智能技术以其惊人的创造力和创新性席卷全球。党的二十大报告把“实施科教兴国战略&#xff0c;强化现代化建设人才支撑”作为战略举措进行系统阐述&#xff0c;彰显我国不断发展新动能、新优势的决心和气魄。 Stable Diffusion是一款…

淘宝天猫玩具销售数据可视化

目录 背景描述数据说明数据来源1. 导入模块2. 乐高淘宝数据分析及其可视化2.1 乐高淘宝数据概览2.2 乐高淘宝数据处理2.3 乐高销量排名淘宝店铺Top502.4 乐高产地数量排名top502.5 天猫乐高价格分布2.6 不同价格区间的销售额整体表现分布2.7 淘宝乐高标题词云图 3. 乐高天猫旗舰…

06-java面向对象(中)封装与继承

6.1 封装 6.1.1 封装概述 1、为什么需要封装&#xff1f; 适当的封装可以让代码更容易理解与维护&#xff0c;也加强了代码的安全性。 通俗的讲&#xff0c;把该隐藏的隐藏起来&#xff0c;该暴露的暴露出来。这就是封装性的设计思想。 随着我们系统越来越复杂&#xff0c;…