当前位置: 首页 > news >正文

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. 测试代码
    • 创建了一个对象结构,并添加了两种具体元素。
    • 使用两个不同的访问者访问元素集合,展示了访问者模式的扩展性。

八.总结

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

相关文章:

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

文章目录 一.什么是访问者模式&#xff1f;二.访问者模式的结构三.访问者模式的应用场景四.访问者模式的优缺点五.访问者模式的C实现六.访问者模式的JAVA实现七.代码解释八.总结 类图&#xff1a; 访问者设计模式类图 一.什么是访问者模式&#xff1f; 访问者模式&#xff08;…...

ssm150旅游网站的设计与实现+jsp(论文+源码)_kaic

毕 业 设 计&#xff08;论 文&#xff09; 题目&#xff1a;旅游网站设计与实现 摘 要 现代经济快节奏发展以及不断完善升级的信息化技术&#xff0c;让传统数据信息的管理升级为软件存储&#xff0c;归纳&#xff0c;集中处理数据信息的管理方式。本旅游网站就是在这样的大…...

【SKFramework框架】一、框架介绍

推荐阅读 CSDN主页GitHub开源地址Unity3D插件分享QQ群&#xff1a;398291828小红书小破站 大家好&#xff0c;我是佛系工程师☆恬静的小魔龙☆&#xff0c;不定时更新Unity开发技巧&#xff0c;觉得有用记得一键三连哦。 一、前言 【Unity3D框架】SKFramework框架完全教程《全…...

Arcgis地图实战三:自定义导航功能的实现

文章目录 1.最终效果预览2.计算两点之间的距离3.将点线画到地图上4.动态展示点线的变化5.动态画线6.动态画点 1.最终效果预览 2.计算两点之间的距离 let dis this.utilsTools.returnDisByCoorTrans(qdXYData, zdXYData, "4549")当距离小于我们在配置文件中预设置的…...

LLaMA-Factory 上手即用教程

LLaMA-Factory 是一个高效的大型语言模型微调工具&#xff0c;支持多种模型和训练方法&#xff0c;包括预训练、监督微调、强化学习等&#xff0c;同时提供量化技术和实验监控&#xff0c;旨在提高训练速度和模型性能。 官方开源地址&#xff1a;https://github.com/hiyouga/L…...

黑马点评 秒杀下单出现的问题:服务器异常---java.lang.NullPointerException: null(已解决)

前言&#xff1a; 在此之前找了好多资料&#xff0c;查了很多&#xff0c;都没有找到对应解决的方法&#xff0c;虽然知道是userid为空&#xff0c;但不知道要修改哪里&#xff0c;还是自己的debug能力不足&#xff0c;以后得多加练习。。。 问题如下&#xff1a; 点击限时抢…...

购物街项目TabBar的封装

1.TabBar介绍 在购物街项目中 不论页面如何滚动 始终存在一个TabBar固定在该项目的底部 他在该项目中 扮演者选项卡栏的角色 内部存在若干选项 而选项中 固定存在两部分(图片文本) 其中主要涉及到TabBar/TabBarItem这些和业务无关的共享组件(建议存放于components/common中)、…...

C++游戏开发面试题及参考答案

目录 在游戏开发中,为什么选择 C++ 作为编程语言? 为什么 C++ 语言更适合游戏开发? 描述游戏中的碰撞检测的基本原理。 解释游戏中的碰撞检测机制,并用 C++ 举例说明如何实现。 描述游戏中的物理模拟的基本原理。 阐述游戏中的物理模拟,如重力模拟在 C++ 中的实现方…...

字符串的基本操作(C语言版)

一、实验内容&#xff1a; 采用顺序结构存储串&#xff0c;编写一个函数substring(strl,str2)&#xff0c;用于判定str2是否为strl的子串&#xff1b;编写一个函数&#xff0c;实现在两个已知字符串中找出所有非空最长公共子串的长度和最长公共子串的个数&#xff1b; ①字符…...

C缺陷与陷阱 — 7 可移植性缺陷

目录 1 应对C语言标准变更 2 标识符的名称限制 3 整数的大小 4 字符是有符号整数还是无符号整数 5 移位运算符 6 内存位置0 7 除法运算时发生的截断 1 应对C语言标准变更 使用新特性可以使代码更容易编写且减少错误&#xff0c;但可能会导致代码在旧编译器上无法编译。…...

应急响应:玄机_Linux后门应急

https://xj.edisec.net/challenges/95 11关做出拿到万能密码&#xff0c;ATMB6666&#xff0c;后面都在root权限下操作 1、主机后门用户名称&#xff1a;提交格式如&#xff1a;flag{backdoor} cat /etc/passwd&#xff0c;发现后门用户 flag{backdoor} 2、主机排查项中可以…...

C++:捕获 shared_from_this()和捕获this的区别

两种方法的主要区别在于对象的生命周期管理以及捕获方式的不同。以下是对两种方法的详细对比&#xff1a; 第一种&#xff1a;捕获 shared_from_this() 的方法 event.subscribe([self shared_from_this()]() {std::cout << "Event triggered, object is alive.&qu…...

网络协议之TCP

一、定义 TCP&#xff08;Transmission Control Protocol&#xff0c;传输控制协议&#xff09;是一种面向连接的、可靠的、基于字节流的传输层通信协议&#xff0c;由IETF的RFC 793定义。TCP旨在适应支持多网络应用的分层协议层次结构。在因特网协议族&#xff08;Internet p…...

《澳鹏AI全景报告2024》分析最新的数据挑战

华盛顿州柯克兰市&#xff0c;2024 年 10 月 22 日 —— Appen Limited&#xff08;澳大利亚证券交易所代码&#xff1a;APX&#xff09;&#xff0c;一家为人工智能生命周期提供高质量数据的领先供应商&#xff0c;发布了其《2024 年人工智能现状报告》。该报告对美国多个行业…...

【Java每日面试题】—— String、StringBuilder和StringBuffer的区别?

1、String 不可变性:String对象创建后不可变,内容不能被修改,对字符串修改会产生一个新的字符串对象。 线程:线程安全 适用:字符串内容不发生变化或少量字符串操作 String str = "Hello"; str = str + " World"; 2、StringBuffer 不可变性:对…...

【设计模式】【创建型模式(Creational Patterns)】之单例模式

单例模式是一种常用的创建型设计模式&#xff0c;其目的是确保一个类只有一个实例&#xff0c;并提供一个全局访问点。 单例模式的原理 单例模式的核心在于控制类的实例化过程&#xff0c;通常通过以下方式实现&#xff1a; 私有化构造函数&#xff0c;防止外部直接实例化。…...

form表单的使用

模板 <template><el-form :model"formData" ref"form1Ref" :rules"rules"><el-form-item label"手机号" prop"tel"><el-input v-model"formData.tel" /></el-form-item><el-f…...

PDF内容提取,MinerU使用

准备环境 # python 3.10 python3 -m pip install huggingface_hub python3 -m pip install modelscope python3 -m pip install -U magic-pdf[full] --extra-index-url https://wheels.myhloli.com下载需要的模型 import json import osimport requests from huggingface_hub…...

SpringCloud篇(服务网关 - GateWay)

目录 一、简介 二、为什么需要网关 二、gateway快速入门 1. 创建gateway服务&#xff0c;引入依赖 2. 编写启动类 3. 编写基础配置和路由规则 4. 重启测试 5. 网关路由的流程图 6. 总结 三、断言工厂 四、过滤器工厂 1. 路由过滤器的种类 2. 请求头过滤器 3. 默认…...

自动化测试之unittest框架详解

&#x1f345; 点击文末小卡片 &#xff0c;免费获取软件测试全套资料&#xff0c;资料在手&#xff0c;涨薪更快 unittest 1、什么是Unittest框架&#xff1f; python自带一种单元测试框架 2、为什么使用UnitTest框架&#xff1f; >批量执行用例 >提供丰富的断…...

反向工程与模型迁移:打造未来商品详情API的可持续创新体系

在电商行业蓬勃发展的当下&#xff0c;商品详情API作为连接电商平台与开发者、商家及用户的关键纽带&#xff0c;其重要性日益凸显。传统商品详情API主要聚焦于商品基本信息&#xff08;如名称、价格、库存等&#xff09;的获取与展示&#xff0c;已难以满足市场对个性化、智能…...

【力扣数据库知识手册笔记】索引

索引 索引的优缺点 优点1. 通过创建唯一性索引&#xff0c;可以保证数据库表中每一行数据的唯一性。2. 可以加快数据的检索速度&#xff08;创建索引的主要原因&#xff09;。3. 可以加速表和表之间的连接&#xff0c;实现数据的参考完整性。4. 可以在查询过程中&#xff0c;…...

渗透实战PortSwigger靶场-XSS Lab 14:大多数标签和属性被阻止

<script>标签被拦截 我们需要把全部可用的 tag 和 event 进行暴力破解 XSS cheat sheet&#xff1a; https://portswigger.net/web-security/cross-site-scripting/cheat-sheet 通过爆破发现body可以用 再把全部 events 放进去爆破 这些 event 全部可用 <body onres…...

React19源码系列之 事件插件系统

事件类别 事件类型 定义 文档 Event Event 接口表示在 EventTarget 上出现的事件。 Event - Web API | MDN UIEvent UIEvent 接口表示简单的用户界面事件。 UIEvent - Web API | MDN KeyboardEvent KeyboardEvent 对象描述了用户与键盘的交互。 KeyboardEvent - Web…...

C++ 基础特性深度解析

目录 引言 一、命名空间&#xff08;namespace&#xff09; C 中的命名空间​ 与 C 语言的对比​ 二、缺省参数​ C 中的缺省参数​ 与 C 语言的对比​ 三、引用&#xff08;reference&#xff09;​ C 中的引用​ 与 C 语言的对比​ 四、inline&#xff08;内联函数…...

leetcodeSQL解题:3564. 季节性销售分析

leetcodeSQL解题&#xff1a;3564. 季节性销售分析 题目&#xff1a; 表&#xff1a;sales ---------------------- | Column Name | Type | ---------------------- | sale_id | int | | product_id | int | | sale_date | date | | quantity | int | | price | decimal | -…...

Java入门学习详细版(一)

大家好&#xff0c;Java 学习是一个系统学习的过程&#xff0c;核心原则就是“理论 实践 坚持”&#xff0c;并且需循序渐进&#xff0c;不可过于着急&#xff0c;本篇文章推出的这份详细入门学习资料将带大家从零基础开始&#xff0c;逐步掌握 Java 的核心概念和编程技能。 …...

Java面试专项一-准备篇

一、企业简历筛选规则 一般企业的简历筛选流程&#xff1a;首先由HR先筛选一部分简历后&#xff0c;在将简历给到对应的项目负责人后再进行下一步的操作。 HR如何筛选简历 例如&#xff1a;Boss直聘&#xff08;招聘方平台&#xff09; 直接按照条件进行筛选 例如&#xff1a…...

Spring AI与Spring Modulith核心技术解析

Spring AI核心架构解析 Spring AI&#xff08;https://spring.io/projects/spring-ai&#xff09;作为Spring生态中的AI集成框架&#xff0c;其核心设计理念是通过模块化架构降低AI应用的开发复杂度。与Python生态中的LangChain/LlamaIndex等工具类似&#xff0c;但特别为多语…...

初学 pytest 记录

安装 pip install pytest用例可以是函数也可以是类中的方法 def test_func():print()class TestAdd: # def __init__(self): 在 pytest 中不可以使用__init__方法 # self.cc 12345 pytest.mark.api def test_str(self):res add(1, 2)assert res 12def test_int(self):r…...