23、设计模式之访问者模式(Visitor)

一、什么是访问者模式
访问者模式是一种行为型设计模式,它可以用于在不修改已有对象结构的情况下,定义新的操作方式。简单地说就是在不改变数据结构的前提下,通过在数据结构中加入一个新的角色——访问者,来达到执行不同操作的目的。

二、角色组成

抽象访问者(Visitor):定义了对自身数据结构中各个元素的操作,为每个具体元素类对应一个访问操作,该操作中的参数标识了被访问的具体元素。
具体访问者(Concrete Visitor):实现了访问者接口中定义的具体操作,确定访问者访问一个元素时该做什么。
抽象元素(Element):定义了接受访问者的接口,通常是一个接口或抽象类,其中定义了一个接受访问者的方法,被访问者对象作为方法的参数。
具体元素(Concrete Element):实现了抽象元素接口,它是数据结构中的具体的元素,用于接收具体的访问者并执行相应的操作。每个具体元素都有自己的业务逻辑,并在接收访问者时将具体的操作委托给访问者进行处理。
对象结构(Object Structure):是一个包含元素角色的容器,提供让访问者对象遍历容器中的所有元素的方法,通常由 List、Set、Map 等聚合类实现。

三、优缺点
优点:

扩展性好:能够在不修改对象结构中的元素的情况下,为对象结构中的元素添加新的功能。
复用性好:可以通过访问者来定义整个对象结构通用的功能,从而提高系统的复用程度。
灵活性好:访问者模式将数据结构与作用于结构上的操作解耦,使得操作集合可相对自由地演化而不影响系统的数据结构。
符合单一职责原则。访问者模式把相关的行为封装在一起,构成一个访问者,使每一个访问者的功能都比较单一。
缺点:

违反开闭原则:在访问者模式中,每增加一个新的元素类,都要在每一个具体访问者类中增加相应的具体操作,这违背了“开闭原则”。
违反迪米特法则:在访问者模式中,具体元素类需要暴露接受访问者的方法给访问者使用,这样破坏了具体元素类对于访问者的封装性,增加了元素类与具体访问者之间的耦合性。
破坏封装性:访问者模式中具体元素对访问者公布细节,这破坏了对象的封装性。
四、 应用场景
4.1 生活场景
蔬菜摊位:在一个农贸市场的蔬菜摊位上,摊主可能提供不同的服务,如称重、清洗、切割等。每个服务可以被视为一个访问者,而蔬菜则是元素,根据不同的服务访问者进行相应的操作。
医院就诊:在医院就诊时,医生、护士和药师可以视为不同的访问者,而病人则是元素。不同的访问者根据其职责和需要,对病人进行不同的操作和处理,如诊断、治疗、开药等。
旅游参观:游客可以参观不同的地方,如参观文物、欣赏风景等。游客可以看作访问者,而景点本身则是元素,根据游客的选择展示不同的参观操作。
4.2 Java场景
XML解析器:许多Java XML解析器,如DOM和SAX解析器,使用访问者模式来处理XML文档。XML的节点可以被视为元素,而访问者则可以是处理XML节点的具体操作,如提取数据、修改节点等。
数据库访问:一些Java数据库访问框架,如Hibernate和MyBatis,使用访问者模式来处理数据库操作。数据库表和字段可以被视为元素,而访问者则可以是查询、更新或删除操作,通过访问者模式来执行这些操作。
文件系统操作:Java的文件和目录操作中,使用了访问者模式。Java提供了FileVisitor接口和SimpleFileVisitor类,可以通过自定义的访问者类来遍历文件系统,并执行不同的操作,如复制文件、删除文件等。
五、代码实现
下面以“旅游参观”为例,解释一下访问者模式。游客挑选不同的景点来参观,如参观文物、欣赏风景等。那么游客可以看作访问者,而景点本身则是元素,根据游客的选择展示不同的参观操作。

抽象访问者:Visitor
具体访问者:Tourist
抽象元素:Spot
具体元素:Relic、View
对象结构:SpotCollection

5.0 UML类图
在这里插入图片描述
5.1 抽象访问者——Visitor

/**
 *
 * 1.抽象访问者(Visitor):参观者
 * 定义:定义了对自身数据结构中各个元素的操作,为每个具体元素类对应一个访问操作,该操作中的参数标识了被访问的具体元素。
 */
public interface Visitor {
    void visit(Relic relic);
    void visit(View scenery);
}

5.2 具体访问者——Tourist

/**
 *
 * 2.具体访问者(Concrete Visitor):游客
 * 定义:实现了访问者接口中定义的具体操作,确定访问者访问一个元素时该做什么。
 */
public class Tourist implements Visitor{
    @Override
    public void visit(Relic relic) {
        System.out.println("游客正在参观文物...");
        relic.display();
    }
 
    @Override
    public void visit(View scenery) {
        System.out.println("游客正在欣赏自然风景...");
        scenery.display();
    }
}

5.3 抽象元素——Spot

/**
 * @
 * 3.抽象元素(Element):景点
 * 定义:定义了接受访问者的接口,通常是一个接口或抽象类,其中定义了一个接受访问者的方法,被访问者对象作为方法的参数。
 */
public interface Spot {
    void accept(Visitor visitor);
}

5.4 具体元素——View、Relic

/**
 *
 * 4.具体元素(Concrete Element):风景
 * 定义:实现了抽象元素接口,它是数据结构中的具体的元素,用于接收具体的访问者并执行相应的操作。
 * 每个具体元素都有自己的业务逻辑,并在接收访问者时将具体的操作委托给访问者进行处理。
 */
public class View implements Spot{
    @Override
    public void accept(Visitor visitor) {
        visitor.visit(this); // 将自身传递给访问者
    }
    // 具体自然风景的业务逻辑
    public void display() {
        System.out.println("这是一处壮丽的自然风景。");
    }
/**
 * 
 * 4.具体元素(Concrete Element):文物
 * 定义:实现了抽象元素接口,它是数据结构中的具体的元素,用于接收具体的访问者并执行相应的操作。
 * 每个具体元素都有自己的业务逻辑,并在接收访问者时将具体的操作委托给访问者进行处理。
 */
public class Relic implements Spot{
    @Override
    public void accept(Visitor visitor) {
        visitor.visit(this); // 将自身传递给访问者
    }
    // 具体文物的业务逻辑
    public void display() {
        System.out.println("这是一件珍贵的文物。");
    }
}

5.5 对象结构——SpotCollection

/**
 * 
 * 5.对象结构(Object Structure)
 * 定义:包含元素角色的容器,提供让访问者对象遍历容器中的所有元素的方法,通常由 List、Set、Map 等聚合类实现。
 */
public class SpotCollection {
    private List<Spot> spots = new ArrayList<>();
 
    //添加元素
    public void addSpot(Spot spot) {
        spots.add(spot);
    }
 
    public void accept(Visitor visitor) {
        for (Spot spot : spots) {
            spot.accept(visitor);
        }
    }
}

5.6 testVisitor

/**
 * 
 * 访问者模式测试类
 */
@SpringBootTest
public class TestVisitor {
 
    @Test
    void testVisitor(){
        //创建对象结构
        SpotCollection spotCollection = new SpotCollection();
        //添加元素
        spotCollection.addSpot(new Relic());
        spotCollection.addSpot(new View());
 
        Tourist tourist = new Tourist();
        //景点接受游客的访问
        spotCollection.accept(tourist);
    }
}

在这里插入图片描述
六、总结
访问者模式主要用于将操作与数据结构分离,增加新的操作变得简单,但增加新的元素类可能会导致修改访问者接口和所有的具体访问者类。

以下情况,可以考虑使用访问者模式:

当对象结构中的元素类(Element)和操作类(Operation)的种类固定或者很少改变,但是需要经常新增或者修改操作时。
当需要对一个对象结构中的元素进行多种不同且无关的操作时。
当需要对不同类型的元素对象进行某种共同的处理逻辑时。
当对象结构中的元素类(Element)和操作类(Operation)的种类很多,并且相互之间的组合和嵌套可能会产生大量的代码重复时。
当需要在不修改元素对象的类结构的前提下,给元素对象新增一些操作时。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

防御安全(IPSec实验)

目录 需求&#xff1a; pc1 ping通 pc2 ,使用IPSec VPN 拓扑图&#xff1a; ​编辑实验配置&#xff1a; 注意&#xff1a; 直接在路由器r1和r2分别配置即可&#xff0c;路由器r1和r2要写一条缺省指向ISP 实验配置截图如下&#xff1a; 2. r1​编辑 3. r3​编辑 3.r…

【C++】—— 代理模式

目录 &#xff08;一&#xff09;什么是代理模式 &#xff08;二&#xff09;为什么使用代理模式 &#xff08;三&#xff09;代理模式实现步奏 &#xff08;四&#xff09;代码示例 &#xff08;五&#xff09;代理模式优缺点 &#xff08;一&#xff09;什么是代理模式 …

车辆路径优化问题(VRP)变体及数学模型

车辆路径优化问题变体及数学模型 一、旅行商问题&#xff08;Travelling salesman problem&#xff0c;TSP&#xff09;TSP问题数学模型TSP问题求解 二、车辆路径问题&#xff08;Vehicle Routing Problem&#xff0c;VRP&#xff09;三、带容量约束的车辆路径优化问题&#xf…

【项目】C++ 基于多设计模式下的同步异步日志系统

前言 一般而言&#xff0c;业务的服务都是周而复始的运行&#xff0c;当程序出现某些问题时&#xff0c;程序员要能够进行快速的修复&#xff0c;而修复的前提是要能够先定位问题。 因此为了能够更快的定位问题&#xff0c;我们可以在程序运行过程中记录一些日志&#xff0c;通…

MySQL8.0 通过data文件恢复数据库

情景&#xff1a; mysql突然访问不了&#xff0c;也启动不了&#xff0c;需要保存之前的数据库文件&#xff0c;在卸载重装恢复数据 步骤&#xff1a; 1、Mysql里的数据一般会自动保存到C:\ProgramData\MySQL\MySQL Server 8.0\Data目录下&#xff0c;卸载前要将其备份。这是…

数据结构之树(Topk问题, 链式二叉树)

一.topk问题 取N个数中最大(小)的前k个值,N远大于k 这道题可以用堆的方法来解决,首先取这N个数的前k个值,用它们建堆 时间复杂度O(k) 之后将剩余的N-k个数据依次与堆顶数据进行比较,如果比堆顶数据大,则将堆顶数据覆盖后向下调整 时间复杂度(N-k)*log(N) 总共的时间复杂度…

【05】消失的数字

hellohello~这里是土土数据结构学习笔记&#x1f973;&#x1f973; &#x1f4a5;个人主页&#xff1a;大耳朵土土垚的博客 &#x1f4a5;所属专栏&#xff1a;C语言函数实现 感谢大家的观看与支持&#x1f339;&#x1f339;&#x1f339; 有问题可以写在评论区或者私信我哦…

缓冲区与C库函数的实现

目录 一、缓冲区 二、C库函数的实现 一、缓冲区 缓冲区本质就是一块内存&#xff0c;而缓冲区存在的意义本质是提高使用者(用户)的效率【把缓冲区理解成寄送包裹的菜鸟驿站】 缓冲区的刷新策略 1. 无缓冲(立即刷新) 2. 行缓冲(行刷新) 3. 全缓冲(缓冲区满了&#xff0c;再刷…

春风吹又生的开源项目「GitHub 热点速览」

随着上周知名 Switch 开源模拟器 Yuzu&#xff08;柚子&#xff09;被任天堂起诉&#xff0c;该项目作者就删库了&#xff0c;但还是要赔偿任天堂数百万美元。此事还在 GitHub 上掀起了一波 Yuzu fork 项目的小浪潮&#xff0c;正所谓野火烧不尽&#xff0c;春风吹又生。 很多读…

Express学习(四)

使用Express写接口 创建基本的服务器 创建API路由模块 编写GET接口 编写POST接口 CORS跨域资源共享 什么是CORS CORS由一系列HTTP响应头组成&#xff0c;这些HTTP响应头决定浏览器是否阻止前端JS代码跨域获取资源。浏览器的同源安全策略默认会阻止网页“跨域”获取资源。但如…

十五、软考-系统架构设计师笔记-面向服务架构设计理论与实践

1、SOA相关概念 面向服务的架构(SOA)的定义 SOA 是一个组件模型&#xff0c;它将应用程序的不同功能单元(称为服务)通过这些服务之间定义良好的接口和契约联系起来。接口是采用中立的方式进行定义的&#xff0c;它应该独立于实现服务的硬件平台、操作系统和编程语言。这使得构…

狂揽Github—start19.7k☆开源OCR—Umi-OCR

文章目录 背景Umi-OCR—源码下载Umi-OCR—可执行程序下载页面介绍截图OCR识别批量OCR识别批量文档二维码全局设置 总结&#xff1a; 背景 大家都知道我是一个Python办公自动化的小小程序员&#xff0c;经常收集一些免费开源的OCR供大家使用&#xff0c;目前我已经写出来多家OCR…

(done) win11 如何安装 Anaconda3 ? 如何安装 jupyter notebook

首先是这个网站 https://www.anaconda.com/download/#windows 下载并安装 anaconda3 进入 anaconda3.navigator 后&#xff0c;会看到如下界面 点击下面这个 Launch 按钮&#xff0c;可以启动 jupyter notebook 如下图&#xff0c;jupyter 出来了

【数据结构七】堆与PriorityQueue详解

堆 在Java中有一种数据结构基于队列&#xff0c;并保证操作的数据带有优先级&#xff0c;该数据结构应该提供了两个最基本的操作&#xff0c;一个是返回最高优先级对象&#xff0c;一个是添加新的对象。这种数据结构就是优先级队列(Priority Queue)。它的底层使用了堆这种数据结…

离散化算法,以Acwing802.区间和为例子(C++实现)

目录 1.例题2.算法实现思路3.代码 1.例题 假定有一个无限长的数轴&#xff0c;数轴上每个坐标上的数都是 0现在&#xff0c;我们首先进行 n 次操作&#xff0c;每次操作将某一位置 x 上的数加 c接下来&#xff0c;进行 m 次询问&#xff0c;每个询问包含两个整数 l 和 r&#…

贪心算法(算法竞赛、蓝桥杯)--奶牛晒衣服

1、B站视频链接&#xff1a;A28 贪心算法 P1843 奶牛晒衣服_哔哩哔哩_bilibili 题目链接&#xff1a;奶牛晒衣服 - 洛谷 #include <bits/stdc.h> using namespace std; priority_queue<int> q;//用大根堆维护湿度的最大值 int n,a,b; int tim,maxn;int main(){s…

sqllab第十关通关笔记

知识点&#xff1a; 时间盲注适用于回显无变化的场景重点还是不断的构造payload进行尝试&#xff1b;判断绕过条件 这里就不演示判断注入类型&#xff1b;通过测试发现和第九关一样&#xff1b;回显无变化的&#xff1b; 构造第九关的payload:id1 and if(1,sleep(2),1) -- 发…

MySQL的事务隔离是如何实现的?

目录 从一个例子说起 快照读和当前读 事务的启动时机和读视图生成的时刻 MVCC 隐藏字段 Undo Log回滚日志 Read View - 读视图 可重复读(RC)隔离级别下的MVCC 读提交(RR)隔离级别下的MCC 关于MVCC的一些疑问 1.为什么需要 MVCC &#xff1f;如果没有 MVCC 会怎样&am…

Windows-WSL2-VSCode+Docker配置C++开发环境

Windows-WSL2-VSCodeDocker配置C开发环境 写在前面 因为在学习工作中&#xff0c;需要不同的编码环境&#xff0c;若将这些不同的开发环境都状态一台设备上&#xff0c;很容易出问题&#xff0c;而且迁移性差&#xff0c;于是计划把不同的开发环境用docker隔离开来&#xff0…

Llama-3公布基础训练设施,使用49000个H100

3月13日&#xff0c;社交、科技巨头Meta在官网公布了两个全新的24K H100 GPU集群&#xff08;49,152个&#xff09;&#xff0c;专门用于训练大模型Llama-3。 此外&#xff0c;Llama-3使用了RoCEv2网络&#xff0c;基于Tectonic/Hammerspace的NFS/FUSE网络存储&#xff0c;继续…