行为型:访问者模式

news2025/6/3 8:39:51

目录

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; }

    @Override
    public 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; }

    @Override
    public 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 {
    @Override
    public void visit(TextElement text) {
        System.out.println("导出文本内容到PDF: " + text.getContent());
    }

    @Override
    public void visit(ImageElement image) {
        System.out.println("导出图片到PDF: " + image.getPath());
    }
}

// 具体访问者:渲染到屏幕
class RenderVisitor implements Visitor {
    @Override
    public void visit(TextElement text) {
        System.out.println("显示文本: " + text.getContent());
    }

    @Override
    public 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"));

        // 导出为PDF
        Visitor 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.coloradmin.cn/o/2395077.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

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

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

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

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

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;先利…

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、示例监听播放模…

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…

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 "…

RabbitMQ vs MQTT:深入比较与最新发展

RabbitMQ vs MQTT&#xff1a;深入比较与最新发展 引言 在消息队列和物联网&#xff08;IoT&#xff09;通信领域&#xff0c;RabbitMQ 和 MQTT 是两种备受瞩目的技术&#xff0c;各自针对不同的需求和场景提供了强大的解决方案。随着 2025 年的到来&#xff0c;这两项技术都…

金砖国家人工智能高级别论坛在巴西召开,华院计算应邀出席并发表主题演讲

当地时间5月20日&#xff0c;由中华人民共和国工业和信息化部&#xff0c;巴西发展、工业、贸易与服务部&#xff0c;巴西公共服务管理和创新部以及巴西科技创新部联合举办的金砖国家人工智能高级别论坛&#xff0c;在巴西首都巴西利亚举行。 中华人民共和国工业和信息化部副部…

【KWDB 创作者计划】_再热垃圾发电汽轮机仿真与监控系统:KaiwuDB 批量插入10万条数据性能优化实践

再热垃圾发电汽轮机仿真与监控系统&#xff1a;KaiwuDB 批量插入10万条数据性能优化实践 我是一台N25-3.82/390型汽轮机&#xff0c;心脏在5500转/分的轰鸣中跳动。垃圾焚烧炉是我的胃&#xff0c;将人类遗弃的残渣转化为金色蒸汽&#xff0c;沿管道涌入我的胸腔。 清晨&#x…

Android第十一次面试多线程篇

​面试官​&#xff1a; “你在项目里用过Handler吗&#xff1f;能说说它是怎么工作的吗&#xff1f;” ​候选人​&#xff1a; “当然用过&#xff01;比如之前做下载功能时&#xff0c;需要在后台线程下载文件&#xff0c;然后在主线程更新进度条。这时候就得用Handler来切…

安全,稳定可靠的政企即时通讯数字化平台

在当今数字化时代&#xff0c;政企机构面临着复杂多变的业务需求和日益增长的沟通协作挑战。BeeWorks作为一款安全&#xff0c;稳定可靠的政企即时通讯数字化平台&#xff0c;凭借其安全可靠、功能强大的特性&#xff0c;为政企提供了高效、便捷的沟通协作解决方案&#xff0c;…