【设计模式-访问者模式】
定义
访问者模式(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 …...

IDEA运行Tomcat出现乱码问题解决汇总
最近正值期末周,有很多同学在写期末Java web作业时,运行tomcat出现乱码问题,经过多次解决与研究,我做了如下整理: 原因: IDEA本身编码与tomcat的编码与Windows编码不同导致,Windows 系统控制台…...

【OSG学习笔记】Day 18: 碰撞检测与物理交互
物理引擎(Physics Engine) 物理引擎 是一种通过计算机模拟物理规律(如力学、碰撞、重力、流体动力学等)的软件工具或库。 它的核心目标是在虚拟环境中逼真地模拟物体的运动和交互,广泛应用于 游戏开发、动画制作、虚…...

突破不可导策略的训练难题:零阶优化与强化学习的深度嵌合
强化学习(Reinforcement Learning, RL)是工业领域智能控制的重要方法。它的基本原理是将最优控制问题建模为马尔可夫决策过程,然后使用强化学习的Actor-Critic机制(中文译作“知行互动”机制),逐步迭代求解…...
k8s从入门到放弃之Ingress七层负载
k8s从入门到放弃之Ingress七层负载 在Kubernetes(简称K8s)中,Ingress是一个API对象,它允许你定义如何从集群外部访问集群内部的服务。Ingress可以提供负载均衡、SSL终结和基于名称的虚拟主机等功能。通过Ingress,你可…...
1688商品列表API与其他数据源的对接思路
将1688商品列表API与其他数据源对接时,需结合业务场景设计数据流转链路,重点关注数据格式兼容性、接口调用频率控制及数据一致性维护。以下是具体对接思路及关键技术点: 一、核心对接场景与目标 商品数据同步 场景:将1688商品信息…...

el-switch文字内置
el-switch文字内置 效果 vue <div style"color:#ffffff;font-size:14px;float:left;margin-bottom:5px;margin-right:5px;">自动加载</div> <el-switch v-model"value" active-color"#3E99FB" inactive-color"#DCDFE6"…...
Java数值运算常见陷阱与规避方法
整数除法中的舍入问题 问题现象 当开发者预期进行浮点除法却误用整数除法时,会出现小数部分被截断的情况。典型错误模式如下: void process(int value) {double half = value / 2; // 整数除法导致截断// 使用half变量 }此时...

逻辑回归暴力训练预测金融欺诈
简述 「使用逻辑回归暴力预测金融欺诈,并不断增加特征维度持续测试」的做法,体现了一种逐步建模与迭代验证的实验思路,在金融欺诈检测中非常有价值,本文作为一篇回顾性记录了早年间公司给某行做反欺诈预测用到的技术和思路。百度…...

Golang——9、反射和文件操作
反射和文件操作 1、反射1.1、reflect.TypeOf()获取任意值的类型对象1.2、reflect.ValueOf()1.3、结构体反射 2、文件操作2.1、os.Open()打开文件2.2、方式一:使用Read()读取文件2.3、方式二:bufio读取文件2.4、方式三:os.ReadFile读取2.5、写…...
怎么让Comfyui导出的图像不包含工作流信息,
为了数据安全,让Comfyui导出的图像不包含工作流信息,导出的图像就不会拖到comfyui中加载出来工作流。 ComfyUI的目录下node.py 直接移除 pnginfo(推荐) 在 save_images 方法中,删除或注释掉所有与 metadata …...