设计模式二十四:访问者模式(Visitor Pattern)
用于将数据结构与数据操作分离,使得可以在不修改数据结构的情况下,定义新的操作。访问者模式的核心思想是,将数据结构和操作进行解耦,从而使得新增操作时不必修改数据结构,只需添加新的访问者。主要目的是在不改变数据结构的情况下,为数据结构中的元素添加新的操作,从而满足开闭原则(对扩展开放,对修改封闭)
访问者模式使用场景
- 数据结构稳定,但操作频繁变化
当数据结构相对稳定,但经常需要新增或修改不同类型的操作时,访问者模式可以将操作与数据结构分离,使得新增操作不影响现有的数据结构 - 操作多态性
当存在一组不同类型的元素,每个元素需要支持不同类型的操作时,访问者模式可以将操作封装成具体访问者类,每个具体访问者类负责一种操作 - 避免污染数据结构
当希望在不改变现有数据结构的前提下,向数据结构中添加新的操作时,访问者模式可以避免污染数据结构。 - 扩展性要求高
当需要添加新类型的元素或操作时,访问者模式使得扩展变得相对容易,只需要新增具体元素类和具体访问者类。 - 解耦操作和数据结构
当数据结构和操作之间的耦合度较高时,访问者模式可以解耦这两者,使得各自可以独立变化。 - 复杂的对象结构
当对象结构非常复杂,且其中的元素类型较多时,通过访问者模式可以将不同类型的操作分布到不同的具体访问者类中,使代码更加清晰
访问者模式的主要角色
- 访问者(Visitor):
定义了对数据结构中各个元素进行访问的抽象方法,每个方法对应一个具体元素的操作。访问者接口可能会定义多个访问方法,每个方法处理不同类型的元素。 - 具体访问者(Concrete Visitor):
实现了访问者接口中定义的方法,对具体的元素进行操作。 - 元素(Element):
定义了一个accept方法,该方法接受一个访问者对象作为参数,将自身传递给访问者,使访问者可以对自己进行操作。 - 具体元素(Concrete Element):
实现了元素接口的accept方法,将自身传递给访问者,以便访问者可以对自己进行操作。 - 对象结构(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
访问者模式优缺点
访问者模式适用于某些特定的场景,特别是在操作和数据结构之间的耦合性较高,且数据结构相对稳定的情况下。在使用访问者模式时,需要权衡其优点和缺点,并根据实际需求进行选择。
优点
- 新增操作容易
访问者模式使得新增操作变得相对容易,只需要新增一个新的访问者类,而无需修改现有的元素类。 - 解耦操作和数据结构
访问者模式将操作(访问者类)与数据结构(元素类)解耦,使得操作可以独立变化,不影响数据结构 - 增加灵活性
可以在不改变数据结构的情况下,对数据结构中的元素进行不同类型的操作,从而增加了灵活性。 - 符合单一职责原则
访问者模式将具体操作封装到具体访问者类中,符合单一职责原则,使得每个类的职责更加清晰。 - 适用于稳定的数据结构
访问者模式适用于数据结构相对稳定,而操作需要频繁变化的场景
缺点
- 增加类的数量
访问者模式引入了多个具体访问者类,可能会增加类的数量,使得代码变得复杂 - 破坏封装性
访问者模式需要元素类暴露接受访问者的方法,这可能会破坏元素类的封装性 - 增加扩展难度
新增一种元素类型时,需要修改所有具体访问者类,这可能会增加扩展的难度。 - 不适用于元素变化频繁的场景
如果元素的类型经常变化,频繁新增元素,使用访问者模式可能会增加维护成本 - 不适用于简单场景
在简单的场景下,使用访者模式可能会引入不必要的复杂性
相关文章:
设计模式二十四:访问者模式(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 ----- 套接字的选项
一、优雅的断开套接字连接 之前套接字的断开都是单方面的。 (一)基于TCP的半关闭 Linux的close函数和windows的closesocket函数意味着完全断开连接。完全断开不仅不能发送数据,从而也不能接收数据。在某些情况下,通信双方的某一方…...
区块链金融项目怎么做?
区块链技术的兴起引发了金融领域的变革,为金融行业带来了前所未有的机遇与挑战。在这个快速发展的领域中,如何在区块链金融领域做出卓越的表现?本文将从专业性和思考深度两个方面,探讨区块链金融的发展路径,并为读者提…...
Redis与数据库保持一致
参考链接 先更新数据库,再更新redis 存在漏洞,如果更新Redis失败,仍然会导致不一致 先删Redis,再更新数据库并同步数据到Redis 存在漏洞,多线程情况下,线程1删除redis后,还是有可能被其他线程读取旧的数据…...
idea中vue项目 npm安装插件后node modules中找不到
从硬盘中重新加载一下...
已知两地经纬度,计算两地直线距离
文章目录 1 原理公式2 代码实现2.1 JavaScript2.2 C2.3 Python2.4 MATLAB 1 原理公式 在地球上,计算两点之间的直线距离通常使用地理坐标系(例如WGS84)。计算两地直线距离的公式是根据经纬度之间的大圆距离(Great Circle Distanc…...
我想开通期权?如何开通期权账户?
场内期权的合约由交易所统一标准化定制,大家面对的同一个合约对应的价格都是一致的,比较公开透明,期权开户当天不能交易的,期权开户需要满足20日日均50万及半年交易经验即可操作,下文科普我想开通期权?如何…...
ChatGPT对软件测试的影响
ChatGPT 是一个经过预训练的 AI 语言模型,可以通过聊天的方式回答问题,或者与人闲聊。它能处理的是文本类的信息,输出也只能是文字。它从我们输入的信息中获取上下文,结合它被训练的大模型,进行分析总结,给…...
minion在ubuntu上的搭建步骤
在Ubuntu上搭建MinIO可以按照以下步骤进行: 下载MinIO服务器二进制文件: 通过浏览器访问 https://min.io/download 或使用以下命令获取最新的MinIO二进制文件:wget https://dl.min.io/server/minio/release/linux-amd64/minio赋予二进制文件…...
Leetcode刷题笔记--Hot31-40
1--颜色分类(75) 主要思路: 快排 #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版本安装
总结: 使用conda新建切换环境,然后使用pip安装卸载包 【python】pip conda_conda list没有pytorch_myaijarvis的博客-CSDN博客 pip换源 https://blog.csdn.net/maotenghua/article/details/104188086 在当前用户目录下创建pip目录,即C:\U…...
BEVFusion复现 (Ubuntu RTX3090)
https://github.com/ADLab-AutoDrive/BEVFusion 1.环境安装 我的机器是RTX3090,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基本语法 标识符 标识符由数字、字符串、下划线构成。 注意事项: 标识符不以数字开头区分大小写下划线开头的标识符具有特殊意义保留字,Python保留了一些关键字,这些关键字都是通过小写字母进行保存。 下划线开头的特…...
SpringBoot笔记——(狂神说)——待续
路线 javase: OOPmysql:持久化 htmlcssjsjquery框架:视图,框架不熟练,css不好; javaweb:独立开发MVC三层架构的网站了∶原始 ssm :框架:简化了我们的开发流程,配置也开始较为复杂; war: tomcat运行 spring再简化: SpringBoot - jar:内嵌tomca…...
Linux TCP编程流程
一、TCP编程流程 TCP 提供的是面向连接的、可靠的、字节流服务。TCP的服务器端和客户端编程流程如下: 1.socket()方法 用来创建一个套接字,有了套接字就可以通过网络进行数据的收发。这也是为什么进行网络通信的程序首先要创建一个套接字。创建套接字时…...
pyqt5 QuickStart
在使用pyqt5之前,建议下载一个Anaconda环境,这样下载python包更方便,本篇文章是建立在已经安装好Anaconda的情况下使用的。IDE就是标准的PyCharm了。 一、pyqt包的安装 python终端执行下面两个安装命令: pip install PyQt5 pip …...
linux之kylin系统nginx的安装
一、nginx的作用 1.可做高性能的web服务器 直接处理静态资源(HTML/CSS/图片等),响应速度远超传统服务器类似apache支持高并发连接 2.反向代理服务器 隐藏后端服务器IP地址,提高安全性 3.负载均衡服务器 支持多种策略分发流量…...
springboot 百货中心供应链管理系统小程序
一、前言 随着我国经济迅速发展,人们对手机的需求越来越大,各种手机软件也都在被广泛应用,但是对于手机进行数据信息管理,对于手机的各种软件也是备受用户的喜爱,百货中心供应链管理系统被用户普遍使用,为方…...
ubuntu搭建nfs服务centos挂载访问
在Ubuntu上设置NFS服务器 在Ubuntu上,你可以使用apt包管理器来安装NFS服务器。打开终端并运行: sudo apt update sudo apt install nfs-kernel-server创建共享目录 创建一个目录用于共享,例如/shared: sudo mkdir /shared sud…...
《Qt C++ 与 OpenCV:解锁视频播放程序设计的奥秘》
引言:探索视频播放程序设计之旅 在当今数字化时代,多媒体应用已渗透到我们生活的方方面面,从日常的视频娱乐到专业的视频监控、视频会议系统,视频播放程序作为多媒体应用的核心组成部分,扮演着至关重要的角色。无论是在个人电脑、移动设备还是智能电视等平台上,用户都期望…...
中南大学无人机智能体的全面评估!BEDI:用于评估无人机上具身智能体的综合性基准测试
作者:Mingning Guo, Mengwei Wu, Jiarun He, Shaoxian Li, Haifeng Li, Chao Tao单位:中南大学地球科学与信息物理学院论文标题:BEDI: A Comprehensive Benchmark for Evaluating Embodied Agents on UAVs论文链接:https://arxiv.…...
从零实现STL哈希容器:unordered_map/unordered_set封装详解
本篇文章是对C学习的STL哈希容器自主实现部分的学习分享 希望也能为你带来些帮助~ 那咱们废话不多说,直接开始吧! 一、源码结构分析 1. SGISTL30实现剖析 // hash_set核心结构 template <class Value, class HashFcn, ...> class hash_set {ty…...
C# SqlSugar:依赖注入与仓储模式实践
C# SqlSugar:依赖注入与仓储模式实践 在 C# 的应用开发中,数据库操作是必不可少的环节。为了让数据访问层更加简洁、高效且易于维护,许多开发者会选择成熟的 ORM(对象关系映射)框架,SqlSugar 就是其中备受…...
【JavaWeb】Docker项目部署
引言 之前学习了Linux操作系统的常见命令,在Linux上安装软件,以及如何在Linux上部署一个单体项目,大多数同学都会有相同的感受,那就是麻烦。 核心体现在三点: 命令太多了,记不住 软件安装包名字复杂&…...
C++八股 —— 单例模式
文章目录 1. 基本概念2. 设计要点3. 实现方式4. 详解懒汉模式 1. 基本概念 线程安全(Thread Safety) 线程安全是指在多线程环境下,某个函数、类或代码片段能够被多个线程同时调用时,仍能保证数据的一致性和逻辑的正确性…...
sipsak:SIP瑞士军刀!全参数详细教程!Kali Linux教程!
简介 sipsak 是一个面向会话初始协议 (SIP) 应用程序开发人员和管理员的小型命令行工具。它可以用于对 SIP 应用程序和设备进行一些简单的测试。 sipsak 是一款 SIP 压力和诊断实用程序。它通过 sip-uri 向服务器发送 SIP 请求,并检查收到的响应。它以以下模式之一…...
