访问者模式【行为模式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.应用场景

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

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

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

相关文章

选择、插入、冒泡、计数、堆、归并、快速排序算法的Java代码汇总和GUI界面时间测试与讲解

运行效果&#xff1a; Video_2024-04-16_150519 文章目录 前言&#xff1a;排序算法在数据结构和算法中的重要性一、排序算法详解1.选择排序2.插入排序3.冒泡排序4.计数排序5.堆排序6.归并排序7.快速排序 二、实现一个可以计算时间的Java GUI排序应用程序 前言&#xff1a;排序…

【Linux】进程间通信——system V版本 共享内存

目录 共享内存 原理 实践 shmget() 创建共享内存 shmctl() 删除共享内存 shmat() 挂接进程和共享内存 shmt() 进程和共享内存去关联 共享内存的特性 优势 劣势 用共享内存实现进程间通信 共享内存 原理 两个进程的PCB各自维护着一个进程地址空间。当两个进…

ViM-UNet:用于生物医学细分的 Vision Mamba

ViM-UNet&#xff1a;用于生物医学细分的 Vision Mamba 摘要IntroductionMethod and Experiments结果与讨论 ViM-UNet: Vision Mamba for Biomedical Segmentation 摘要 卷积神经网络&#xff08;CNNs&#xff09;&#xff0c;尤其是UNet&#xff0c;是生物医学分割的默认架构…

Linux安装部署Tomcat

个人简介&#xff1a;Java领域新星创作者&#xff1b;阿里云技术博主、星级博主、专家博主&#xff1b;正在Java学习的路上摸爬滚打&#xff0c;记录学习的过程~ 个人主页&#xff1a;.29.的博客 学习社区&#xff1a;进去逛一逛~ Linux安装部署Tomcat //将tomcat压缩包解压到对…

Innodb之redo日志

Innodb引擎执行流程 redo log ​ MySQL中的redo log&#xff08;重做日志&#xff09;是实现WAL&#xff08;预写式日志&#xff09;技术的关键组件&#xff0c;用于确保事务的持久性和数据库的crash-safe能力。借用《孔乙己》中酒店掌柜使用粉板记录赊账的故事&#xff0c;…

小程序视频下载器

下载高手&#xff0c;让小程序视频下载变得前所未有的简单&#xff01;专为非编程专业人士设计&#xff0c;该工具免去了繁琐的抓包软件学习过程&#xff0c;无需深入研究Fiddler或Charles的配置。它优化了视频、图片和音频资源的下载&#xff0c;提供直观的操作界面&#xff0…

拉普拉斯金字塔的频谱分析

1. 基本分析 拉普拉斯金字塔分解&#xff0c;主要由以下步骤组成&#xff1a; 对输入图像 L0 进行低通滤波&#xff0c;其中常采用高斯滤波&#xff1b;对低通滤波后的图像进行 1/2 倍率的下采样&#xff0c;这里的下采样通常是指直接取偶行且偶列&#xff08;以 0 开始计&am…

创建影子用户

文章目录 1.认识影子用户2.创建隐藏账户并加入管理员组3.修改注册表3.删除用户4.添加管理员权限 1.认识影子用户 影子用户通常指的是那些在系统用户列表中不可见&#xff0c;但在某些情况下可以进行操作的用户。在内网渗透过程中&#xff0c;当我们拿到shell时&#xff0c;肯定…

微博百度热搜收集

背景 大家都有使用微博、百度吧&#xff0c;而每天的热搜想必大家也用的不少。微博、百度的热搜有7、8种分类&#xff0c;每个单独查看比较耗费时间&#xff0c;效率极低&#xff0c;大概要花费3&#xff0c;4分钟左右。最近闲来无事&#xff0c;冒出个想法&#xff0c;是不是有…

rmallox勒索病毒#如何防范及处理?

rmallox勒索病毒介绍 rmallox将其特定的“.rmallox”扩展名添加到每个文件的名称中。例如&#xff0c;您命名为“my_dog.jpeg”的照片将被转换为“ my_dog.jpeg.rmallox”&#xff0c;在名为“ 资料.xlsx ”的Excel表格中报告——转换为“ 资料.xlsx.rmallox”&#xff0c;等等…

中医圆运动规律

目录 人体圆运动营气在十二经脉的运行规律子午流注与圆运动升降结合图 人体圆运动 营气在十二经脉的运行规律 营气在脉中&#xff0c;卫气在脉外 这个顺序也是子午流注的顺序 子午流注与圆运动升降结合图

DBA面试总结(Mysql篇)

一、delete与trancate的区别 相同点 1.两者都是删除表中的数据&#xff0c;不删除表结构 不同点 1.delete支持按条件删除&#xff0c;TRUNCATE不支持。 2.delete 删除后自增列不会重置&#xff0c;而TRUNCATE会被重置。 3.delete是逐条删除&#xff08;速度较慢&#xff09…