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

news2024/11/26 10:40:03

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.coloradmin.cn/o/1591014.html

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

相关文章

SpringBoot中使用Jackson序列化返回

SpringBoot中使用Jackson序列化返回 在Spring Boot应用中&#xff0c;使用Jackson库来处理JSON的序列化和反序列化是一种常见的做法。Jackson是一个高效的JSON处理器&#xff0c;广泛用于Java环境中&#xff0c;尤其是在与Spring框架集成时。本文将详细介绍如何在Spring Boot中…

Leetcode算法训练日记 | day24

一、组合问题 1.题目 Leetcode&#xff1a;第 77 题 给定两个整数 n 和 k&#xff0c;返回范围 [1, n] 中所有可能的 k 个数的组合。 你可以按 任何顺序 返回答案。 示例 1&#xff1a; 输入&#xff1a;n 4, k 2 输出&#xff1a; [[2,4],[3,4],[2,3],[1,2],[1,3],[1,4…

汽车咨询|基于SprinBoot的汽车资讯管理系统设计与实现(源码+数据库+文档)

汽车资讯管理系统目录 基于SprinBoot的汽车资讯管理系统设计与实现 一、前言 二、系统设计 三、系统功能设计 四、数据库设计 五、核心代码 六、论文参考 七、最新计算机毕设选题推荐 八、源码获取&#xff1a; 博主介绍&#xff1a;✌️大厂码农|毕设布道师&#xff…

关于 Amazon DynamoDB 的学习和使用

文章主要针对于博主自己的技术栈&#xff0c;从Unity的角度出发&#xff0c;对于 DynamoDB 的使用。 绿色通道&#xff1a; WS SDK for .NET Version 3 API Reference - AmazonDynamoDBClient Amazon DynamoDB Amazon DynamoDB is a fast, highly scalable, highly available,…

全景剖析SSD SLC Cache缓存设计原理-2

四、SLC缓存对SSD的寿命是否有优化&#xff1f; 当使用QLC或TLC NAND闪存并将其切换到SLC模式进行写入时&#xff0c;会对闪存的寿命产生以下影响&#xff1a; 短期寿命提升&#xff1a; SLC模式下&#xff0c;每个存储单元仅存储一个比特数据&#xff0c;相对于QLC或TLC来说…

matlab学习002-函数及流程控制语句

目录 一&#xff0c;matlab编程基础 1&#xff09;matlab脚本和函数文件 ①脚本文件 ②函数文件 2&#xff09;函数的定义和调用 ①定义 ②调用 3&#xff09;程序流程控制 ①使用for求 122^2……2^622^63之和 ②使用while语句求122^2……2^622^63之和 ③使用matl…

【御控物联】 Java JSON结构转换(2):对象To对象——属性重组

文章目录 一、JSON结构转换是什么&#xff1f;二、案例之《JSON对象 To JSON对象》三、代码实现四、在线转换工具五、技术资料 一、JSON结构转换是什么&#xff1f; JSON结构转换指的是将一个JSON对象或JSON数组按照一定规则进行重组、筛选、映射或转换&#xff0c;生成新的JS…

【Python】实现导入、提交文件并显示其路径的基础GUI界面

The tkinter package (“Tk interface”) 是一个基于Tcl/Tk GUI工具标准的Python接口。集合在大多数操作系统都有Tk和tkinter 库&#xff0c;包括MacOS&#xff0c;Window还有一些Unix类的操作系统 【基础操作】 1 设置窗口 # -*- coding: utf-8 -*- from tkinter import *#创…

2024年认证杯SPSSPRO杯数学建模D题(第一阶段)AI绘画带来的挑战全过程文档及程序

2024年认证杯SPSSPRO杯数学建模 D题 AI绘画带来的挑战 原题再现&#xff1a; 2023 年开年&#xff0c;ChatGPT 作为一款聊天型 AI 工具&#xff0c;成为了超越疫情的热门词条&#xff1b;而在 AI 的另一个分支——绘图领域&#xff0c;一款名为 Midjourney&#xff08;MJ&…

Matlab调C/C++简单模板例子

如果你是需要快速搭建一个matlab调c/c环境&#xff0c;这篇文章可以参考 有了c代码&#xff0c;想在matlab里面调用&#xff0c;可以参考我这个模板 matlab调用代码&#xff1a; clear all close all clcinput1 1; input2 2;[output1,output2] mexfunction(input1,input2);…

充电有喜分析

参考相关应用 华为市场 -> 充电有喜2.0.1网络查找 -> 充电有喜1.0.0 http://www.xz7.com/downinfo/609008.html反编译app有个文字漏洞&#xff0c;找到 来福充电宝 https://sj.qq.com/appdetail/com.evenhaexplo.courte 需要解决的问题 电源插拔注册为什么需要悬浮窗权…

Linux C柔性数组(零长数组)

零长数组&#xff0c;大小为0&#xff0c;一般用在结构体中&#xff08;网络通信&#xff0c;省流&#xff09;&#xff0c;节省空间&#xff0c;方便善后&#xff08;相对于指针类型&#xff09;&#xff0c;我们通过具体例子进行理解。 常规定长数组 #include <stdio.h&…

[温故] 红黑树算法

前言 最近在突然想起一些基础的东西, 向着温故知新, 有了些新的感悟和大家分享一下. 排序算法是数据结构的一个重要组成部分, 当时学习的时候没有少折腾, 这里来看看大佬们怎么运用这些数据结构来构建庞大的计算机体系的. 二叉树是排序算法的一个衍生, 基于二叉树的构建不同…

【路径规划】基于六次多项式的多关节机器人避障路径规划

最近迷上了机械臂避障轨迹规划&#xff0c;因为之前一直做的都是无障碍物轨迹规划&#xff0c;所以这次想试一下有障碍物的&#xff0c;把避障算法用在我的SimMechanics机械臂上&#xff0c;看看效果咋样。以下定义不区分路径规划和轨迹规划。   by the way&#xff0c;本文实…

一种跳板机的实现思路

一、 跳板机思路简介 本文所描述的跳板机&#xff08;下文称为“jmp”&#xff09;支持&#xff1a; Linux服务器 Windows服务器 其他终端&#xff08;MySQL终端、Redis终端、网络设备终端 等等&#xff09; 有别于市面上常见的jumpserver方案&#xff0c;使用本文所搭建的跳…

CSS实现卡片在鼠标悬停时突出效果

在CSS中&#xff0c;实现卡片在鼠标悬停时突出&#xff0c;通常使用:hover伪类选择器。 :hover伪类选择器用于指定当鼠标指针悬停在某个元素上时&#xff0c;该元素的状态变化。通过:hover选择器&#xff0c;你可以定义鼠标悬停在元素上时元素的样式&#xff0c;比如改变颜色、…

最新PDD批发Anti-Content参数逆向分析与算法还原

文章目录 1. 写在前面2. 接口分析3. 分析与扣代码 【&#x1f3e0;作者主页】&#xff1a;吴秋霖 【&#x1f4bc;作者介绍】&#xff1a;擅长爬虫与JS加密逆向分析&#xff01;Python领域优质创作者、CSDN博客专家、阿里云博客专家、华为云享专家。一路走来长期坚守并致力于Py…

Java(今天偷懒一丢丢

今天学了一点点io流 基本概念 输入流&#xff08;InputStream&#xff09;&#xff1a;用于从数据源读取数据。输出流&#xff08;OutputStream&#xff09;&#xff1a;用于向目标写入数据。 分类 按功能分类 字节流&#xff1a;处理字节数据&#xff0c;如 InputStream 和…

CSS aspect-ratio属性设置元素宽高比

aspect-ratio 是CSS的一个属性&#xff0c;用于设置元素的期望宽高比。它设置确保元素保持特定的比例&#xff0c;不受其内容或容器大小的影响。 语法&#xff1a; aspect-ratio: <ratio>;其中 <ratio> 是一个由斜杠&#xff08;/&#xff09;分隔的两个数字&…

韩顺平 | 零基础快速学Python(12) OOP基础

面向对象编程-基础 类与对象 类提供了把数据和功能绑定在一起的方法。创建新类时创建了新的对象类型&#xff0c;从而能够创建该类型的新实例/对象。 类时抽象的概念&#xff0c;作为数据类型代表一类事物&#xff1b;对象时具体实际的&#xff0c;作为实例代表具体事物&…