23种设计模式-访问者(Visitor)设计模式

文章目录

  • 一.什么是访问者模式?
  • 二.访问者模式的结构
  • 三.访问者模式的应用场景
  • 四.访问者模式的优缺点
  • 五.访问者模式的C++实现
  • 六.访问者模式的JAVA实现
  • 七.代码解释
  • 八.总结

类图: 访问者设计模式类图

一.什么是访问者模式?

访问者模式(Visitor Pattern)是一种行为型设计模式,允许在不更改元素类的情况下,为对象结构中的元素增加新的操作。访问者模式通过将操作从元素类中抽离出来,实现操作的扩展。
 在访问者模式中,核心思想是将数据结构和操作分开,数据结构负责提供必要的接口,而具体的操作逻辑由访问者实现。

二.访问者模式的结构

  • Visitor(访问者接口):声明一组访问方法,每个方法对应一种具体的元素类型。
  • ConcreteVisitor(具体访问者):实现访问者接口中声明的操作,对不同的元素提供不同的处理。
  • Element(元素接口):定义一个Accept方法,用于接收访问者对象。
  • ConcreteElement(具体元素):实现元素接口,并在Accept方法中调用访问者的相应方法。
  • ObjectStructure(对象结构):提供元素的容器,负责存储和遍历元素。
    在这里插入图片描述

三.访问者模式的应用场景

  1. 数据结构稳定,操作逻辑需要频繁变化:例如编译器中的语法树遍历。
  2. 需要对一组不相关的类执行操作:如不同形状的图形对象(圆形、矩形等)。
  3. 需要集中管理行为,而不想污染元素类

四.访问者模式的优缺点

  • 优点
    • 增加新的操作很方便,只需新增一个具体访问者类。
    • 遵循单一职责原则,将操作与元素本身解耦。
  • 缺点
    • 增加新的元素类型需要修改所有访问者,违背了开闭原则。
    • 对象结构不容易扩展。

五.访问者模式的C++实现

#include <iostream>
#include <vector>
#include <memory>// 前置声明,避免循环引用
class ConcreteElementA;
class ConcreteElementB;
class Visitor;// 访问者接口(Visitor)
class Visitor {
public:virtual void visitConcreteElementA(ConcreteElementA& element) = 0;virtual void visitConcreteElementB(ConcreteElementB& element) = 0;virtual ~Visitor() = default;
};// 元素接口(Element)
class Element {
public:virtual void accept(std::shared_ptr<Visitor> visitor) = 0;virtual ~Element() = default;
};// 具体元素 A(ConcreteElementA)
class ConcreteElementA : public Element {
public:void accept(std::shared_ptr<Visitor> visitor) override {visitor->visitConcreteElementA(*this);}void operationA() {std::cout << "ConcreteElementA specific operation.\n";}
};// 具体元素 B(ConcreteElementB)
class ConcreteElementB : public Element {
public:void accept(std::shared_ptr<Visitor> visitor) override {visitor->visitConcreteElementB(*this);}void operationB() {std::cout << "ConcreteElementB specific operation.\n";}
};// 具体访问者 1(ConcreteVisitor1)
class ConcreteVisitor1 : public Visitor {
public:void visitConcreteElementA(ConcreteElementA& element) override {std::cout << "ConcreteVisitor1 visiting ConcreteElementA.\n";element.operationA();}void visitConcreteElementB(ConcreteElementB& element) override {std::cout << "ConcreteVisitor1 visiting ConcreteElementB.\n";element.operationB();}
};// 具体访问者 2(ConcreteVisitor2)
class ConcreteVisitor2 : public Visitor {
public:void visitConcreteElementA(ConcreteElementA& element) override {std::cout << "ConcreteVisitor2 visiting ConcreteElementA.\n";element.operationA();}void visitConcreteElementB(ConcreteElementB& element) override {std::cout << "ConcreteVisitor2 visiting ConcreteElementB.\n";element.operationB();}
};// 对象结构(ObjectStructure)
class ObjectStructure {
private:std::vector<std::shared_ptr<Element>> elements;public:void addElement(std::shared_ptr<Element> element) {elements.push_back(element);}void accept(std::shared_ptr<Visitor> visitor) {for (auto& element : elements) {element->accept(visitor);}}
};// 测试代码
int main() {// 创建对象结构ObjectStructure objectStructure;// 添加元素objectStructure.addElement(std::make_shared<ConcreteElementA>());objectStructure.addElement(std::make_shared<ConcreteElementB>());// 创建访问者 1 并访问std::shared_ptr<Visitor> visitor1 = std::make_shared<ConcreteVisitor1>();std::cout << "Using ConcreteVisitor1:\n";objectStructure.accept(visitor1);// 创建访问者 2 并访问std::shared_ptr<Visitor> visitor2 = std::make_shared<ConcreteVisitor2>();std::cout << "\nUsing ConcreteVisitor2:\n";objectStructure.accept(visitor2);return 0;
}

六.访问者模式的JAVA实现

// 抽象访问者
interface Visitor {void VisitConcreteElementA(ConcreteElementA elementA);void VisitConcreteElementB(ConcreteElementB elementB);
}// 具体访问者1
class ConcreteVisitor1 implements Visitor {@Overridepublic void VisitConcreteElementA(ConcreteElementA elementA) {System.out.println("ConcreteVisitor1 visiting ConcreteElementA");}@Overridepublic void VisitConcreteElementB(ConcreteElementB elementB) {System.out.println("ConcreteVisitor1 visiting ConcreteElementB");}
}// 具体访问者2
class ConcreteVisitor2 implements Visitor {@Overridepublic void VisitConcreteElementA(ConcreteElementA elementA) {System.out.println("ConcreteVisitor2 visiting ConcreteElementA");}@Overridepublic void VisitConcreteElementB(ConcreteElementB elementB) {System.out.println("ConcreteVisitor2 visiting ConcreteElementB");}
}// 抽象元素
abstract class Element {public abstract void Accept(Visitor visitor);
}// 具体元素A
class ConcreteElementA extends Element {@Overridepublic void Accept(Visitor visitor) {visitor.VisitConcreteElementA(this);}public void OperationA() {System.out.println("ConcreteElementA specific operation.");}
}// 具体元素B
class ConcreteElementB extends Element {@Overridepublic void Accept(Visitor visitor) {visitor.VisitConcreteElementB(this);}public void OperationB() {System.out.println("ConcreteElementB specific operation.");}
}// 对象结构
class ObjectStructure {private final List<Element> elements = new ArrayList<>();public void Add(Element element) {elements.add(element);}public void Accept(Visitor visitor) {for (Element element : elements) {element.Accept(visitor);}}
}// 客户端代码
public class VisitorPatternDemo {public static void main(String[] args) {// 创建对象结构ObjectStructure structure = new ObjectStructure();// 添加具体元素structure.Add(new ConcreteElementA());structure.Add(new ConcreteElementB());// 创建并使用访问者1ConcreteVisitor1 visitor1 = new ConcreteVisitor1();structure.Accept(visitor1);// 创建并使用访问者2ConcreteVisitor2 visitor2 = new ConcreteVisitor2();structure.Accept(visitor2);}
}

七.代码解释

  1. Element 接口和 ConcreteElement
    • Element接口定义了一个accept方法,具体元素类需要实现该方法,并在其中调用访问者的相应方法。
  2. Visitor 接口和 ConcreteVisitor
    • Visitor接口声明了针对每种具体元素的访问方法。
    • ConcreteVisitor1和ConcreteVisitor2实现了Visitor接口,并定义了对ConcreteElementA和ConcreteElementB的具体操作。
  3. ObjectStructure 类
    • ObjectStructure维护了一个元素集合,并提供accept方法,用于将访问者传递给集合中的每个元素。
  4. 测试代码
    • 创建了一个对象结构,并添加了两种具体元素。
    • 使用两个不同的访问者访问元素集合,展示了访问者模式的扩展性。

八.总结

访问者模式是一种将操作和数据结构分离的强大工具。当需要频繁添加新的操作或行为时,它提供了扩展性良好的解决方案。通过访问者模式,可以大幅简化复杂操作的管理,提升代码的可读性和维护性

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

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

相关文章

【开源免费】基于Vue和SpringBoot的在线考试系统(附论文)

本文项目编号 T 624 &#xff0c;文末自助获取源码 \color{red}{T624&#xff0c;文末自助获取源码} T624&#xff0c;文末自助获取源码 网络的广泛应用给生活带来了十分的便利。所以把在线考试管理与现在网络相结合&#xff0c;利用java技术建设在线考试系统&#xff0c;实现…

【H2O2|全栈】MySQL的云端部署

目录 前言 开篇语 准备工作 MySQL移除 为什么需要移除&#xff1f; 移除操作 Yum仓库 yum简介 rpm安装 yum库安装 MySQL安装 使用yum安装 开机自启动 检查运行状态 MySQL配置 初始密码 ​编辑登录 修改root密码 退出MySQL 字符集配置 重启数据库 结束语 …

DAY30|贪心算法Part04|LeetCode:452. 用最少数量的箭引爆气球、435. 无重叠区间、763.划分字母区间

目录 LeetCode:452. 用最少数量的箭引爆气球 基本思路 C代码 LeetCode:435. 无重叠区间 基本思路 C代码 LeetCode:763.划分字母区间 基本思路 C代码 LeetCode:452. 用最少数量的箭引爆气球 力扣代码链接 文字讲解&#xff1a;LeetCode:452. 用最少数量的箭引爆气球 视…

Enterprise Architect 16 下载、安装与无限30天操作

文章目录 Enterprise Architect 16 简介&#xff08;一&#xff09;支持多种建模语言和标准&#xff08;二&#xff09;强大的版本控制、协作和文档管理功能&#xff08;三&#xff09;增强的技术和用户体验&#xff08;四&#xff09;高级功能和扩展性 一&#xff0c;下载软件…

31.3 XOR压缩和相关的prometheus源码解读

本节重点介绍 : xor 压缩value原理xor压缩过程讲解xor压缩prometheus源码解读xor 压缩效果 xor 压缩value原理 原理:时序数据库相邻点变化不大&#xff0c;采用异或压缩float64的前缀和后缀0个数 xor压缩过程讲解 第一个值使用原始点存储计算和前面的值的xor 如果XOR值为0&…

解决 IDEA 修改代码重启不生效的问题

前言 在使用 IntelliJ IDEA 进行 Java 项目开发时&#xff0c;有时会遇到一个令人头疼的问题&#xff1a;修改了代码后&#xff0c;重启服务却发现更改没有生效。通常情况下&#xff0c;解决这个问题需要通过 Maven 的 clean 和 compile 命令来强制重新编译&#xff0c;但这显…

java 根据 pdf 模板带图片文字生成pdf文件

在现代应用开发中,自动生成包含动态内容的 PDF 文档在电子发票、合同生成、表单填充等场景中有着广泛的应用。本文将介绍如何使用 iText 库动态填充 PDF 模板字段,并在指定位置插入签名和公章图片。 项目需求 假设我们有一个 PDF 模板文件,包含表单字段,如用户姓名、地址…

MTK主板定制_联发科主板_MTK8766/MTK8768/MTK8788安卓主板方案

主流市场上的MTK主板通常采用联发科的多种芯片平台&#xff0c;如MT8766、MT6765、MT6762、MT8768和MT8788等。这些芯片基于64位Cortex-A73/A53架构&#xff0c;提供四核或八核配置&#xff0c;主频可达2.1GHz&#xff0c;赋予设备卓越的计算与处理能力。芯片采用12纳米制程工艺…

Windows仿macOS?看这一篇就够了

如果你有任何关于Windows仿macOS的问题&#xff0c;可加入942644281 &#xff08;QQ群&#xff09; Date9.20更新&#xff1a;增加功能按键左移部分Date9.16更新&#xff1a;增加了大多数资源的网盘链接Date9.15更新&#xff1a;增加StartAllBack&#xff0c;资源管理器调整部…

无法下载element-admin的依赖无法运行

目录 无法下载element-admin的依赖偷懒方法完美方法 运行element-admin错误 之前在下载element-admin时遇到了多多少少的问题 无法下载element-admin的依赖 偷懒方法 开始是从github下载源码后安装依赖时在与tui-editor相关的依赖时就会卡死&#xff0c;然后报错&#xff0c…

基于Java Springboot幼儿园管理系统

一、作品包含 源码数据库设计文档万字PPT全套环境和工具资源部署教程 二、项目技术 前端技术&#xff1a;Html、Css、Js、Vue、Element-ui 数据库&#xff1a;MySQL 后端技术&#xff1a;Java、Spring Boot、MyBatis 三、运行环境 开发工具&#xff1a;IDEA/eclipse 数据…

新一代API开发工具,让API调试更快 更简单

新一代API开发工具 代理调试 请求测试一站式解决方案 Reqable Fiddler Charles Postman, 让API调试更快 &#x1f680; 更简单 &#x1f44c; 直接上下载地址 根据系统,下载对应的版本即可 https://reqable.com/zh-CN/download/

Python | Leetcode Python题解之第564题寻找最近的回文数

题目&#xff1a; 题解&#xff1a; class Solution:def nearestPalindromic(self, n: str) -> str:m len(n)candidates [10 ** (m - 1) - 1, 10 ** m 1]selfPrefix int(n[:(m 1) // 2])for x in range(selfPrefix - 1, selfPrefix 2):y x if m % 2 0 else x // 10…

爬虫——数据解析与提取

第二节&#xff1a;数据解析与提取 在网络爬虫开发中&#xff0c;获取网页内容&#xff08;HTML&#xff09;是第一步&#xff0c;但从这些内容中提取有用的数据&#xff0c;才是爬虫的核心部分。HTML文档通常结构复杂且充满冗余信息&#xff0c;因此我们需要使用高效的解析工…

使用 Ant Design Vue 自定渲染函数customRender实现单元格合并功能rowSpan

使用 Ant Design Vue 自定渲染函数customRender实现单元格合并功能rowSpan 背景 在使用Ant Design Vue 开发数据表格时&#xff0c;我们常常会遇到需要合并单元格的需求。 比如&#xff0c;某些字段的值可能会在多行中重复出现&#xff0c;而我们希望将这些重复的单元格合并为…

RabbitMQ教程:发布/订阅模式(Publish/Subscribe)(三)

文章目录 RabbitMQ教程&#xff1a;发布/订阅模式&#xff08;Publish/Subscribe&#xff09;&#xff08;三&#xff09;一、引言二、简介三、准备工作3.1 说明3.2 生成项目 四、实战4.1 交换机&#xff08;Exchanges&#xff09;4.2 临时队列&#xff08;Temporary Queues&am…

CANoe发送和接收CAN DataBase(DBC文件)数据

目录 1、接收CAN数据&#xff0c;DBC解析数据内容 2、发送DBC定义的CAN报文 CANoe是一款强大的网络仿真和开发工具&#xff0c;它支持发送和接收基于CAN DataBase&#xff08;DBC文件&#xff09;的数据。 1、接收CAN数据&#xff0c;DBC解析数据内容 要使用CANoe接收CAN数…

【第六课】Rust所有权系统(二)

目录 前言 借用和引用 借用规则 切片和迭代器 总结 前言 上节课介绍了Rust中的所有权系统&#xff0c;简单回顾一下&#xff0c;rust的内存系统系统&#xff0c;每一块内存都有一个主人&#xff0c;主人对这块内存有着读写和释放的权限&#xff0c;当主人离开作用域之后&am…

ISUP协议视频平台EasyCVR私有化部署视频平台如何实现RTMP推流将大疆无人机的视频画面回传?

在现代视频监控和流媒体技术领域&#xff0c;EasyCVR视频融合云平台以其卓越的性能和灵活性&#xff0c;成为了跨区域、网络化视频监控综合管理的理想选择。作为TSINGSEE青犀视频“云边端”架构体系中的核心组件&#xff0c;私有化部署视频平台EasyCVR不仅能够实现视频数据的集…

排序算法 -归并排序

文章目录 1. 归并排序&#xff08;Merge Sort&#xff09;1.1 简介1.2 归并排序的步骤1.3 归并排序c 语言实现代码说明 1.4 时间复杂度1.5 空间复杂度1.6 动画 1. 归并排序&#xff08;Merge Sort&#xff09; 1.1 简介 归并排序&#xff08;Merge Sort&#xff09;是一种基于…