访问器模式(Visitor Pattern)

定义

访问器模式(Visitor Pattern)是一种将数据结构与数据操作分离的设计模式,它可以将对数据的操作添加到数据结构中,而不必修改已有的数据结构。这允许我们定义新的操作,而不需要修改已有的类结构。

访问器模式通常用于以下场景:

  1. 当一个数据结构包含许多不同类型的对象,你想对这些对象实施一些依赖于其具体类的操作,而不希望修改这些类的结构。
  2. 需要对一个数据结构进行很多不同且不相关的操作,你想避免让这些操作"污染"这些对象的类。

示例

以下是一个使用C++实现的访问器模式的简单示例:

#include <iostream>  
#include <vector>  // 定义元素类型  
enum ElementType { INT, DOUBLE, STRING };  // 定义元素基类  
class Element {  
public:  virtual ~Element() = default;  virtual ElementType getType() const = 0;  virtual void accept(class Visitor& visitor) = 0; // 声明接受访问者的函数  
};  // 具体元素类型  
class IntElement : public Element {  
private:  int value;  
public:  IntElement(int v) : value(v) {}  ElementType getType() const override { return INT; }  void accept(class Visitor& visitor) override { visitor.visit(this); } // 调用访问者的visit函数  int getValue() const { return value; }  
};  class DoubleElement : public Element {  
private:  double value;  
public:  DoubleElement(double v) : value(v) {}  ElementType getType() const override { return DOUBLE; }  void accept(class Visitor& visitor) override { visitor.visit(this); } // 调用访问者的visit函数  double getValue() const { return value; }  
};  class StringElement : public Element {  
private:  std::string value;  
public:  StringElement(const std::string& v) : value(v) {}  ElementType getType() const override { return STRING; }  void accept(class Visitor& visitor) override { visitor.visit(this); } // 调用访问者的visit函数  const std::string& getValue() const { return value; }  
};  // 定义访问者基类  
class Visitor {  
public:  virtual ~Visitor() = default;  virtual void visit(IntElement* element) = 0;  virtual void visit(DoubleElement* element) = 0;  virtual void visit(StringElement* element) = 0;  
};  // 具体访问者  
class ConcreteVisitor : public Visitor {  
public:  void visit(IntElement* element) override {  std::cout << "IntElement: " << element->getValue() << std::endl;  }  void visit(DoubleElement* element) override {  std::cout << "DoubleElement: " << element->getValue() << std::endl;  }  void visit(StringElement* element) override {  std::cout << "StringElement: " << element->getValue() << std::endl;  }  
};  int main() {  std::vector<Element*> elements;  elements.push_back(new IntElement(10));  elements.push_back(new DoubleElement(3.14));  elements.push_back(new StringElement("Hello World"));  ConcreteVisitor visitor;  for (auto element : elements) {  element->accept(visitor);  }  // 清理内存  for (auto element : elements) {  delete element;  }  return 0;  
}

解释

  1. 数据结构:我们定义了Element作为元素的基类,并提供了三个具体的元素类型:IntElementDoubleElementStringElement。每个具体元素类型都实现了accept方法,该方法接受一个Visitor对象。
  2. 访问者Visitor是访问者的基类,定义了三个visit方法,每个方法对应一个具体的元素类型。ConcreteVisitor是具体的访问者类,它实现了Visitor的所有方法,并在每个方法中实现了对应的操作。
  3. 操作:在main函数中,我们创建了一个元素列表,并遍历该列表,对每个元素调用其accept方法,并传入ConcreteVisitor对象。这样,ConcreteVisitor就可以对每个元素执行相应的操作,而不需要知道元素的具体类型。

访问者模式允许我们在不修改已有类结构的情况下增加新的操作。例如,如果我们要添加一个新的操作,只需要定义一个新的访问者类,实现其visit方法,而不需要修改已有的元素类。这种灵活性使得访问者模式在处理复杂的数据结构和对数据结构进行多种操作时非常有用。

  1. 扩展性:由于访问者模式将数据结构与数据操作分离,所以添加新的操作变得非常容易。你只需实现一个新的访问者类,而不需要修改已有的元素类。同样地,如果你需要添加新的元素类型,你只需要实现新的元素类,并更新访问者类以包含对新元素类型的处理。

  2. 封装性:访问者模式允许你封装复杂的数据结构,并通过访问者对象来提供对这些数据的操作。这意味着客户端代码可以保持简单,只与访问者接口交互,而不需要了解数据结构的内部细节。

  3. 双重分派:访问者模式实现了一种称为双重分派(double dispatch)的技术。这意味着方法的选择不仅依赖于对象的类型(如IntElementDoubleElement等),还依赖于在运行时调用的方法(如visit)。这种分派机制使得可以在运行时动态地确定应该执行哪个操作。

  4. 注意事项:虽然访问者模式具有很多优点,但也有一些潜在的问题。例如,如果你频繁地添加新的元素类型或操作,可能会导致访问者类变得非常庞大和复杂。此外,如果访问者类之间有很多共享的逻辑,可能需要考虑将这些共享逻辑提取到一个公共的基类或辅助类中,以避免代码重复。

总结

访问者模式是一种强大的设计模式,它允许你在不修改已有类结构的情况下增加新的操作。通过将数据结构与数据操作分离,访问者模式提供了灵活性和扩展性,使得你可以轻松地处理复杂的数据结构和对这些数据进行多种操作。然而,你也需要注意避免访问者类变得过于庞大和复杂,以及处理共享逻辑的问题。

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

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

相关文章

品牌百度百科应该怎样创建?编辑品牌百度百科词条的秘籍!

在数字化时代&#xff0c;品牌的故事不仅仅存在于广告牌和电视屏幕上&#xff0c;它们还在互联网的每一个角落悄然讲述。百度百科词条作为中国最大的中文百科全书&#xff0c;成为了品牌展示自身故事的重要舞台。那么&#xff0c;如何在这个舞台上留下你的品牌印记呢&#xff1…

solidity编程

一.Solidity 简介 Solidity 是⼀种⽤于编写以太坊虚拟机&#xff08; EVM &#xff09;智能合约的 编程语⾔。我认为掌握 Solidity 是参与链上项⽬的必备技 能&#xff1a;区块链项⽬⼤部分是开源的&#xff0c;如果你能读懂代码&#xff0c;就可以 规避很多亏钱项⽬。…

RK3568 android11 调试陀螺仪模块 MPU-6500

一&#xff0c;MPU6500功能介绍 1.简介 MPU6500是一款由TDK生产的运动/惯性传感器&#xff0c;属于惯性测量设备&#xff08;IMU&#xff09;的一种。MPU6500集成了3轴加速度计、3轴陀螺仪和一个板载数字运动处理器&#xff08;DMP&#xff09;&#xff0c;能够提供6轴的运动…

Outlook邮箱IMAP怎么开启?服务器怎么填?

Outlook邮箱IMAP服务器如何开启&#xff1f;Outlook设置IMAP的方法&#xff1f; Outlook邮箱作为其中的佼佼者&#xff0c;被广大用户所青睐。但在使用Outlook邮箱时&#xff0c;许多用户可能会碰到一个问题&#xff1a;如何开启IMAP服务&#xff1f;下面&#xff0c;蜂邮EDM就…

Go Barrier栅栏

1. 简介 实现与pythonthreading.Barrier库类似的功能&#xff0c;多线程同时等待达到指定数量一起放行。 有待改进地方&#xff1a; wait方法没有支持context控制。 2. 代码 import ("context""golang.org/x/sync/semaphore""sync/atomic" …

1222221

☞ 通用计算机启动过程 1️⃣一个基础固件&#xff1a;BIOS 一个基础固件&#xff1a;BIOS→基本IO系统&#xff0c;它提供以下功能&#xff1a; 上电后自检功能 Power-On Self-Test&#xff0c;即POST&#xff1a;上电后&#xff0c;识别硬件配置并对其进行自检&#xff0c…

解决鸿蒙模拟器卡顿的问题

缘起 最近在学习鸿蒙的时候&#xff0c;发现模拟器非常卡&#xff0c;不要说体验到鸿蒙的丝滑&#xff0c;甚至到严重影响使用的程度。 根据我开发Android的经验和在论坛翻了一圈&#xff0c;最终总结出了以下几个方案。 创建模拟器 1、在DevEco Virtual Device Configurat…

歌尔气压计SPA06-003在无人机和手表上的创新应用

随着科技的不断进步&#xff0c;各类智能设备的功能日益强大&#xff0c;其中气压计作为一种能够测量大气压力的传感器&#xff0c;已被广泛应用于多种领域。歌尔气压计以其高精度、低功耗的特点&#xff0c;在无人机和智能手表上的应用尤为突出&#xff0c;为这两个领域的产品…

【InternLM 实战营笔记】LMDeploy 的量化和部署

环境配置 vgpu-smi 查看显卡资源使用情况 新开一个终端执行下面的命令实时观察 GPU 资源的使用情况。 watch vgpu-smi复制环境到我们自己的 conda 环境 /root/share/install_conda_env_internlm_base.sh lmdeploy激活环境 conda activate lmdeploy安装依赖库 # 解决 Modu…

day04_拦截器Apifox角色管理(登录校验,API接口文档,权限管理说明,角色管理,添加角色,修改角色,删除角色)

文章目录 1. 登录校验1.1 需求说明1.2 实现思路1.3 ThreadLocal1.4 AuthContextUtil1.5 拦截器使用1.5.1 拦截器开发1.5.2 拦截器注册 1.6 代码优化1.6.1 配置优化1.6.2 代码优化1.6.3 前端修改 2. API接口文档2.1 Apifox接口管理平台2.1.1 接口管理平台简介2.1.2 Apifox简介2.…

2.1基本算法之枚举1812:完美立方

形如a3 b3 c3 d3的等式被称为完美立方等式。例如123 63 83 103 。编写一个程序&#xff0c;对任给的正整数N (N≤100)&#xff0c;寻找所有的四元组(a, b, c, d)&#xff0c;使得a3 b3 c3 d3&#xff0c;其中a,b,c,d 大于 1, 小于等于N&#xff0c;且b<c<d。 #in…

java面试:elasticsearch

文章目录 引言I 索引1.1 覆盖索引1.2 elasticsearch 面试题1.3 Google的搜索本质II elasticsearch的倒叙索引2.1 发展历史2.2 倒排索引2.3 倒排序的搜索流程III elasticsearch的基础概念IV 创建索引库4.1 步骤4.2 mapping映射4.3 ik分词器

【kubernetes】关于云原生之k8s集群的pod理论详解

目录 一、pod的基础概念 什么是pod&#xff1f; k8s集群中pod的两种使用方式 pod中运行容器的原则&#xff1a; 创建pod的3种方式 第一种&#xff1a;自主式Pod 第二种&#xff1a;控制器管理的Pod 第三种&#xff1a;静态Pod 二、pod中容器的基础概念 pod容器的分类 …

记录工作中遇见问题、学习项

1、判空操作 Demo demo Optional .ofNullable(demoService.getById(id)) .orElseThrow(() -> new ServiceException("不存在id为" id "的数据")); 2、SQL方面 1、group by : GROUP BY 子句必须放在 WHERE 子句中的条件之后&#…

Apache SeaTunnel 及 Web 功能部署指南(小白版)

在大数据处理领域&#xff0c;Apache SeaTunnel 已成为一款备受青睐的开源数据集成平台&#xff0c;它不仅可以基于Apache Spark和Flink&#xff0c;而且还有社区单独开发专属数据集成的Zeta引擎&#xff0c;提供了强大的数据处理能力。随着SeaTunnel Web的推出&#xff0c;用户…

雾锁王国服务器要开服务器吗?

雾锁王国要开服务器吗&#xff1f;可以使用官方服务器&#xff0c;也可以自己搭建多人联机服务器&#xff0c;更稳定不卡&#xff0c;畅玩开黑。阿腾云分享atengyun.com给大家目前阿里云和腾讯云均提供雾锁王国服务器和一键搭建程序&#xff0c;成本26元即可搭建一台自己的雾锁…

post请求同时上传文件并传递其他参数的前后端写法

最近有一需求&#xff0c;post请求从前端上传一个文件同时传递一个参数&#xff0c;多次实验后记录下两种写法&#xff1a; 方法一&#xff1a; 前端&#xff1a;重点是设置请求头代码如下&#xff1a; getfile(event) {//input框输入文件let file event.target.files[0];l…

h5和app原生通信的方法,什么是jsBridge,jsBridge 原理和步骤

H5 和 App 原生应用之间通信的方法 url schemejsBridge 也就是 javascript interface原生应用通过注入 JavaScript 接口到 WebView 中&#xff0c;让 H5 页面可以调用原生方法&#xff0c;从而实现双向通信【本质还是利用了 android webview 提供了注入的方法】WebSocketHybri…

Keepalived双机热备——Haproxy搭建web群集

一、认识keepalived keepalived是一个开源的软件&#xff0c;用于实现高可用性和负载均衡。它主要用于在多个服务器之间提供故障转移和负载均衡的功能。keepalived可以监控服务器的状态&#xff0c;并在主服务器发生故障时自动将备份服务器切换为主服务器&#xff0c;以确保服…

高压高能碳陶瓷无感电阻的制作以及应用?

由于现有需求&#xff0c;许多现代电子电路和设备都会经历瞬态脉冲和浪涌。这反过来又导致需要“设计”瞬态浪涌保护&#xff0c;尤其是在电机控制器等电路中。当电机启动时&#xff0c;此时消耗的电流过大&#xff0c;可能导致电阻器故障。同样&#xff0c;如果电容器用于电机…