当前位置: 首页 > article >正文

行为型:访问者模式

目录

1、核心思想

2、实现方式

2.1 模式结构

2.2 实现案例

3、优缺点分析

4、适用场景


1、核心思想

目的:数据结构稳定的情况下,解决数据与算法的耦合问题。适用于对象结构稳定但需频繁扩展操作的场景。

实现:在访问数据时根据数据类型(重载)自动切换(双重分派)到对应的算法,实现数据的自动响应机制,并且确保算法的自由扩展。

核心:对重载方法与双派发方式的利用

  • 双重分派(Double Dispatch):通过两次方法调用(先接受访问者,再调用访问者的方法)实现动态绑定。

  • 解耦数据与操作:对象结构中的元素(如文档节点、抽象语法树节点)仅定义“接受访问者”的方法,具体操作由访问者实现。

举例

1> 超市对不同商品有不同的折扣力度和计价方式

2> 文档中有不同对象(文本、图片)转换成PDF或渲染到屏幕两种输出方式

2、实现方式

2.1 模式结构

五种核心角色:

  • Element(元素接口)​:被访问的数据元素接口,定义一个可以接待访问者的行为标准accept(Visitor visitor),且所有数据封装类需实现此接口,通常作为泛型并被包含在对象容器中。
  • ConcreteElement(元素实现)​:具体数据元素实现类,可以有多个实现,并且相对固定。其accept实现方法中调用访问者并将自己“this”传回(如 visitor.visit(this))。
  • Visitor(访问者接口)​:可以是接口或者抽象类,定义了一系列访问操作方法以处理所有数据元素,通常为同名的访问方法,并以数据元素类作为入参来确定哪个重载方法被调用。
  • ConcreteVisitor(访问者实现)​:访问者接口的实现类,可以有多个实现,每个访问者类都需实现所有数据元素类型的访问重载方法。
  • ObjectContainer(对象容器)​:包含所有可被访问的数据对象(元素)的容器--元素的集合(如列表、树),提供遍历元素的方法,供访问者访问。

2.2 实现案例

假设有一个文档对象结构,包含文本和图片元素,需要支持导出为PDF和渲染到屏幕两种操作:

//1、元素接口
interface DocumentElement {void accept(Visitor visitor);
}//2、元素实现
// 具体元素:文本
class TextElement implements DocumentElement {private String content;public TextElement(String content) {this.content = content;}public String getContent() { return content; }@Overridepublic void accept(Visitor visitor) {visitor.visit(this); // 调用访问者的visit(TextElement)方法}
}// 具体元素:图片
class ImageElement implements DocumentElement {private String path;public ImageElement(String path) {this.path = path;}public String getPath() { return path; }@Overridepublic void accept(Visitor visitor) {visitor.visit(this); // 调用访问者的visit(ImageElement)方法}
}//3、访问者接口
interface Visitor {void visit(TextElement text);void visit(ImageElement image);
}//4、访问者实现
// 具体访问者:导出为PDF
class ExportToPDFVisitor implements Visitor {@Overridepublic void visit(TextElement text) {System.out.println("导出文本内容到PDF: " + text.getContent());}@Overridepublic void visit(ImageElement image) {System.out.println("导出图片到PDF: " + image.getPath());}
}// 具体访问者:渲染到屏幕
class RenderVisitor implements Visitor {@Overridepublic void visit(TextElement text) {System.out.println("显示文本: " + text.getContent());}@Overridepublic void visit(ImageElement image) {System.out.println("显示图片: " + image.getPath());}
}//5、对象容器:文档对象
class Document {private List<DocumentElement> elements = new ArrayList<>();public void addElement(DocumentElement element) {elements.add(element);}// 允许访问者遍历所有元素public void accept(Visitor visitor) {for (DocumentElement element : elements) {element.accept(visitor);}}
}//6、客户端
public class Client {public static void main(String[] args) {Document doc = new Document();doc.addElement(new TextElement("Hello World"));doc.addElement(new ImageElement("photo.jpg"));// 导出为PDFVisitor exportVisitor = new ExportToPDFVisitor();doc.accept(exportVisitor);// 输出:// 导出文本内容到PDF: Hello World// 导出图片到PDF: photo.jpg// 渲染到屏幕Visitor renderVisitor = new RenderVisitor();doc.accept(renderVisitor);// 输出:// 显示文本: Hello World// 显示图片: photo.jpg}
}

3、优缺点分析

优点:

  • 开闭原则:新增操作(访问者)无需修改元素类。

  • 集中操作逻辑:将相关操作聚合到访问者中,便于维护。

  • 支持复杂操作:访问者可跨多个元素类实现全局逻辑(如统计文档字数)。

缺点:

  • 破坏封装性:访问者需访问元素的内部状态,可能导致元素暴露私有字段。

  • 元素类扩展困难:新增元素类需修改所有访问者接口及实现。

  • 复杂度高:双重分派机制理解成本较高,代码结构更复杂。

4、适用场景

  • 对象结构稳定但操作多变

    • 如编译器中的抽象语法树(AST)处理(类型检查、代码生成、格式化)。

  • 跨元素类的复杂操作

    • 如统计报表生成、文档格式转换。

  • 解耦数据与操作

    • 如GUI框架中,控件树支持多种事件处理逻辑。

相关文章:

行为型:访问者模式

目录 1、核心思想 2、实现方式 2.1 模式结构 2.2 实现案例 3、优缺点分析 4、适用场景 1、核心思想 目的&#xff1a;数据结构稳定的情况下&#xff0c;解决数据与算法的耦合问题。适用于对象结构稳定但需频繁扩展操作的场景。 实现&#xff1a;在访问数据时根据数据类…...

C++数据结构 : 哈希表的实现

C数据结构 &#xff1a; 哈希表的实现 目录 C数据结构 &#xff1a; 哈希表的实现引言1. 哈希概念1.1 直接定址法1.2 哈希冲突1.3 负载因子 2. 哈希函数2.1 除法散列法/除留余数法2.2 乘法散列法&#xff08;了解&#xff09;2.3 全域散列法&#xff08;了解&#xff09; 3. 处…...

抖音电商客户端一面面经

抖音电商客户端一面面经 时间&#xff1a; 25.05.30 岗位&#xff1a; 抖音电商客户端开发工程师 形式&#xff1a; 技术一面 刚刚结束了字节跳动抖音电商客户端开发工程师岗位的技术一面&#xff0c;整体感觉考察范围非常全面&#xff0c;涵盖了基础、项目、算法、系统设计等…...

JavaScript 在 AcroForm 中的广泛应用

在Adobe表单(特别是SAP Interactive Forms by Adobe)中使用JavaScript的各种技巧和方法,下面这些代码片段可以帮助开发者更高效地处理表单逻辑和交互。 1. 获取数据内容 从上下文结构中获取数据 var LV_DATA = xfa.resolveNode("$record.IM_TEST.FIELDNAME").val…...

Socket编程之TCP套件字

基于的TCP套件字编程流程 1. Socket套接字 Socket是一个编程接口&#xff08;网络编程接口&#xff09;&#xff0c;是一种特殊的文件描述符&#xff08;write/read&#xff09;。Socket并不 仅限于TCP/IP Socket独立于具体协议的编程接口&#xff0c;这个接口位于TCP/IP四层…...

AD9268、AD9643调试过程中遇到的问题

Ad9268芯片 AD9268是一款双通道、16位、80 MSPS/105 MSPS/125 MSPS模数转换器(ADC)。AD9268旨在支持要求高性能、低成本、小尺寸和多功能的通信应用。双通道ADC内核采用多级差分流水线架构&#xff0c;集成输出纠错逻辑。每个ADC都具有宽带宽、差分采样保持模拟输入放大器&…...

Java-File类基本方法使用指南

Java-File类基本方法使用指南 一、File类基础概念1.1 什么是File类1.2 File类的构造函数 二、文件和目录的创建与删除2.1 创建文件 - createNewFile()2.2 创建目录 - mkdir() 和 mkdirs()2.3 删除文件或目录 - delete() 三、文件和目录的查询与判断3.1 存在性判断 - exists()3.…...

Python爬虫实战:研究PyQuery库相关技术

1. 引言 1.1 研究背景与意义 随着互联网的快速发展,网络上的数据量呈爆炸式增长。如何高效地从海量的网页数据中提取有价值的信息,成为当前信息技术领域的一个重要研究方向。网络爬虫作为一种自动获取网页内容的程序,能够按照一定的规则,自动地抓取万维网信息,在搜索引擎…...

第九篇:MySQL 安全加固与访问控制策略实战

数据库的安全不仅仅是防止外部入侵&#xff0c;更包括合理配置账户权限、日志审计、网络加密、配置加固等。本文将系统性梳理 MySQL 的安全机制与实战加固方法&#xff0c;助你构建安全可靠的数据库运行环境。 一、数据库安全风险面 数据库常面临的威胁&#xff1a; 弱口令或默…...

神经网络-Day40

目录 单通道图片的规范写法图像任务中的张量形状NLP任务中的张量形状1. **Flatten操作**2. **view/reshape操作** 总结彩色图片的规范写法 图像数据的格式以及模型定义的过程&#xff0c;和之前结构化数据的略有不同&#xff0c;主要差异体现在2处 模型定义的时候需要展平图像由…...

WindowServer2022下docker方式安装dify步骤

WindowServer2022下docker方式安装dify步骤&#xff08;稳定后考虑部署至linux中&#xff09; 教程&#xff1a;https://blog.csdn.net/qq_49035156/article/details/143264534 0、资源要求 ---windows&#xff1a;8核CPU、16G内存、200G500G存储 ---10.21.31.122/administra…...

Java五种方法批量处理List元素全解

Java:如何优雅批量处理List中的每个元素 一、场景分析&#xff1a;为什么需要批量处理List&#xff1f;二、核心方法&#xff1a;五种实现方式对比2.1 普通for循环&#xff08;最直接的方式&#xff09;代码示例&#xff1a;优缺点&#xff1a; 2.2 Java 8 replaceAll&#xff…...

springboot文件上传下载

基于ResponseEntity的下载响应 SpringBoot中&#xff0c;ResponseEntity类型可以精确控制HTTP响应&#xff0c;为文件下载提供完善的HTTP头信息。 RestController RequestMapping("/api/download") public class FileDownloadController {GetMapping("/file/{…...

webpack CDN打包优化

CDN网络分发服务 请求资源时最近的服务器将缓存内容交给用户 体积较大且变动不多的文件存在CDN文件中 react react-dom资源 // 添加自定义对于webpack的配置const path require(path) const { whenProd, getPlugin, pluginByName } require(craco/craco)module.exports {//…...

ARM内核一览

经常看介绍某某牛批芯片用的又是ARM什么核&#xff0c;看的云里雾里&#xff0c;所以简单整理整理。&#xff08;内容来自官网和GPT&#xff09; 1 ARM 内核总体分类 系列特点应用场景Cortex-M超低功耗、低成本、实时性嵌入式系统、微控制器、IoTCortex-R高可靠性、硬实时汽车…...

Rust 和 Python 如何混合使用

Rust 与 Python 可以通过多种方式混合使用&#xff0c;如 FFI 接口、PyO3 库、CFFI、CPython API、wasm 模块嵌入等。这种混合开发模式可结合 Rust 的性能优势与 Python 的开发效率。其中&#xff0c;PyO3 是目前最受欢迎的桥接工具&#xff0c;它允许使用 Rust 编写 Python 扩…...

台式电脑CPU天梯图_2025年台式电脑CPU天梯图

CPU的选择绝对是重中之重,它关乎了一台电脑性能好坏。相信不少用户,在挑选CPU的时候不知道谁强谁弱,尤其是intel和AMD两款CPU之间。下面通过2025年台式电脑CPU天梯图来了解下这两款cpu. 2025年台式电脑CPU天梯图 2025年台式电脑CPU天梯图包含了老旧型号以及12代、13代、14代…...

2025年渗透测试面试题总结-匿名[校招]安全服务工程师(题目+回答)

安全领域各种资源&#xff0c;学习文档&#xff0c;以及工具分享、前沿信息分享、POC、EXP分享。不定期分享各种好玩的项目及好用的工具&#xff0c;欢迎关注。 目录 匿名[校招]安全服务工程师 一面问题与完整回答 1. 学校、专业、成绩与排名 2. 学习安全时长 3. 当前学习…...

Deseq2:MAG相对丰度差异检验

首先使用代码将contigs和MAG联系起来 https://github.com/MrOlm/drep/blob/master/helper_scripts/parse_stb.py ~/parse_stb.py --reverse -f ~/bin_dir/* -o ~/bin_dir/genomes.stb # 查看第一列的contigs有没有重复&#xff08;重复的话会影响后续比对&#xff09; awk {p…...

CTFHub-RCE 命令注入-过滤目录分隔符

观察源代码 代码里面可以发现过滤了目录分隔符\和/ 判断是Windows还是Linux 源代码中有 ping -c 4 说明是Linux 查看有哪些文件 127.0.0.1|ls 打开flag文件 发现存在一个flag_is_here的文件夹&#xff0c;我们需要打开这个文件夹找到目标文件我们尝试分步&#xff0c;先利…...

从零开始的数据结构教程(七) 回溯算法

&#x1f504; 标题一&#xff1a;回溯核心思想——走迷宫时的“穷举回头”策略 回溯算法 (Backtracking) 是一种通过探索所有可能的候选解来找出所有的解或某些解的算法。它就像你在一个复杂的迷宫中寻找出路&#xff1a;当你遇到一个岔路口时&#xff0c;你会选择一条路继续…...

CentOS-stream-9 Zabbix的安装与配置

一、Web环境搭建部署Zabbix时&#xff0c;选择合适的MariaDB、PHP和Nginx版本非常重要&#xff0c;以确保兼容性和最佳性能。以下是建议版本&#xff1a;Zabbix 6.4 MariaDB&#xff1a;官方文档推荐使用MariaDB 10.3或更高版本。对于CentOS Stream 9&#xff0c;建议使用Maria…...

开源是什么?我们为什么要开源?

本片为故事类文章推荐听音频哦 软件自由运动的背景 梦开始的地方 20世纪70年代&#xff0c;软件行业处于早期发展阶段&#xff0c;软件通常与硬件捆绑销售&#xff0c;用户对软件的使用、修改和分发权利非常有限。随着计算机技术的发展和互联网的普及&#xff0c;越来越多的开…...

【unity游戏开发——编辑器扩展】EditorApplication公共类处理编辑器生命周期事件、播放模式控制以及各种编辑器状态查询

注意&#xff1a;考虑到编辑器扩展的内容比较多&#xff0c;我将编辑器扩展的内容分开&#xff0c;并全部整合放在【unity游戏开发——编辑器扩展】专栏里&#xff0c;感兴趣的小伙伴可以前往逐一查看学习。 文章目录 前言一、监听编辑器事件1、常用编辑器事件2、示例监听播放模…...

elasticsearch低频字段优化

在Elasticsearch中&#xff0c;通过设置"index": false关闭低频字段的倒排索引构建是常见的优化手段&#xff0c;以下是关键要点&#xff1a; 一、核心机制 ‌倒排索引禁用‌ 设置index: false后&#xff0c;字段不会生成倒排索引&#xff0c;无法通过常规查…...

React---day3

React 2.5 jsx的本质 jsx 仅仅只是 React.createElement(component, props, …children) 函数的语法糖。所有的jsx最终都会被转换成React.createElement的函数调用。 createElement需要传递三个参数&#xff1a; 参数一&#xff1a;type 当前ReactElement的类型&#xff1b;…...

PyCharm接入DeepSeek,实现高效AI编程

介绍本土AI工具DeepSeek如何结合PyCharm同样实现该功能。 一 DeepSeek API申请 首先进入DeepSeek官网&#xff1a;DeepSeek 官网 接着点击右上角的 “API 开放平台“ 然后点击API keys 创建好的API key&#xff0c;记得复制保存好 二 pycharm 接入deepseek 首先打开PyCh…...

前端面经 get和post区别

get获取数据 post提交资源&#xff0c;引起服务器状态变化或者副作用 区别 1get会比post更不安全 get参数写在url中 post在请求体内 2get报文 head和body一起发 响应200 post报文 先发head 100 再发 body 200 3 get请求url有长度限制 4 默认缓存get 请求...

CTFSHOW-WEB-36D杯

给你shell 这道题对我这个新手还是有难度的&#xff0c;花了不少时间。首先f12看源码&#xff0c;看到?view_source&#xff0c;点进去看源码 <?php //Its no need to use scanner. Of course if you want, but u will find nothing. error_reporting(0); include "…...

MySQL connection close 后, mysql server上的行为是什么

本文着重讲述的是通过 msql client 连接到 mysql server &#xff0c;发起 update 、 select 操作(由于数据量非常大&#xff0c;所以 update、select 操作都很耗时&#xff0c;即在结果返回前我们有足够的时间执行一些操作) 。 在客户端分别尝试执行 ctrl C 结束关闭 mysql c…...