访问者模式的理解和实践
在软件开发过程中,设计模式为我们提供了解决常见问题的最佳实践。访问者模式(Visitor Pattern)是行为设计模式之一,它将数据操作与数据结构分离,使得在不修改数据结构的前提下,能够定义作用于这些元素的新的操作。本文将详细讲解访问者模式的概念、原理、优缺点,并通过Java代码示例展示其在实际项目中的应用。


一、访问者模式的概念
访问者模式是一种将数据操作与数据结构分离的设计模式。它通过将作用于某种数据结构中的各元素的操作封装起来,使得这些操作可以独立于数据结构进行变化。访问者模式使得我们能够在不修改数据结构的前提下,增加新的操作。
二、访问者模式的结构
访问者模式包含以下几个角色:
- Visitor(访问者):接口或抽象类,声明了访问者对各个元素的操作方法。
- ConcreteVisitor(具体访问者):实现了Visitor接口或抽象类,具体实现了对各个元素的操作。
- Element(元素):接口或抽象类,声明了接受访问者的方法。
- ConcreteElement(具体元素):实现了Element接口或抽象类,存储数据,并实现了接受访问者的方法。
- ObjectStructure(对象结构):包含多个元素,可以迭代这些元素,并允许访问者访问这些元素。
三、访问者模式的原理
访问者模式的原理是将操作从数据结构中分离出来,封装到访问者类中。数据结构中的每个元素都接受访问者对象,访问者对象通过访问这些元素来执行相应的操作。这样,当需要增加新的操作时,只需新增一个访问者类,而无需修改数据结构。
四、访问者模式的优缺点
优点:
- 增加新的操作很容易:只需增加一个新的访问者类,而无需修改已有的数据结构。
- 将数据操作集中管理:访问者模式将相关的操作集中到一个访问者类中,便于管理。
- 分离了数据结构和操作:数据结构和操作不再耦合在一起,提高了系统的灵活性。
缺点:
- 增加了类的数量:每增加一个新的操作,都需要增加一个新的访问者类,增加了类的数量。
- 破坏了封装:访问者需要访问被访问对象的内部结构,这在一定程度上破坏了封装性。
- 增加了系统复杂度:访问者模式的实现相对复杂,需要理解其工作原理,才能正确使用。
五、访问者模式的实践
下面通过Java代码示例,展示访问者模式在实际项目中的应用。
示例背景:
假设我们有一个简单的员工管理系统,员工分为两类:工程师(Engineer)和经理(Manager)。我们需要实现两个操作:计算工资(CalculateSalary)和显示员工信息(DisplayInfo)。
代码实现:
定义Element接口:
// 定义Element接口
public interface Element {void accept(Visitor visitor);
}
定义具体元素类:
// 定义工程师类
public class Engineer implements Element {private String name;private int salary;public Engineer(String name, int salary) {this.name = name;this.salary = salary;}public String getName() {return name;}public int getSalary() {return salary;}@Overridepublic void accept(Visitor visitor) {visitor.visit(this);}
}// 定义经理类
public class Manager implements Element {private String name;private int salary;private int bonus;public Manager(String name, int salary, int bonus) {this.name = name;this.salary = salary;this.bonus = bonus;}public String getName() {return name;}public int getSalary() {return salary;}public int getBonus() {return bonus;}@Overridepublic void accept(Visitor visitor) {visitor.visit(this);}
}
定义Visitor接口:
// 定义Visitor接口
public interface Visitor {void visit(Engineer engineer);void visit(Manager manager);
}
定义具体访问者类:
// 定义计算工资访问者类
public class CalculateSalaryVisitor implements Visitor {@Overridepublic void visit(Engineer engineer) {System.out.println("Engineer " + engineer.getName() + " salary: " + engineer.getSalary());}@Overridepublic void visit(Manager manager) {int totalSalary = manager.getSalary() + manager.getBonus();System.out.println("Manager " + manager.getName() + " salary: " + totalSalary);}
}// 定义显示信息访问者类
public class DisplayInfoVisitor implements Visitor {@Overridepublic void visit(Engineer engineer) {System.out.println("Engineer: " + engineer.getName());}@Overridepublic void visit(Manager manager) {System.out.println("Manager: " + manager.getName() + ", Bonus: " + manager.getBonus());}
}
定义ObjectStructure类:
import java.util.ArrayList;
import java.util.List;// 定义ObjectStructure类
public class ObjectStructure {private List<Element> elements = new ArrayList<>();public void addElement(Element element) {elements.add(element);}public void removeElement(Element element) {elements.remove(element);}public void accept(Visitor visitor) {for (Element element : elements) {element.accept(visitor);}}
}
客户端代码:
public class Client {public static void main(String[] args) {ObjectStructure os = new ObjectStructure();os.addElement(new Engineer("John Doe", 70000));os.addElement(new Manager("Jane Smith", 80000, 10000));Visitor calculateSalaryVisitor = new CalculateSalaryVisitor();os.accept(calculateSalaryVisitor);System.out.println("------");Visitor displayInfoVisitor = new DisplayInfoVisitor();os.accept(displayInfoVisitor);}
}
运行结果:
Engineer John Doe salary: 70000
Manager Jane Smith salary: 90000
------
Engineer: John Doe
Manager: Jane Smith, Bonus: 10000
总结
访问者模式通过将操作从数据结构中分离出来,提高了系统的灵活性和可扩展性。它使得在不修改数据结构的前提下,能够增加新的操作。然而,访问者模式也增加了类的数量,破坏了封装,增加了系统的复杂度。因此,在实际应用中,我们需要根据具体需求权衡利弊,选择是否使用访问者模式。
通过上面的示例,我们可以看到访问者模式在员工管理系统中的应用,通过定义不同的访问者类,实现了计算工资和显示员工信息的功能。这使得系统的操作更加灵活,易于扩展和维护。希望这篇文章能够帮助大家更好地理解访问者模式,并在实际项目中灵活运用。
相关文章:
访问者模式的理解和实践
在软件开发过程中,设计模式为我们提供了解决常见问题的最佳实践。访问者模式(Visitor Pattern)是行为设计模式之一,它将数据操作与数据结构分离,使得在不修改数据结构的前提下,能够定义作用于这些元素的新的…...
在Scala中对Map函数的使用
package pp28{object cscc {def main(args: Array[String]): Unit {val m1 Map("马云 — 阿里巴巴" -> 1964,"马化腾 — 腾讯" -> 1971,"李彦宏 - 百度" -> 1968,"雷军 - 小米" -> 1969,"丁磊 - 网易" -> …...
PyTorch基本使用-张量的索引操作
在操作张量时,经常要去获取某些元素进行处理或者修改操作,在这里需要了解torch中的索引操作。 准备数据: data torch.randint(0,10,[4,5]) print(data--->,data)输出结果: data---> tensor([[3, 9, 4, 0, 5],[7, 5, 9, …...
OpenCV实验:图片加水印
第二篇:图片添加水印(加 logo) 1. 实验原理 水印原理: 图片添加水印是图像叠加的一种应用,分为透明水印和不透明水印。水印的实现通常依赖于像素值操作,将水印图片融合到目标图片中,常用的方法…...
sql server log文件
确定 SQL Server 实例中具有大量 VDF 的数据库 SELECT [name], COUNT(l.database_id) AS vlf_count FROM sys.databases AS s CROSS APPLY sys.dm_db_log_info(s.database_id) AS l GROUP BY [name] HAVING COUNT(l.database_id) > 100; 在收缩日志文件之前确定事务日志中…...
Elasticsearch 集群部署
Elasticsearch 是一个分布式的搜索和分析引擎,广泛应用于日志分析、全文搜索、实时数据分析等场景。它以其高性能、高可用性和易用性而著称。本文档将引导您完成一个基本的 Elasticsearch 集群配置,包括节点间的通信、客户端访问、安全设置等关键步骤。我…...
微信小程序5-图片实现点击动作和动态加载同类数据
搜索 微信小程序 “动物觅踪” 观看效果 感谢阅读,初学小白,有错指正。 一、功能描述 a. 原本想通过按钮加载背景图片,来实现一个可以点击的搜索button,但是遇到两个难点,一是按钮大小调整不方便(网上搜索…...
策略梯度定理公式的详细推导
策略梯度定理公式的详细推导 以下是策略梯度定理公式从基础概率公式到最终形式的完整推导,帮助更清晰地理解推导过程中的每一个步骤。 1. 策略梯度的目标 我们希望最大化期望累积奖励 ( J ( θ ) J(\theta) J(θ) ),其定义为: J ( θ ) E…...
力扣-图论-10【算法学习day.60】
前言 ###我做这类文章一个重要的目的还是给正在学习的大家提供方向和记录学习过程(例如想要掌握基础用法,该刷哪些题?)我的解析也不会做的非常详细,只会提供思路和一些关键点,力扣上的大佬们的题解质量是非…...
《Python WEB安全 库全解析》
《Python WEB安全 库全解析》 一、Python WEB安全 库概述二、常见的 Python WEB安全 库介绍1. Jiasule2. Awesome Python Security3. Flask-Security4. Flask-SeaSurf 三、Python WEB 安全库的优缺点1. 优点2. 缺点 四、Python WEB 安全库的使用场景1. 开发 Web 应用2. 处理敏感…...
Linux yum-config-manager命令异常
错误信息 使用 yum-config-manager命令时错误信息如下 sudo yum-config-manager \ > --add-repo \ > https://download.docker.com/linux/centos/docker-ce.repo sudo: yum-config-manager: command not found 解决办法 第一步: sudo yum -y install yum-u…...
ios 开发配置蓝牙
如果使用了蓝牙功能, 又没有配置, 会出现以下错误: This app has crashed because it attempted to access privacy-sensitive data without a usage description. The apps Info.plist must contain an NSBluetoothAlwaysUsageDescription key with a string value explaini…...
geoserver(1) 发布sql 图层 支持自定义参数
前提使用postgis 数据库支持关联 join 支持 in,not in,like,及其他sql原生函数 新增sql图层 编写自定义sql 编辑sql语句必须输出带有geom数据 正则表达式去除 设置id以及坐标参考系 预览sql图层效果 拼接sql参数 http://xxx.com/geoserver/weather/wms?SERVICEWMS&VERSI…...
Linux:network:添加ip的时候自动添加一个本地路由
文章目录 问题问题 最近在看一个路由的问题,顺便看内核代码,发现在添加IP的时候,内核会自动添加一个local route。 net/ipv4/devinet.c inet_rtm_newaddr->__inet_insert_ifa /* Send message first, then call notifier.Notifier will trigger FIB update, so thatlis…...
go 集成nacos注册中心、配置中心
使用限制 Go>v1.15 Nacos>2.x 安装 使用go get安装SDK: go get -u github.com/nacos-group/nacos-sdk-go/v2 快速使用 初始化客户端配置ClientConfig constant.ClientConfig{TimeoutMs uint64 // 请求Nacos服务端的超时时间,默…...
ssd202d-badblock-坏块检测
这边文章讲述的是坏快检测功能 思路: 1.第一次烧录固件会实现跳坏块,但是后续使用会导致坏块的产生; 于是我在uboot环境变量添加了两个变量来控制坏快 lb_badnum //坏块个数 lb_badoff //坏块所在位置 2.第一次开机会根据lb_badnum是否…...
MySQL-练习-数据介绍
文章目录 一. 数据介绍1. 数据结构2. 创建数据库,数据表3. 员工表(employees)练习1 4. 顾客表(customers)练习2 5. 商品(products)和商品类别(categories)表练习3 6. 供应商表(suppliers)练习4 7. 订单和订单明细表练习5 二. 数据汇总三. 使用CASE WHEN …...
React框架:解锁现代化Web开发的新维度
在当今前端开发领域,React 无疑是一颗璀璨的明星。React 是由 Facebook 开发的用于构建用户界面的 JavaScript 库,它在前端开发中占据着重要的地位,为开发者提供了一种高效、灵活且可维护的方式来构建复杂的用户界面。 一、React 的背景与开…...
电阻功率,限流,等效电阻
1 电阻额定功率 2 电阻限流作用 3 电阻并联等效电阻...
Qt | 开发工具(top1)
Qt Creator 跨平台、完整的集成开发环境(IDE),供应用程序开发者创建用于多个桌面、嵌入式和移动设备平台的应用程序。 Qt Linguist 一套将Qt C和Qt Quick应用程序翻译成本地语言的工具。 qmake Qt自动化构建工具,简化了不同平台的构建过程。…...
大数据学习栈记——Neo4j的安装与使用
本文介绍图数据库Neofj的安装与使用,操作系统:Ubuntu24.04,Neofj版本:2025.04.0。 Apt安装 Neofj可以进行官网安装:Neo4j Deployment Center - Graph Database & Analytics 我这里安装是添加软件源的方法 最新版…...
深入浅出Asp.Net Core MVC应用开发系列-AspNetCore中的日志记录
ASP.NET Core 是一个跨平台的开源框架,用于在 Windows、macOS 或 Linux 上生成基于云的新式 Web 应用。 ASP.NET Core 中的日志记录 .NET 通过 ILogger API 支持高性能结构化日志记录,以帮助监视应用程序行为和诊断问题。 可以通过配置不同的记录提供程…...
深入浅出:JavaScript 中的 `window.crypto.getRandomValues()` 方法
深入浅出:JavaScript 中的 window.crypto.getRandomValues() 方法 在现代 Web 开发中,随机数的生成看似简单,却隐藏着许多玄机。无论是生成密码、加密密钥,还是创建安全令牌,随机数的质量直接关系到系统的安全性。Jav…...
苍穹外卖--缓存菜品
1.问题说明 用户端小程序展示的菜品数据都是通过查询数据库获得,如果用户端访问量比较大,数据库访问压力随之增大 2.实现思路 通过Redis来缓存菜品数据,减少数据库查询操作。 缓存逻辑分析: ①每个分类下的菜品保持一份缓存数据…...
mysql已经安装,但是通过rpm -q 没有找mysql相关的已安装包
文章目录 现象:mysql已经安装,但是通过rpm -q 没有找mysql相关的已安装包遇到 rpm 命令找不到已经安装的 MySQL 包时,可能是因为以下几个原因:1.MySQL 不是通过 RPM 包安装的2.RPM 数据库损坏3.使用了不同的包名或路径4.使用其他包…...
算法笔记2
1.字符串拼接最好用StringBuilder,不用String 2.创建List<>类型的数组并创建内存 List arr[] new ArrayList[26]; Arrays.setAll(arr, i -> new ArrayList<>()); 3.去掉首尾空格...
STM32HAL库USART源代码解析及应用
STM32HAL库USART源代码解析 前言STM32CubeIDE配置串口USART和UART的选择使用模式参数设置GPIO配置DMA配置中断配置硬件流控制使能生成代码解析和使用方法串口初始化__UART_HandleTypeDef结构体浅析HAL库代码实际使用方法使用轮询方式发送使用轮询方式接收使用中断方式发送使用中…...
归并排序:分治思想的高效排序
目录 基本原理 流程图解 实现方法 递归实现 非递归实现 演示过程 时间复杂度 基本原理 归并排序(Merge Sort)是一种基于分治思想的排序算法,由约翰冯诺伊曼在1945年提出。其核心思想包括: 分割(Divide):将待排序数组递归地分成两个子…...
Python环境安装与虚拟环境配置详解
本文档旨在为Python开发者提供一站式的环境安装与虚拟环境配置指南,适用于Windows、macOS和Linux系统。无论你是初学者还是有经验的开发者,都能在此找到适合自己的环境搭建方法和常见问题的解决方案。 快速开始 一分钟快速安装与虚拟环境配置 # macOS/…...
深度解析云存储:概念、架构与应用实践
在数据爆炸式增长的时代,传统本地存储因容量限制、管理复杂等问题,已难以满足企业和个人的需求。云存储凭借灵活扩展、便捷访问等特性,成为数据存储领域的主流解决方案。从个人照片备份到企业核心数据管理,云存储正重塑数据存储与…...
