访问者模式:对象结构的元素处理
欢迎来到设计模式系列的第十九篇文章,本篇将介绍访问者模式。访问者模式是一种行为型设计模式,它用于处理对象结构中不同类型的元素,而不需要修改这些元素的类。
什么是访问者模式?
访问者模式是一种将数据结构与数据操作分离的设计模式。在访问者模式中,我们定义了一个访问者(Visitor)类,该类包含一组访问方法,每个方法用于处理不同类型的元素。然后,我们可以为不同类型的元素定义一个元素类,并将这些元素传递给访问者进行处理。
访问者模式的核心思想是在不修改元素类的情况下,通过访问者来实现对元素的操作。这种模式通常用于处理复杂对象结构,其中包含多种类型的元素,以及需要执行不同操作的需求。
访问者模式的角色
访问者模式涉及以下几个角色:
- 访问者(Visitor):访问者是一个接口或抽象类,它定义了一组访问方法,每个方法用于处理不同类型的元素。
- 具体访问者(Concrete Visitor):具体访问者是实现访问者接口的具体类,它实现了访问方法,用于对元素进行具体的处理。
- 元素(Element):元素是一个接口或抽象类,它定义了一个接受(Accept)方法,该方法接受一个访问者作为参数,以便访问者可以对该元素进行操作。
- 具体元素(Concrete Element):具体元素是实现元素接口的具体类,它实现了接受方法,并将自身作为参数传递给访问者。
- 对象结构(Object Structure):对象结构是一个包含多种类型元素的集合,它通常提供了一种方式来遍历这些元素,以便访问者可以对它们进行操作。
为什么需要访问者模式?
访问者模式的主要目的是将数据结构与数据操作分离,使得可以在不修改元素类的情况下,通过访问者来添加新的操作。这种模式适用于以下情况:
- 元素类的稳定性高:如果元素类的稳定性很高,很少需要修改,但需要添加新的操作,那么使用访问者模式可以避免修改元素类。
- 多种操作与元素的组合:如果存在多种不同类型的操作需要与多种不同类型的元素组合,访问者模式可以简化操作的管理。
- 封装性要求高:访问者模式可以将具体的操作封装在具体访问者中,使得元素类保持封装性,不暴露细节。
访问者模式的实现
让我们通过一个简单的示例来演示访问者模式的实现。考虑一个电商平台,有不同类型的商品,包括书籍、电子产品和食品。我们希望实现一个价格计算器,该计算器可以根据商品的类型和折扣策略计算最终价格。
// 访问者接口
interface Visitor {void visit(Book book);void visit(ElectronicProduct electronicProduct);void visit(Food food);
}// 具体访问者
class PriceCalculator implements Visitor {@Overridepublic void visit(Book book) {double discount = book.getCategory().equals("Fiction") ? 0.2 : 0.1;double discountedPrice = book.getPrice() * (1 - discount);System.out.println("Price of " + book.getName() + ": $" + discountedPrice);}@Overridepublic void visit(ElectronicProduct electronicProduct) {double discountedPrice = electronicProduct.getPrice() * 0.9;System.out.println("Price of " + electronicProduct.getName() + ": $" + discountedPrice);}@Overridepublic void visit(Food food) {double discountedPrice = food.getPrice() * 0.95;System.out.println("Price of " + food.getName() + ": $" + discountedPrice);}
}// 元素接口
interface Element {void accept(Visitor visitor);
}// 具体元素
class Book implements Element {private String name;private String category;private double price;public Book(String name, String category, double price) {this.name = name;this.category = category;this.price = price;}public String getName() {return name;}public String getCategory() {return category;}public double getPrice() {return price;}@Overridepublic void accept(Visitor visitor) {visitor.visit(this);}
}class ElectronicProduct implements Element {private String name;private double price;public ElectronicProduct(String name, double price) {this.name = name;this.price = price;}public String getName() {return name;}public double getPrice() {return price;}@Overridepublic void accept(Visitor visitor) {visitor.visit(this);}
}class Food implements Element {private String name;private double price;public Food(String name, double price) {this.name = name;this.price = price;}public String getName() {return name;}public double getPrice() {return price;}@Overridepublic void accept(Visitor visitor) {visitor.visit(this);}
}// 对象结构
class ShoppingCart {private List<Element> items = new ArrayList<>();public void addItem(Element item) {items.add(item);}public void accept(Visitor visitor) {for (Element item : items) {item.accept(visitor);}}
}public class VisitorPatternExample {public static void main(String[] args) {ShoppingCart cart = new ShoppingCart();cart.addItem(new Book("The Great Gatsby", "Fiction", 15.99));cart.addItem(new ElectronicProduct("Smartphone", 499.99));cart.addItem(new Food("Chocolate", 4.99));Visitor priceCalculator = new PriceCalculator();cart.accept(priceCalculator);}
}
在这个示例中,我们定义了访问者接口 Visitor,并实现了具体访问者 PriceCalculator。元素接口 Element 定义了 accept 方法,用于接受访问者。每个具体元素类都实现了 accept 方法,并将自身传递给访问者。
对象结构 ShoppingCart 包含了不同类型的商品元素,并提供了 accept 方法,用于遍历元素并调用访问者的方法。
在示例的 main 方法中,我们创建了一个购物车 cart,并向其中添加了书籍、电子产品和食品。然后,我们创建了一个 PriceCalculator 访问者,并将购物车传递给它进行价格计算。
访问者模式的优点
访问者模式的优点包括:
- 符合开闭原则:可以通过添加新的访问者来扩展操作,而无需修改元素类。
- 将操作与元素分离:访问者模式可以将数据结构与数据操作分离,使元素类保持简洁,不包含操作的逻辑。
- 支持多态行为:访问者模式利用多态性,使不同类型的元素可以有不同的操作,增加了灵活性。
访问者模式的缺点
访问者模式的缺点包括:
- 增加了类的数量:引入访问者模式会增加访问者和元素类的数量,增加了代码的复杂性。
- 不容易理解:访问者模式的结构相对复杂,可能不容易理解和维护。
适用场景
访问者模式适用于以下情况:
- 当需要对复杂对象结构中的元素进行不同类型的操作,而且这些操作需要保持独立时。
- 当元素类的稳定性高,不经常修改,但需要添加新的操作时。
- 当希望在不修改元素类的情况下,增加新的操作或访问方式时。
总结
访问者模式是一种行为型设计模式,它将数据结构与数据操作分离,通过访问者来实现对元素的操作。这种模式在处理复杂对象结构和需要多种操作的情况下非常有用。虽然它增加了类的数量和代码的复杂性,但能够提供灵活性和可扩展性,符合开闭原则。在实际项目中,可以根据具体需求考虑是否使用访问者模式。
相关文章:
访问者模式:对象结构的元素处理
欢迎来到设计模式系列的第十九篇文章,本篇将介绍访问者模式。访问者模式是一种行为型设计模式,它用于处理对象结构中不同类型的元素,而不需要修改这些元素的类。 什么是访问者模式? 访问者模式是一种将数据结构与数据操作分离的…...
ChatGPT快速入门
ChatGPT快速入门 一、什么是ChatGPT二、ChatGPT底层逻辑2.1 实现原理2.2 IO流程 三、ChatGPT应用场景3.1 知心好友3.2 文案助理3.3 创意助理3.4 角色扮演 一、什么是ChatGPT ChatGPT指的是基于GPT(Generative Pre-trained Transformer)模型的对话生成系…...
链表的实现(c语言)
链表分为单链表、双链表和循环链表,这些理论知识在笔记中自然写了,这里我只写出其中的实现: 单链表的实现 #include <stdio.h> #include <stdlib.h> #include <string.h> typedef struct Book {char bookname[20];char a…...
【Redis】渐进式遍历
scan命令渐进式遍历 Redis使⽤scan命令进⾏渐进式遍历键,进⽽解决直接使⽤keys获取键时可能出现的阻塞问题。每次scan命令的时间复杂度是O(1),但是要完整地完成所有键的遍历,需要执⾏多次scan。 SCAN 以渐进式的⽅式进⾏键的遍历。 SCAN…...
uni-app开发微信小程序的报错[渲染层错误]排查及解决
一、报错信息 [渲染层错误] Framework nner error (expect FLOW INITIALCREATION end but get FLOW CREATE-NODE) 二、原因分析及解决方案 第一种 原因:基础库版本的原因导致的。 解决: 1.修改调试基础库版本 2.详情—>本地设置—>调试基础库…...
三、C语言常用运算符
1、算术运算符 符号说明加号-减号*乘号/除号%取余符号,相除以后余数是几自增运算符,整数值增加 1--自减运算符,整数值减少1 2、关系运算符 符号说明检查两个操作数的值是否相等,如果相等则条件为真。!检查两个操作数的值是否相…...
ubuntu联网图标消失
sudo service NetworkManager stopsudo rm /var/lib/NetworkManager/NetworkManager.statesudo service NetworkManager start执行 sudo rm /var/lib/NetworkManager/NetworkManager.state 命令将删除位于 /var/lib/NetworkManager 目录下的 NetworkManager.state 文件。...
中华人民共和国网络安全法
中华人民共和国网络安全法 《中华人民共和国网络安全法》已由中华人民共和国第十二届全国人民代表大会常务委员会第二十四次会议于2016年11月7日通过,现予公布,自2017年6月1日起施行。2022年9月12日,国家互联网信息办公室发布关于公开征求《…...
Java并发面试题:(二)线程池参数和使用
线程池参数 线程池工作过程 当提交一个新任务到线程池时,具体的执行流程如下: 当我们提交任务,线程池会根据corePoolSize大小创建若干任务数量线程执行任务 当任务的数量超过corePoolSize数量,后续的任务将会进入阻塞队列阻塞排…...
Python机器学习零基础理解AffinityPropagation亲和力传播聚类
如何解决社交媒体上的好友推荐问题? 想象一下,一个社交媒体平台希望提供更加精准的好友推荐功能,让用户能更容易地找到可能成为好友的人。这个问题看似简单,但当面对数百万甚至数千万的用户时,手动进行好友推荐就变得几乎不可能。 解决这个问题的一个方案就是使用机器学…...
Open3D 进阶(12)PCA拟合空间直线
目录 一、算法原理二、代码实现三、结果展示本文由CSDN点云侠原创,原文链接。如果你不是在点云侠的博客中看到该文章,那么此处便是不要脸的爬虫。 一、算法原理 见:Open3D 最小二乘拟合空间直线(方法一) 二、代码实现 import numpy as np import open3d as o...
4种实现JS深拷贝的方法
浅拷贝与深拷贝 浅拷贝是创建一个新对象,这个对象有着原始对象属性值的拷贝。如果属性是基本类型,拷贝的就是基本类型的值,如果属性是引用类型,拷贝的是内存地址 。 如果不进行深拷贝,其中一个对象改变了对象的值&am…...
六、RocketMQ发送事务消息
事务消息介绍 在一些对数据一致性有强需求的场景,可以用 Apache RocketMQ 事务消息来解决,从而保证上下游数据的一致性。 以电商交易场景为例,用户支付订单这一核心操作的同时会涉及到下游物流发货、积分变更、购物车状态清空等多个子系统的…...
Node.js初体验
Node.js简介 node.js的运行环境 1.V8引擎对js代码进行解析与执行 2.内置API:fs、path、http...等,提供了一些能力,能够使得js调用这些API去做一些后端的事情 流程:我们在node.js的运行环境中编写待执行的JavaScript代码&#…...
激活函数理解
激活函数(Activation Function)是神经网络中的一种数学函数,它的作用是为神经元(或人工神经元)引入非线性特性,从而使神经网络能够学习和表示更复杂的函数。激活函数通常位于神经元的输出端,接收…...
【docker - 安装】windows 10 专业版 安装docker,以及 WSL kernel version too low 解决方案
一、开启 Hyper-V 二、下载 docker 三、安装 docker 四、问题 Stage 1:打开 powershell,并执行 Stage 2:下载Linux内核更新包,并安装 Stage 3:将 WSL 2 设置为默认版本 Stage 4:安装所选的 Linux 分…...
洛谷P1601
题目见:P1601 AB Problem(高精) - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) 1. 问题分析 加法计算问题应该和在界面输出“Hello,world!”是一个难度级别,但是问题在于受限于原始数据类型的限制,无法进行大数据的精…...
Elasticsearch:使用 LangChain 对话链和 OpenAI 的聊天机器人
在此笔记本中,我们将构建一个聊天机器人,它可以回答有关自定义数据的问题,例如雇主的政策。 聊天机器人使用 LangChain 的 ConversationalRetrievalChain,具有以下功能: 用自然语言回答问题在 Elasticsearch 中运行混…...
铜死亡+机器学习+WGCNA+分型生信思路
今天给同学们分享一篇单基因泛癌免疫实验生信文章“IGF2BP3 overexpression predicts poor prognosis and correlates with immune infiltration in bladder cancer”,这篇文章于2023年2月3日发表在BMC Cancer期刊上,影响因子为3.8。 膀胱癌是全球最常见…...
GB28181平台简介
产品简介 LiveMedia视频中间件是支持部署到本地服务器或者云服务器的纯软件服务,也提供服务器、GPU一体机全包服务,提供视频设备管理、无插件、跨平台的实时视频、历史回放、语音对讲、设备控制等基础功能,支持视频协议有海康、大华私有协议…...
告别命令行:5分钟掌握ffmpegGUI视频处理新方式
告别命令行:5分钟掌握ffmpegGUI视频处理新方式 【免费下载链接】ffmpegGUI ffmpeg GUI 项目地址: https://gitcode.com/gh_mirrors/ff/ffmpegGUI ffmpegGUI是一款创新的跨平台视频处理工具,它将强大的FFmpeg命令行功能转化为直观的图形界面操作&a…...
数组运算18题:从递归求和解到Kadane算法
1. 数组运算进阶指南:18道经典题目深度解析数组作为最基本的数据结构,在编程面试和实际开发中无处不在。掌握数组的各种运算技巧不仅能帮助你在面试中脱颖而出,更能提升日常编码的效率和质量。本文将深入解析18个经典的数组运算题目ÿ…...
量子机器学习在医疗影像中的技术迷思与测试验证陷阱
当量子计算遭遇医学影像近年来,"量子赋能医疗影像"成为热门概念,宣称通过量子算法(如QSVM、量子卷积)可大幅提升病灶识别精度和图像重建效率。然而,作为软件测试从业者,我们需警惕技术炒作背后的…...
2025届毕业生推荐的五大AI论文方案推荐榜单
Ai论文网站排名(开题报告、文献综述、降aigc率、降重综合对比) TOP1. 千笔AI TOP2. aipasspaper TOP3. 清北论文 TOP4. 豆包 TOP5. kimi TOP6. deepseek 普及时,人工智能生成的内容让文本展现出一种高度模式化的特性,这一情…...
新手福音:在快马平台开启你的云端代码编程第一课
作为一名刚接触编程的新手,我最近发现了一个特别适合入门的学习方式——云端代码编程。以前总觉得学编程要先装一堆软件、配置环境,光是这些准备工作就能劝退不少人。但在InsCode(快马)平台上,这些烦恼都不存在了。 零门槛的编程初体验 打开平…...
MySQL
我目前正在学习SQL语句,我所了解到的MySQL其实是一堆服务器,在下载服务器的时候,可以选择下载一些客户端,MySQL会自带一些客户端,像类似于终端的小黑框,还有什么bench;我还是喜欢外观好看的客户端 !我学SQL语句目前学到了数据类型,有数值型的,字符型的,二进制型的,值得一提的是…...
Phi-4-mini-reasoning开源模型优势:轻量级+高精度+低GPU资源占用实测
Phi-4-mini-reasoning开源模型优势:轻量级高精度低GPU资源占用实测 1. 模型概述 Phi-4-mini-reasoning是一款专注于推理任务的文本生成模型,特别擅长处理数学题、逻辑题、多步分析和简洁结论输出。与通用聊天模型不同,它采用了"题目输…...
亚洲美女-造相Z-Turbo算力适配实践:24G显存下支持batch_size=2高清图并行生成
亚洲美女-造相Z-Turbo算力适配实践:24G显存下支持batch_size2高清图并行生成 1. 快速了解亚洲美女-造相Z-Turbo 亚洲美女-造相Z-Turbo是一个专门针对亚洲女性形象生成优化的文生图模型,基于Z-Image-Turbo的LoRA版本进行深度定制。这个模型最大的特点是…...
WarcraftHelper:魔兽争霸III现代化增强工具全面指南
WarcraftHelper:魔兽争霸III现代化增强工具全面指南 【免费下载链接】WarcraftHelper Warcraft III Helper , support 1.20e, 1.24e, 1.26a, 1.27a, 1.27b 项目地址: https://gitcode.com/gh_mirrors/wa/WarcraftHelper 如何让经典游戏适配现代硬件环境&…...
CRT库链接冲突详解:为什么你的Visual Studio项目会警告LNK4098(含/NODEFAULTLIB使用指南)
CRT库链接冲突深度解析:从原理到实战解决LNK4098警告 当你用Visual Studio编译C项目时,突然蹦出"warning LNK4098: 默认库msvcrtd.lib与其他库的使用冲突"的提示,这就像开车时仪表盘突然亮起的警告灯——它不会立即让引擎熄火&…...
