当前位置: 首页 > 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框架中,控件树支持多种事件处理逻辑。

http://www.lryc.cn/news/2395077.html

相关文章:

  • C++数据结构 : 哈希表的实现
  • 抖音电商客户端一面面经
  • JavaScript 在 AcroForm 中的广泛应用
  • Socket编程之TCP套件字
  • AD9268、AD9643调试过程中遇到的问题
  • Java-File类基本方法使用指南
  • Python爬虫实战:研究PyQuery库相关技术
  • 第九篇:MySQL 安全加固与访问控制策略实战
  • 神经网络-Day40
  • WindowServer2022下docker方式安装dify步骤
  • Java五种方法批量处理List元素全解
  • springboot文件上传下载
  • webpack CDN打包优化
  • ARM内核一览
  • Rust 和 Python 如何混合使用
  • 台式电脑CPU天梯图_2025年台式电脑CPU天梯图
  • 2025年渗透测试面试题总结-匿名[校招]安全服务工程师(题目+回答)
  • Deseq2:MAG相对丰度差异检验
  • CTFHub-RCE 命令注入-过滤目录分隔符
  • 从零开始的数据结构教程(七) 回溯算法
  • CentOS-stream-9 Zabbix的安装与配置
  • 开源是什么?我们为什么要开源?
  • 【unity游戏开发——编辑器扩展】EditorApplication公共类处理编辑器生命周期事件、播放模式控制以及各种编辑器状态查询
  • elasticsearch低频字段优化
  • React---day3
  • PyCharm接入DeepSeek,实现高效AI编程
  • 前端面经 get和post区别
  • CTFSHOW-WEB-36D杯
  • MySQL connection close 后, mysql server上的行为是什么
  • RabbitMQ vs MQTT:深入比较与最新发展