【设计模式-访问者模式】
定义
访问者模式(Visitor Pattern)是一种行为型设计模式,允许你在不修改已有类的情况下向这些类添加新的功能或行为。它通过将操作的执行逻辑从对象的类中分离出来,使得你可以在保持类的封闭性(符合开闭原则)的前提下为不同对象定义新的操作。
UML图

- Visitor(访问者):定义了针对元素结构中每种类型元素的访问操作,通常通过重载 visit 方法实现。
- Element(元素接口或抽象类):定义了一个 accept(Visitor visitor) 方法,允许访问者访问自己。
- ConcreteElement(具体元素):实现了 Element 接口,并在 accept 方法中调用访问者的对应方法,如 visitor.visit(this)。
- ConcreteVisitor(对象结构):可以是一个包含不同类型元素的集合,它负责遍历元素并对每个元素调用 accept 方法。
优点
- 开闭原则:可以在不修改现有类的情况下添加新的操作。
- 单一职责原则:通过将元素的操作行为封装到访问者中,元素类的职责得以简化。
- 可扩展性强:可以为对象结构中的类定义新的操作,而不改变类的定义。
缺点
- 破坏封装性:访问者需要了解元素的内部细节,这可能破坏类的封装性。
- 难以维护:如果元素类频繁变更,则需要更新所有访问者,访问者模式的维护成本可能较高。
- 双重分派问题:访问者模式的实现涉及双重分派,即通过 accept 方法调用访问者的 visit 方法,这使得结构变得复杂。
代码
// 定义访问者接口
interface Visitor {void visit(Book book);void visit(Fruit fruit);
}// 定义元素接口
interface ItemElement {void accept(Visitor visitor);
}// 具体元素类 Book
class Book implements ItemElement {private String title;private double price;public Book(String title, double price) {this.title = title;this.price = price;}public String getTitle() {return title;}public double getPrice() {return price;}@Overridepublic void accept(Visitor visitor) {visitor.visit(this);}
}// 具体元素类 Fruit
class Fruit implements ItemElement {private String name;private double weight;private double pricePerKg;public Fruit(String name, double weight, double pricePerKg) {this.name = name;this.weight = weight;this.pricePerKg = pricePerKg;}public String getName() {return name;}public double getWeight() {return weight;}public double getPricePerKg() {return pricePerKg;}@Overridepublic void accept(Visitor visitor) {visitor.visit(this);}
}// 实现具体的访问者
class ShoppingCartVisitor implements Visitor {@Overridepublic void visit(Book book) {System.out.println("Book: " + book.getTitle() + ", Price: " + book.getPrice());}@Overridepublic void visit(Fruit fruit) {double cost = fruit.getWeight() * fruit.getPricePerKg();System.out.println("Fruit: " + fruit.getName() + ", Cost: " + cost);}
}// 测试访问者模式
public class VisitorPatternDemo {public static void main(String[] args) {ItemElement[] items = new ItemElement[] {new Book("Design Patterns", 50),new Fruit("Apple", 2, 3)};Visitor visitor = new ShoppingCartVisitor();for (ItemElement item : items) {item.accept(visitor); // 访问每个元素}}
}
场景
- 对象结构稳定:当你的对象结构(类)相对固定,但需要在这个结构上添加新的操作时,访问者模式非常合适。这样可以避免修改已有类的代码。
- 需要对多个类执行相似的操作:当你需要对多个不同类型的元素执行类似的操作时,使用访问者模式可以集中管理这些操作。
- 复杂的对象结构:在处理复杂的对象结构时(例如树形结构),访问者模式可以提供清晰的访问逻辑,避免在每个元素中实现相同的逻辑。
- 数据结构和操作分离:当你希望将数据结构与操作分离,以便于未来扩展时,访问者模式是一个良好的选择。这样可以保持类的单一职责原则。
- 频繁变化的操作:如果你的操作逻辑频繁变化,但元素结构相对稳定,使用访问者模式可以方便地添加新的操作而不影响已有的元素类。
- 需要对元素进行类型判断:访问者模式允许在访问者中根据元素的具体类型执行不同的操作,便于类型判断和特定处理。
具体示例
- 编译器:在编译器中,抽象语法树(AST)需要执行不同的操作(如语义分析、优化等),访问者模式可以有效地管理这些操作。
- 图形绘制:在图形编辑软件中,图形元素(如线条、圆形、矩形等)可以通过访问者模式实现不同的绘制和变换操作。
- 文件系统:在文件系统中,可以定义访问者来实现文件的不同处理(如压缩、加密等),而不需要修改文件类的实现。
- 账单处理:在购物车或账单系统中,可以使用访问者模式来处理不同类型的商品(如书籍、食品等),并计算总价或应用折扣。
总结
访问者模式适合于需要在多个元素上执行不同操作,且希望保持代码清晰和可扩展的情况。
相关文章:
【设计模式-访问者模式】
定义 访问者模式(Visitor Pattern)是一种行为型设计模式,允许你在不修改已有类的情况下向这些类添加新的功能或行为。它通过将操作的执行逻辑从对象的类中分离出来,使得你可以在保持类的封闭性(符合开闭原则ÿ…...
一元运算符(自增自减)
一、一元运算符 一元运算符,只需要一个操作数 1. 正号 正号不会对数字产生任何影响 2.-负号 负号可以对数字进行负号的取反 对于非Number的值,会将先转换为Number,在进行运算: 可以对一个其他的数据类型使用,来将其转换为n…...
gitlab/极狐-离线包下载地址
如果想要使用Gitlab/极狐进行数据的恢复,只能使用相同版本或者相近版本的安装包,因此有时候需要到它的官网上下载对应版本的安装包,以下是我收集到的对应地址的下载路径: Gitlab Gitlab离线库, https://packages.gitl…...
C++——输入三个整数,按照由小到大的顺序输出。用指针方法处理。
没注释的源代码 #include <iostream> using namespace std; void swap(int *m,int *n); int main() { int a,b,c; int *p1,*p2,*p3; cout<<"请输入三个整数:"<<endl; cin>>a>>b>>c; p1&a;p2&b;p3&c;…...
【Java8 重要特性】Lambda 表达式
文章目录 Lambda函数式接口Lambda 规则规范简化过程改写 Arrays.setAll()改写 Arrays.sort() forEach循环 list 集合循环 list 集合并输出对象信息循环 Map 集合 方法引用和构造器引用方法引用构造器引用 Lambda Lambda是一个匿名函数,我们可以将Lambda表达式理解为…...
word2vec--CBOW与Skip-Gram 两种模型
Word2Vec 是一种流行的用于生成词嵌入(Word Embeddings)的无监督学习模型,它由 Google 的一个团队在 2013 年提出。它的主要目的是将单词映射到一个连续的向量空间,使得语义相似的单词在这个空间中靠得更近。 Word2Vec 有两种主要…...
iOS六大设计原则设计模式
六大设计原则: 一、单一职责原则 一个类或者模块只负责完成一个职责或者功能。 类似于:UIView 和 CALayer 二、开放封闭原则 对扩展开放,对修改封闭。 我们要尽量通过扩展软件实体来解决需求变化,而不是通过修改已有的代码来…...
nacos 集群搭建
主机准备 IProle192.168.142.155slave02192.168.142.156slave192.168.142.157master 三台主机上分别构建 mysql 镜像 FROM mysql:8.0.31 ADD https://raw.githubusercontent.com/alibaba/nacos/develop/distribution/conf/mysql-schema.sql /docker-entrypoint-initdb.d/nac…...
STM32快速复习(十二)FLASH闪存的读写
文章目录 一、FLASH是什么?FLASH的结构?二、使用步骤1.标准库函数2.示例函数 总结 一、FLASH是什么?FLASH的结构? 1、FLASH简介 (1)STM32F1系列的FLASH包含程序存储器、系统存储器和选项字节三个部分&…...
漏洞扫描工具使用
首先把补丁的两个文件复制下来替换原文件 找到C:\ProgramData\Acunetix\shared\license然后替换 然后打开漏扫工具并刷新页面 然后添加要扫描的网站 等他扫描完成 扫描完成就可以生成报告了 一共五十多页的报告...
C++ | Leetcode C++题解之第424题替换后的最长重复字符
题目: 题解: class Solution { public:int characterReplacement(string s, int k) {vector<int> num(26);int n s.length();int maxn 0;int left 0, right 0;while (right < n) {num[s[right] - A];maxn max(maxn, num[s[right] - A]);i…...
利士策分享,动摇时刻的自我救赎
利士策分享,动摇时刻的自我救赎 在人生的长河中,我们每个人都会面临各种挑战与抉择, 那些让人心生动摇的瞬间,如同夜空中偶尔掠过的乌云,遮蔽了前行的星光。 但正是这些动摇,构成了我们成长的轨迹&#x…...
动手学深度学习(李沐)PyTorch 第 1 章 引言
在线电子书 深度学习介绍 安装 使用conda环境 conda create -n d2l-zh python3.8 pip安装需要的包 pip install jupyter d2l torch torchvision下载代码并执行 wget https://zh-v2.d2l.ai/d2l-zh.zip unzip d2l-zh.zip jupyter notebookpip install rise如果不想使用jupyt…...
二叉树(二)深度遍历和广度遍历
一、层序遍历 广度优先搜索:使用队列,先进先出 模板: 1、定义返回的result和用于辅助的队列 2、队列初始化: root非空时进队 3、遍历整个队列:大循环while(!que.empty()) 记录每层的size以及装每层结果的变量&a…...
【算法——双指针】
922. 按奇偶排序数组 II 算法讲解050【必备】双指针技巧与相关题目_哔哩哔哩_bilibili main:vector<int>nums { 3,1,2,4 };int i 0, j 1;int n nums.size() - 1;while (j < nums.size() && i < nums.size()) //如果奇偶任一方排好了,另…...
Rocky Linux 9 中添加或删除某个网卡的静态路由的方法
使用ip命令配置临时路由 添加静态路由 ip route add <目的网络> via <下一跳IP> dev <网卡接口名称>例: 给eth0网卡添加一个到达 192.168.2.0/24 网络,下一跳为 192.168.1.254 的路由 ip route add 192.168.2.0/24 via 192.168.1.254 dev eth0…...
网站建设中常见的网站后台开发语言有哪几种,各自优缺点都是什么?
市场上常见的网站后台开发语言有PHP、Python、JavaScript、Ruby、Java和.NET等。这些语言各有其独特的优缺点,适用于不同的开发场景和需求。以下是对这些语言的具体介绍: PHP 优点:PHP是一种广泛用于Web开发的动态脚本语言,特别适…...
【程序大侠传】应用内存缓步攀升,告警如影随形
前序 在武侠编码的江湖中,内存泄漏犹如隐秘杀手,潜伏于应用程序的各个角落,悄无声息地吞噬着系统资源。若不及时发现和解决,必将导致内存枯竭,应用崩溃。 背景:内存泄漏的由来 内存泄漏,乃程序…...
JavaWEB概述
JavaWEB概述 一、什么是JavaWEB 用Java技术解决web互联网领域的技术栈。要学习JavaWEB首先得知道什么是客户端和服务端 客户端:简而言之,这就是使用方,比如我们下载一个软件去使用,里面有很多我们可以使用的功能,那…...
半结构化知识抽取案例
半结构化知识抽取是指从半结构化数据源(如HTML、XML、JSON等)中提取有用的信息,并将其转换为更易于理解和使用的知识形式。半结构化数据通常包含一些结构化的标记或标签,但不像完全结构化的数据那样严格。 比如抽取如下网页到neo …...
MPNet:旋转机械轻量化故障诊断模型详解python代码复现
目录 一、问题背景与挑战 二、MPNet核心架构 2.1 多分支特征融合模块(MBFM) 2.2 残差注意力金字塔模块(RAPM) 2.2.1 空间金字塔注意力(SPA) 2.2.2 金字塔残差块(PRBlock) 2.3 分类器设计 三、关键技术突破 3.1 多尺度特征融合 3.2 轻量化设计策略 3.3 抗噪声…...
内存分配函数malloc kmalloc vmalloc
内存分配函数malloc kmalloc vmalloc malloc实现步骤: 1)请求大小调整:首先,malloc 需要调整用户请求的大小,以适应内部数据结构(例如,可能需要存储额外的元数据)。通常,这包括对齐调整,确保分配的内存地址满足特定硬件要求(如对齐到8字节或16字节边界)。 2)空闲…...
MySQL 隔离级别:脏读、幻读及不可重复读的原理与示例
一、MySQL 隔离级别 MySQL 提供了四种隔离级别,用于控制事务之间的并发访问以及数据的可见性,不同隔离级别对脏读、幻读、不可重复读这几种并发数据问题有着不同的处理方式,具体如下: 隔离级别脏读不可重复读幻读性能特点及锁机制读未提交(READ UNCOMMITTED)允许出现允许…...
vscode(仍待补充)
写于2025 6.9 主包将加入vscode这个更权威的圈子 vscode的基本使用 侧边栏 vscode还能连接ssh? debug时使用的launch文件 1.task.json {"tasks": [{"type": "cppbuild","label": "C/C: gcc.exe 生成活动文件"…...
ESP32 I2S音频总线学习笔记(四): INMP441采集音频并实时播放
简介 前面两期文章我们介绍了I2S的读取和写入,一个是通过INMP441麦克风模块采集音频,一个是通过PCM5102A模块播放音频,那如果我们将两者结合起来,将麦克风采集到的音频通过PCM5102A播放,是不是就可以做一个扩音器了呢…...
论文解读:交大港大上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化学习框架(一)
宇树机器人多姿态起立控制强化学习框架论文解析 论文解读:交大&港大&上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化学习框架(一) 论文解读:交大&港大&上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化…...
JVM暂停(Stop-The-World,STW)的原因分类及对应排查方案
JVM暂停(Stop-The-World,STW)的完整原因分类及对应排查方案,结合JVM运行机制和常见故障场景整理而成: 一、GC相关暂停 1. 安全点(Safepoint)阻塞 现象:JVM暂停但无GC日志,日志显示No GCs detected。原因:JVM等待所有线程进入安全点(如…...
是否存在路径(FIFOBB算法)
题目描述 一个具有 n 个顶点e条边的无向图,该图顶点的编号依次为0到n-1且不存在顶点与自身相连的边。请使用FIFOBB算法编写程序,确定是否存在从顶点 source到顶点 destination的路径。 输入 第一行两个整数,分别表示n 和 e 的值(1…...
在Ubuntu24上采用Wine打开SourceInsight
1. 安装wine sudo apt install wine 2. 安装32位库支持,SourceInsight是32位程序 sudo dpkg --add-architecture i386 sudo apt update sudo apt install wine32:i386 3. 验证安装 wine --version 4. 安装必要的字体和库(解决显示问题) sudo apt install fonts-wqy…...
Mysql中select查询语句的执行过程
目录 1、介绍 1.1、组件介绍 1.2、Sql执行顺序 2、执行流程 2.1. 连接与认证 2.2. 查询缓存 2.3. 语法解析(Parser) 2.4、执行sql 1. 预处理(Preprocessor) 2. 查询优化器(Optimizer) 3. 执行器…...
