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

设计模式二十四:访问者模式(Visitor Pattern)

用于将数据结构与数据操作分离,使得可以在不修改数据结构的情况下,定义新的操作。访问者模式的核心思想是,将数据结构和操作进行解耦,从而使得新增操作时不必修改数据结构,只需添加新的访问者。主要目的是在不改变数据结构的情况下,为数据结构中的元素添加新的操作,从而满足开闭原则(对扩展开放,对修改封闭)

访问者模式使用场景

  1. 数据结构稳定,但操作频繁变化
    当数据结构相对稳定,但经常需要新增或修改不同类型的操作时,访问者模式可以将操作与数据结构分离,使得新增操作不影响现有的数据结构
  2. 操作多态性
    当存在一组不同类型的元素,每个元素需要支持不同类型的操作时,访问者模式可以将操作封装成具体访问者类,每个具体访问者类负责一种操作
  3. 避免污染数据结构
    当希望在不改变现有数据结构的前提下,向数据结构中添加新的操作时,访问者模式可以避免污染数据结构。
  4. 扩展性要求高
    当需要添加新类型的元素或操作时,访问者模式使得扩展变得相对容易,只需要新增具体元素类和具体访问者类。
  5. 解耦操作和数据结构
    当数据结构和操作之间的耦合度较高时,访问者模式可以解耦这两者,使得各自可以独立变化。
  6. 复杂的对象结构
    当对象结构非常复杂,且其中的元素类型较多时,通过访问者模式可以将不同类型的操作分布到不同的具体访问者类中,使代码更加清晰

访问者模式的主要角色

  1. 访问者(Visitor):
    定义了对数据结构中各个元素进行访问的抽象方法,每个方法对应一个具体元素的操作。访问者接口可能会定义多个访问方法,每个方法处理不同类型的元素。
  2. 具体访问者(Concrete Visitor):
    实现了访问者接口中定义的方法,对具体的元素进行操作。
  3. 元素(Element):
    定义了一个accept方法,该方法接受一个访问者对象作为参数,将自身传递给访问者,使访问者可以对自己进行操作。
  4. 具体元素(Concrete Element):
    实现了元素接口的accept方法,将自身传递给访问者,以便访问者可以对自己进行操作。
  5. 对象结构(Object Structure):
    维护一个元素的集合,提供了迭代元素的方法,通常可以使用集合类来实现。

java代码实例

元素

public interface Animal  {void accept(AnimalVisitor animalVisitor );}

具体元素

// 具体动物类
class Lion implements Animal {@Overridepublic void accept(AnimalVisitor visitor) {visitor.visitLion(this);}
}class Elephant implements Animal {@Overridepublic void accept(AnimalVisitor visitor) {visitor.visitElephant(this);}
}class Dolphin implements Animal {@Overridepublic void accept(AnimalVisitor visitor) {visitor.visitDolphin(this);}
}

访问者接口

public interface AnimalVisitor {//拜访狮子void visitLion(Lion lion);//拜访大象void visitDolphin(Dolphin dolphin);//拜访海豚void visitElephant(Elephant elephant);}

具体访问者

//动物清洁工
public class AnimalCleaningVisitor implements AnimalVisitor{@Overridepublic void visitLion(Lion lion) {System.out.println("cleaning the lion's enclosure");}@Overridepublic void visitDolphin(Dolphin dolphin) {System.out.println("cleaning the dolphin's enclosure");}@Overridepublic void visitElephant(Elephant elephant) {System.out.println("cleaning the elephant's enclosure");}
}//动物饲养员
public class AnimalFeedingVisitor implements AnimalVisitor{@Overridepublic void visitLion(Lion lion) {System.out.println("Feeding the lion's,ying-ying-ying");}@Overridepublic void visitDolphin(Dolphin dolphin) {System.out.println("Feeding the dolphin's,ying-ying-ying");}@Overridepublic void visitElephant(Elephant elephant) {System.out.println("Feeding the elephant's,ying-ying-ying");}
}

客户端

  public static void main(String[] args) {Animal[] animals = new Animal[]{ new Lion(), new Elephant(), new Dolphin() };AnimalVisitor feedingVisitor = new AnimalFeedingVisitor();AnimalVisitor cleaningVisitor = new AnimalCleaningVisitor();for (Animal animal : animals) {animal.accept(feedingVisitor);animal.accept(cleaningVisitor);}}

输出

Feeding the lion's,ying-ying-ying
cleaning the lion's enclosure
Feeding the elephant's,ying-ying-ying
cleaning the elephant's enclosure
Feeding the dolphin's,ying-ying-ying
cleaning the dolphin's enclosure

访问者模式优缺点

访问者模式适用于某些特定的场景,特别是在操作和数据结构之间的耦合性较高,且数据结构相对稳定的情况下。在使用访问者模式时,需要权衡其优点和缺点,并根据实际需求进行选择。
优点

  1. 新增操作容易
    访问者模式使得新增操作变得相对容易,只需要新增一个新的访问者类,而无需修改现有的元素类。
  2. 解耦操作和数据结构
    访问者模式将操作(访问者类)与数据结构(元素类)解耦,使得操作可以独立变化,不影响数据结构
  3. 增加灵活性
    可以在不改变数据结构的情况下,对数据结构中的元素进行不同类型的操作,从而增加了灵活性。
  4. 符合单一职责原则
    访问者模式将具体操作封装到具体访问者类中,符合单一职责原则,使得每个类的职责更加清晰。
  5. 适用于稳定的数据结构
    访问者模式适用于数据结构相对稳定,而操作需要频繁变化的场景

缺点

  1. 增加类的数量
    访问者模式引入了多个具体访问者类,可能会增加类的数量,使得代码变得复杂
  2. 破坏封装性
    访问者模式需要元素类暴露接受访问者的方法,这可能会破坏元素类的封装性
  3. 增加扩展难度
    新增一种元素类型时,需要修改所有具体访问者类,这可能会增加扩展的难度。
  4. 不适用于元素变化频繁的场景
    如果元素的类型经常变化,频繁新增元素,使用访问者模式可能会增加维护成本
  5. 不适用于简单场景
    在简单的场景下,使用访者模式可能会引入不必要的复杂性

相关文章:

设计模式二十四:访问者模式(Visitor Pattern)

用于将数据结构与数据操作分离,使得可以在不修改数据结构的情况下,定义新的操作。访问者模式的核心思想是,将数据结构和操作进行解耦,从而使得新增操作时不必修改数据结构,只需添加新的访问者。主要目的是在不改变数据…...

使用gn+Ninja构建项目

使用下载编译好的gn和ninja报错 先下载了gn的源码[gn.googlesource.com/gn],然后编译报错,就直接下载了了编译号的gn和Ninja,然后写了Helloworld应用的BUILD.gn,然后将"gn\examples\simple_build\build"拷贝至当前目录…...

VMware虚拟机连不上网络

固定ip地址 进入网络配置文件 cd /etc/sysconfig/network-scripts 打开文件 vi ifcfg-ens33 编辑 BOOTPROTO设置为static,有3个值(decp、none、static) BOOTPROTO"static" 打开网络 ONBOOT"yes" 固定ip IPADDR1…...

安防视频监控/视频集中存储/云存储平台EasyCVR平台无法取消共享通道该如何解决?

视频汇聚/视频云存储/集中存储/视频监控管理平台EasyCVR能在复杂的网络环境中,将分散的各类视频资源进行统一汇聚、整合、集中管理,实现视频资源的鉴权管理、按需调阅、全网分发、云存储、智能分析等,视频智能分析平台EasyCVR融合性强、开放度…...

算法通关村-----如何基于数组和链表实现栈

实现栈的基本方法 push(T t)元素入栈 T pop() 元素出栈 Tpeek() 查看栈顶元素 boolean isEmpty() 栈是否为空 基于数组实现栈 import java.util.Arrays;public class ArrayStack<T> {private Object[] stack;private int top;public ArrayStack() {this.stack new…...

day-05 TCP半关闭 ----- DNS ----- 套接字的选项

一、优雅的断开套接字连接 之前套接字的断开都是单方面的。 &#xff08;一&#xff09;基于TCP的半关闭 Linux的close函数和windows的closesocket函数意味着完全断开连接。完全断开不仅不能发送数据&#xff0c;从而也不能接收数据。在某些情况下&#xff0c;通信双方的某一方…...

区块链金融项目怎么做?

区块链技术的兴起引发了金融领域的变革&#xff0c;为金融行业带来了前所未有的机遇与挑战。在这个快速发展的领域中&#xff0c;如何在区块链金融领域做出卓越的表现&#xff1f;本文将从专业性和思考深度两个方面&#xff0c;探讨区块链金融的发展路径&#xff0c;并为读者提…...

Redis与数据库保持一致

参考链接 先更新数据库&#xff0c;再更新redis 存在漏洞&#xff0c;如果更新Redis失败&#xff0c;仍然会导致不一致 先删Redis&#xff0c;再更新数据库并同步数据到Redis 存在漏洞&#xff0c;多线程情况下,线程1删除redis后&#xff0c;还是有可能被其他线程读取旧的数据…...

idea中vue项目 npm安装插件后node modules中找不到

从硬盘中重新加载一下...

已知两地经纬度,计算两地直线距离

文章目录 1 原理公式2 代码实现2.1 JavaScript2.2 C2.3 Python2.4 MATLAB 1 原理公式 在地球上&#xff0c;计算两点之间的直线距离通常使用地理坐标系&#xff08;例如WGS84&#xff09;。计算两地直线距离的公式是根据经纬度之间的大圆距离&#xff08;Great Circle Distanc…...

我想开通期权?如何开通期权账户?

场内期权的合约由交易所统一标准化定制&#xff0c;大家面对的同一个合约对应的价格都是一致的&#xff0c;比较公开透明&#xff0c;期权开户当天不能交易的&#xff0c;期权开户需要满足20日日均50万及半年交易经验即可操作&#xff0c;下文科普我想开通期权&#xff1f;如何…...

ChatGPT对软件测试的影响

ChatGPT 是一个经过预训练的 AI 语言模型&#xff0c;可以通过聊天的方式回答问题&#xff0c;或者与人闲聊。它能处理的是文本类的信息&#xff0c;输出也只能是文字。它从我们输入的信息中获取上下文&#xff0c;结合它被训练的大模型&#xff0c;进行分析总结&#xff0c;给…...

minion在ubuntu上的搭建步骤

在Ubuntu上搭建MinIO可以按照以下步骤进行&#xff1a; 下载MinIO服务器二进制文件&#xff1a; 通过浏览器访问 https://min.io/download 或使用以下命令获取最新的MinIO二进制文件&#xff1a;wget https://dl.min.io/server/minio/release/linux-amd64/minio赋予二进制文件…...

Leetcode刷题笔记--Hot31-40

1--颜色分类&#xff08;75&#xff09; 主要思路&#xff1a; 快排 #include <iostream> #include <vector>class Solution { public:void sortColors(std::vector<int>& nums) {quicksort(nums, 0, nums.size()-1);}void quicksort(std::vector<int…...

【Python】环境配置,【Pytorch】GPU版本安装

总结&#xff1a; 使用conda新建切换环境&#xff0c;然后使用pip安装卸载包 【python】pip conda_conda list没有pytorch_myaijarvis的博客-CSDN博客 pip换源 https://blog.csdn.net/maotenghua/article/details/104188086 在当前用户目录下创建pip目录&#xff0c;即C:\U…...

BEVFusion复现 (Ubuntu RTX3090)

https://github.com/ADLab-AutoDrive/BEVFusion 1.环境安装 我的机器是RTX3090&#xff0c;CUDA11.1 1.创建虚拟环境 conda create -n bevfusion python3.8.3 2.安装PyTorch 和 torchvision pip install torch1.8.0cu111 torchvision0.9.0cu111 torchaudio0.8.0 -f https://…...

Python基础知识学习与回顾

Python学习 Python基本语法 标识符 标识符由数字、字符串、下划线构成。 注意事项&#xff1a; 标识符不以数字开头区分大小写下划线开头的标识符具有特殊意义保留字&#xff0c;Python保留了一些关键字&#xff0c;这些关键字都是通过小写字母进行保存。 下划线开头的特…...

SpringBoot笔记——(狂神说)——待续

路线 javase: OOPmysql:持久化 htmlcssjsjquery框架:视图&#xff0c;框架不熟练&#xff0c;css不好; javaweb:独立开发MVC三层架构的网站了∶原始 ssm :框架:简化了我们的开发流程&#xff0c;配置也开始较为复杂; war: tomcat运行 spring再简化: SpringBoot - jar:内嵌tomca…...

Linux TCP编程流程

一、TCP编程流程 TCP 提供的是面向连接的、可靠的、字节流服务。TCP的服务器端和客户端编程流程如下&#xff1a; 1.socket()方法 用来创建一个套接字&#xff0c;有了套接字就可以通过网络进行数据的收发。这也是为什么进行网络通信的程序首先要创建一个套接字。创建套接字时…...

pyqt5 QuickStart

在使用pyqt5之前&#xff0c;建议下载一个Anaconda环境&#xff0c;这样下载python包更方便&#xff0c;本篇文章是建立在已经安装好Anaconda的情况下使用的。IDE就是标准的PyCharm了。 一、pyqt包的安装 python终端执行下面两个安装命令&#xff1a; pip install PyQt5 pip …...

云启出海,智联未来|阿里云网络「企业出海」系列客户沙龙上海站圆满落地

借阿里云中企出海大会的东风&#xff0c;以**「云启出海&#xff0c;智联未来&#xff5c;打造安全可靠的出海云网络引擎」为主题的阿里云企业出海客户沙龙云网络&安全专场于5.28日下午在上海顺利举办&#xff0c;现场吸引了来自携程、小红书、米哈游、哔哩哔哩、波克城市、…...

vue3 字体颜色设置的多种方式

在Vue 3中设置字体颜色可以通过多种方式实现&#xff0c;这取决于你是想在组件内部直接设置&#xff0c;还是在CSS/SCSS/LESS等样式文件中定义。以下是几种常见的方法&#xff1a; 1. 内联样式 你可以直接在模板中使用style绑定来设置字体颜色。 <template><div :s…...

DBAPI如何优雅的获取单条数据

API如何优雅的获取单条数据 案例一 对于查询类API&#xff0c;查询的是单条数据&#xff0c;比如根据主键ID查询用户信息&#xff0c;sql如下&#xff1a; select id, name, age from user where id #{id}API默认返回的数据格式是多条的&#xff0c;如下&#xff1a; {&qu…...

【RockeMQ】第2节|RocketMQ快速实战以及核⼼概念详解(二)

升级Dledger高可用集群 一、主从架构的不足与Dledger的定位 主从架构缺陷 数据备份依赖Slave节点&#xff0c;但无自动故障转移能力&#xff0c;Master宕机后需人工切换&#xff0c;期间消息可能无法读取。Slave仅存储数据&#xff0c;无法主动升级为Master响应请求&#xff…...

[Java恶补day16] 238.除自身以外数组的乘积

给你一个整数数组 nums&#xff0c;返回 数组 answer &#xff0c;其中 answer[i] 等于 nums 中除 nums[i] 之外其余各元素的乘积 。 题目数据 保证 数组 nums之中任意元素的全部前缀元素和后缀的乘积都在 32 位 整数范围内。 请 不要使用除法&#xff0c;且在 O(n) 时间复杂度…...

dify打造数据可视化图表

一、概述 在日常工作和学习中&#xff0c;我们经常需要和数据打交道。无论是分析报告、项目展示&#xff0c;还是简单的数据洞察&#xff0c;一个清晰直观的图表&#xff0c;往往能胜过千言万语。 一款能让数据可视化变得超级简单的 MCP Server&#xff0c;由蚂蚁集团 AntV 团队…...

ip子接口配置及删除

配置永久生效的子接口&#xff0c;2个IP 都可以登录你这一台服务器。重启不失效。 永久的 [应用] vi /etc/sysconfig/network-scripts/ifcfg-eth0修改文件内内容 TYPE"Ethernet" BOOTPROTO"none" NAME"eth0" DEVICE"eth0" ONBOOT&q…...

使用Spring AI和MCP协议构建图片搜索服务

目录 使用Spring AI和MCP协议构建图片搜索服务 引言 技术栈概览 项目架构设计 架构图 服务端开发 1. 创建Spring Boot项目 2. 实现图片搜索工具 3. 配置传输模式 Stdio模式&#xff08;本地调用&#xff09; SSE模式&#xff08;远程调用&#xff09; 4. 注册工具提…...

GruntJS-前端自动化任务运行器从入门到实战

Grunt 完全指南&#xff1a;从入门到实战 一、Grunt 是什么&#xff1f; Grunt是一个基于 Node.js 的前端自动化任务运行器&#xff0c;主要用于自动化执行项目开发中重复性高的任务&#xff0c;例如文件压缩、代码编译、语法检查、单元测试、文件合并等。通过配置简洁的任务…...

Git常用命令完全指南:从入门到精通

Git常用命令完全指南&#xff1a;从入门到精通 一、基础配置命令 1. 用户信息配置 # 设置全局用户名 git config --global user.name "你的名字"# 设置全局邮箱 git config --global user.email "你的邮箱example.com"# 查看所有配置 git config --list…...