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

java设计模式六 访问者

访问者模式(Visitor Pattern)是一种设计模式,它允许你将算法附加到对象结构中的各个元素上,而不必修改对象结构本身。它主要用于处理对象结构非常稳定,但频繁需要在此结构上执行不同操作的场景。访问者模式通过将操作移动到一个访问者对象中,来保持元素对象的类结构不变。

角色

  1. 元素(Element):定义一个接受访问者对象的接口。
  2. 具体元素(Concrete Element):实现元素接口,存储该元素的信息。
  3. 访问者(Visitor):定义一个访问元素的接口,每个元素类都有一个对应的访问方法。
  4. 具体访问者(Concrete Visitor):实现访问者接口,存储访问元素时的状态,并定义元素访问的操作。

案例分析

假设我们有一个表示文档的结构,文档中包含不同类型的内容,比如文本段落和图片。我们希望对这些内容执行不同的操作,比如计算总字数或者显示内容,而不修改现有的文档结构。

Java实现

首先,我们定义元素接口和具体元素:

// 元素接口
public interface DocumentElement {void accept(Visitor visitor);
}// 具体元素:文本段落
public class TextElement implements DocumentElement {private String content;public TextElement(String content) {this.content = content;}@Overridepublic void accept(Visitor visitor) {visitor.visit(this);}public String getContent() {return content;}
}// 具体元素:图片
public class ImageElement implements DocumentElement {private String url;public ImageElement(String url) {this.url = url;}@Overridepublic void accept(Visitor visitor) {visitor.visit(this);}public String getUrl() {return url;}
}

然后,我们定义访问者接口和具体访问者:

// 访问者接口
public interface Visitor {void visit(TextElement textElement);void visit(ImageElement imageElement);
}// 具体访问者:计算总字数
public class WordCountVisitor implements Visitor {private int wordCount;public WordCountVisitor() {wordCount = 0;}@Overridepublic void visit(TextElement textElement) {String[] words = textElement.getContent().split("\\s+");wordCount += words.length;}@Overridepublic void visit(ImageElement imageElement) {// 图片不计字数}public int getWordCount() {return wordCount;}
}// 具体访问者:显示内容
public class DisplayVisitor implements Visitor {@Overridepublic void visit(TextElement textElement) {System.out.println("Text: " + textElement.getContent());}@Overridepublic void visit(ImageElement imageElement) {System.out.println("Image: " + imageElement.getUrl());}
}

最后,我们使用访问者模式:

public class Document {private List<DocumentElement> elements = new ArrayList<>();public void addElement(DocumentElement element) {elements.add(element);}public void displayAll() {for (DocumentElement element : elements) {element.accept(new DisplayVisitor());}}public int getWordCount() {return new WordCountVisitor().visitAll(elements);}private int visitAll(List<DocumentElement> elements, Visitor visitor) {for (DocumentElement element : elements) {element.accept(visitor);}return 0; // 实际上,我们需要一个方法来累加计算结果}public static void main(String[] args) {Document document = new Document();document.addElement(new TextElement("Hello, World!"));document.addElement(new ImageElement("http://example.com/image.png"));document.addElement(new TextElement("This is a test document."));System.out.println("Displaying all elements:");document.displayAll();System.out.println("Total word count: " + document.getWordCount());}
}

注意事项

  • 访问者模式使得增加新元素很容易,但增加新操作却需要修改所有的元素类,因此需要谨慎使用。
  • 访问者模式破坏了封装,因为元素需要接受访问者,暴露内部信息。
  • 访问者模式通常用于那些对象结构相对稳定,但经常需要在此结构上执行各种不同操作的场景。

通过上述案例分析,我们可以看到访问者模式如何在不改变现有对象结构的情况下,向对象添加新的操作。这种模式在某些特定场景下非常有用,但也需要考虑到其对封装性和扩展性的影响。

在上一个回答中,我们已经实现了访问者模式的一个基本例子,包括定义元素和访问者接口、具体实现以及如何在文档结构中应用访问者模式。接下来,我将提供一些额外的思考点和可能的改进方向。

改进方向

  1. 增加灵活性:考虑将访问者模式与命令模式结合使用,以提供更多的灵活性和可扩展性。

  2. 异步处理:如果访问操作非常耗时,可以考虑实现异步处理。

  3. 性能优化:在某些情况下,访问者模式可能会对性能产生影响,特别是当文档结构非常庞大时。需要考虑如何优化性能。

  4. 错误处理:在访问者模式中,错误处理非常重要。需要考虑如何处理访问过程中可能出现的异常。

  5. 访问者模式的变体:根据具体需求,可以考虑使用访问者模式的变体,如对称访问者模式或反向访问者模式。

访问者模式的变体

  1. 对称访问者模式:在这种变体中,访问者和元素是对称的,即访问者和元素都实现了相同的接口。这可以简化代码,但也牺牲了一些灵活性。

  2. 反向访问者模式:在这种变体中,元素对象访问访问者对象,而不是访问者访问元素。这在某些情况下可能更自然,但需要重新设计对象结构。

改进后的访问者模式实现

让我们对访问者模式实现进行一些改进,使其更加灵活和健壮:

public interface Visitor {void visitConcreteElementA(ConcreteElementA element);void visitConcreteElementB(ConcreteElementB element);// 可以添加更多的visit方法
}public class ConcreteElementA implements Element {@Overridepublic void accept(Visitor visitor) {visitor.visitConcreteElementA(this);}// 其他具体元素的方法
}public class ConcreteElementB implements Element {@Overridepublic void accept(Visitor visitor) {visitor.visitConcreteElementB(this);}// 其他具体元素的方法
}public class ConcreteVisitor1 implements Visitor {@Overridepublic void visitConcreteElementA(ConcreteElementA element) {// 处理ConcreteElementA}@Overridepublic void visitConcreteElementB(ConcreteElementB element) {// 处理ConcreteElementB}// 可以添加更多的visit方法
}public class ConcreteVisitor2 implements Visitor {@Overridepublic void visitConcreteElementA(ConcreteElementA element) {// 另一种处理ConcreteElementA的方式}@Overridepublic void visitConcreteElementB(ConcreteElementB element) {// 另一种处理ConcreteElementB的方式}// 可以添加更多的visit方法
}public class ObjectStructure {private List<Element> elements = new ArrayList<>();public void addElement(Element element) {elements.add(element);}public void operate(Visitor visitor) {for (Element element : elements) {element.accept(visitor);}}
}

使用改进后的访问者模式

public class Client {public static void main(String[] args) {ObjectStructure objectStructure = new ObjectStructure();objectStructure.addElement(new ConcreteElementA());objectStructure.addElement(new ConcreteElementB());System.out.println("Operation 1:");objectStructure.operate(new ConcreteVisitor1());System.out.println("Operation 2:");objectStructure.operate(new ConcreteVisitor2());}
}

在这个改进的例子中,我们为访问者模式增加了更多的灵活性,允许根据不同的访问者实现不同的操作。同时,我们也提供了更多的扩展点,以便于在不修改现有结构的情况下添加新的操作。

通过这些改进,访问者模式变得更加健壮和易于使用。它不仅提供了更高的灵活性,还提高了代码的可维护性和可读性。在实际应用中,根据具体需求,还可以继续对访问者模式进行定制和优化。

 

 

相关文章:

java设计模式六 访问者

访问者模式&#xff08;Visitor Pattern&#xff09;是一种设计模式&#xff0c;它允许你将算法附加到对象结构中的各个元素上&#xff0c;而不必修改对象结构本身。它主要用于处理对象结构非常稳定&#xff0c;但频繁需要在此结构上执行不同操作的场景。访问者模式通过将操作移…...

中间件研发之Springboot自定义starter

Spring Boot Starter是一种简化Spring Boot应用开发的机制&#xff0c;它可以通过引入一些预定义的依赖和配置&#xff0c;让我们快速地集成某些功能模块&#xff0c;而无需繁琐地编写代码和配置文件。Spring Boot官方提供了很多常用的Starter&#xff0c;例如spring-boot-star…...

libcity笔记:添加新模型(以RNN.py为例)

创建的新模型应该继承AbstractModel或AbstractTrafficStateModel 交通状态预测任务——>继承 AbstractTrafficStateModel类轨迹位置预测任务——>继承AbstractModel类 1 AbstractTrafficStateModel 2 RNN 2.1 构造函数 2.2 predict 2.3 calculate_loss...

Ansible---自动化运维工具

一、Ansible概述 1.1 Ansible简介 Ansible是一款自动化运维工具&#xff0c;通过ssh对目标主机进行配置、应用部署、任务执行、编排调度等操作。它简化了复杂的环境管理和自动化任务&#xff0c;提高了工作效率和一致性&#xff0c;同时&#xff0c;Ansible的剧本(playbooks)…...

5.Git

Git是一个分布式版本控制工具&#xff0c;主要用于管理开发过程中的源代码文件&#xff08;Java类、xml文件、html文件等&#xff09;。通过Git仓库来存储和管理这些文件&#xff0c;Git仓库分为两种 本地仓库&#xff1a;开发人员自己电脑上的Git仓库远程仓库&#xff1a;远程…...

探索中位数快速排序算法:高效寻找数据集的中间值

在计算机科学领域&#xff0c;寻找数据集的中位数是一个常见而重要的问题。而快速排序算法作为一种高效的排序算法&#xff0c;可以被巧妙地利用来解决中位数查找的问题。本文将深入探讨中位数快速排序算法的原理、实现方法以及应用场景&#xff0c;带你领略这一寻找中间值的高…...

密码学《图解密码技术》 记录学习 第十五章

目录 十五章 15.1本章学习的内容 15.2 密码技术小结 15.2.1 密码学家的工具箱 15.2.2 密码与认证 15.2.3 密码技术的框架化 15.2.4 密码技术与压缩技术 15.3 虚拟货币——比特币 15.3.1 什么是比特币 15.3.2 P2P 网络 15.3.3地址 15.3.4 钱包 15.3.5 区块链 15.3.…...

如何在 Ubuntu 16.04 上为 Nginx 创建自签名 SSL 证书

简介 TLS&#xff0c;即传输层安全协议&#xff0c;及其前身SSL&#xff0c;即安全套接字层&#xff0c;是用于将普通流量包装在受保护的加密包装中的网络协议。 使用这项技术&#xff0c;服务器可以在服务器和客户端之间安全地发送流量&#xff0c;而不会被外部方拦截。证书…...

5.协议的编解码

本章内容其实没有多大难度&#xff0c;主要考察大家的细心程度.计算数据长度然后截取相应字节数组并按照协议进行解码&#xff0c;编码则反之。 1.基础消息的编解码 Override public BasicMessage decode(byte[] bytes) {int dataLength ByteUtil.bytesToInt(ByteUtil.extra…...

数据结构基础| 线性表

线性表 定义 没有元素则为空表 例子: 稀疏多项式的运算 图书信息管理系统 特点 线性结构 同类型 线性表的类型定义 1.基本操作: InitList(&L) 操作结果:构造空的线性表L DestroyList(&L) 初始化条件:线性表L存在 操作结果:销毁线性表L(线性表L不存在) Cle…...

嵌入式学习

笔记 作业 有如下结构体 struct Student{ char name[16]; int age; double math_score; double chinese_score; double english_score; double physics_score; double chemistry…...

sass-loader和node-sass与node版本的依赖问题

sass-loader和node-sass与node版本的依赖问题 没有人会陪你走到最后&#xff0c;碰到了便是有缘&#xff0c;即使到了要下车的时候&#xff0c;也要心存感激地告别&#xff0c;在心里留下空白的一隅之地&#xff0c;多年后想起时依然心存甘味。——林清玄 报错截图 报错信息 np…...

基于BP神经网络的QPSK解调算法matlab性能仿真

目录 1.算法运行效果图预览 2.算法运行软件版本 3.部分核心程序 4.算法理论概述 5.算法完整程序工程 1.算法运行效果图预览 2.算法运行软件版本 matlab2022a 3.部分核心程序 ........................................................................ for ij 1:leng…...

Linux服务器常用巡检命令

在Linux服务器上进行常规巡检是确保服务器稳定性和安全性的重要措施之一。以下是一些常用的巡检命令和技巧&#xff1a; 1. 查看系统信息 1.1 系统信息显示 命令&#xff1a;uname -a ​​​​ [rootlinux100 ~]# uname -a Linux linux100 4.15.0-70-generic #79-Ubuntu SMP…...

VSCode 配置 CMake

VSCode 配置 C/C 环境的详细过程可参考&#xff1a;VSCode 配置 C/C 环境 1 配置C/C编译环境 如果是 Windows 环境&#xff0c;需要安装 MingW。 方案一 可以去官网(https://sourceforge.net/projects/mingw-w64/)下载安装包。 注意安装路径不要出现中文。 打开 windows she…...

​《MATLAB科研绘图与学术图表绘制从入门到精通》示例:绘制德国每日风能和太阳能产量3D线图

在MATLAB中&#xff0c;要绘制3D线图&#xff0c;可以使用 plot3 函数。 在《MATLAB科研绘图与学术图表绘制从入门到精通》书中通过绘制德国每日风能和太阳能产量3D线图解释了如何在MATLAB中绘制3D线图。 购书地址&#xff1a;https://item.jd.com/14102657.html...

【信息系统项目管理师知识点速记】质量管理:控制质量

控制质量是为了评估绩效,确保项目输出完整、正确且满足客户期望,而监督和记录质量管理活动执行结果的过程。控制质量过程需要在整个项目期间开展,其目的是测量产品或服务的完整性、合规性和适用性,以确保项目达到主要干系人的质量要求。 12.5.1 输入 项目管理计划 质量管理…...

【云原生】Pod 的生命周期(一)

【云原生】Pod 的生命周期&#xff08;一&#xff09;【云原生】Pod 的生命周期&#xff08;二&#xff09; Pod 的生命周期&#xff08;一&#xff09; 1.Pod 生命期2.Pod 阶段3.容器状态3.1 Waiting &#xff08;等待&#xff09;3.2 Running&#xff08;运行中&#xff09;3…...

Golang | Leetcode Golang题解之第71题简化路径

题目&#xff1a; 题解&#xff1a; func simplifyPath(path string) string {stack : []string{}for _, name : range strings.Split(path, "/") {if name ".." {if len(stack) > 0 {stack stack[:len(stack)-1]}} else if name ! "" &am…...

Unreal游戏GPU性能优化检测模式全新上线

UWA已经在去年推出了针对于Unity项目的GPU性能优化工具&#xff0c;通过对GPU渲染性能、带宽性能以及各种下探指标&#xff0c;帮助Unity项目研发团队定位由GPU导致的发热耗电问题。这个需求在Unreal团队中也极为强烈&#xff0c;因此UWA将该功能移植到针对Unreal项目的GOT Onl…...

设计网页用什么软件

在设计网页时&#xff0c;可以使用多种软件来完成不同的任务。以下是一些常用的网页设计软件&#xff0c;以及它们的特点和用途。 1. Adobe Photoshop&#xff1a; Adobe Photoshop 是一款功能强大的图像编辑软件。在网页设计中&#xff0c;它常用于创建和编辑网页所需的图像、…...

⑪ - 测试工程师通识指南

📖 该文隶属 程序员:职场关键角色通识宝典✍️ 作者:哈哥撩编程(视频号同名) 博客专家全国博客之星第四名超级个体COC上海社区主理人特约讲师谷歌亚马逊演讲嘉宾科技博主极星会首批签约作者🏆 推荐专栏: 🏅 程序员:职场关键角色通识宝典🏅...

RabbitMQ知识点总结和复习

之前项目中用到RabbitMQ的场景主要是订单信息的传递&#xff0c;还有就是利用RabbitMQ的死信队列属性设置&#xff0c;实现延迟队列效果&#xff0c;实现超时支付取消功能&#xff0c;以及在两个不同项目中传递数据等场景。 最近几年的工作中都是一直用的RabbitMQ&#xff0c;…...

ContEA阅读笔记

Facing Changes: Continual Entity Alignment for Growing Knowledge Graphs 面对变化&#xff1a;不断增长的知识图谱的持续实体对齐 Abstract 实体对齐是知识图谱(KG)集成中一项基本且重要的技术。多年来&#xff0c;实体对齐的研究一直基于知识图谱是静态的假设&#xff…...

使用nvm切换nodejs版本

查看可以安装的版本&#xff1a; 使用nvm list显示已安装的nodejs版本&#xff1a; 选择一个版本下载&#xff1a; 切换对应的版本&#xff1a;...

机器学习_KNN算法

机器学习_KNN算法 K-近邻&#xff08;K-Nearest Neighbors&#xff0c;简称KNN&#xff09;算法是一种基本的机器学习分类和回归算法 其核心思想是&#xff1a;如果一个样本在特征空间中的k个最相似&#xff08;即特征空间中最邻近&#xff09;的样本中的大多数属于某一个类别…...

学QT的第一天~

#include "mywidget.h" MyWidget::MyWidget(QWidget *parent) : QWidget(parent) { //窗口相关设置// this->resize(427,330); this->setFixedSize(427,330); //设置图标 this->setWindowIcon(QIcon("C:\\Users\\Admin\\Desktop\\pictrue\\dahz.jpg&q…...

《QT实用小工具·四十九》QT开发的轮播图

1、概述 源码放在文章末尾 该项目实现了界面轮播图的效果&#xff0c;包含如下特点&#xff1a; 左右轮播 鼠标悬浮切换&#xff0c;无需点击 自动定时轮播 自动裁剪和缩放不同尺寸图片 任意添加、插入、删除 单击事件&#xff0c;支持索引和自定义文本 界面美观&#xff0c;圆…...

uniapp 自定义 App启动图

由于uniapp默认的启动界面太过普通 所以需要自定义个启动图 普通的图片不可以过不了苹果的审核 所以使用storyboard启动图 生成 storyboard 的网站&#xff1a;初雪云-提供一站式App上传发布解决方案...

39-1 Web应用防火墙 - WAF应用程序层绕过

环境准备:构建完善的安全渗透测试环境:推荐工具、资源和下载链接_渗透测试靶机下载-CSDN博客 一、双重URL编码绕过 什么是URL编码 URL编码是一种将特殊字符转为%加上其ASCII值的方式,以确保在URL中传输时不会被误解或导致错误。例如,字母"s"的URL编码是"…...

做个素材网网站难做吗/福州整站优化

go run -gcflags -m -m -l main.g...

济宁官方网站/百度推广开户费

章春笋&#xff0c;现任华南师范大学生物光子学研究院副院长&#xff0c;研究员&#xff0c;博士生导师。研究方向&#xff1a;1. 基于布芯片的医疗仪器的研发与应用2. 科学分析仪器的开发与应用研究3. 微流控光学传感器及其生物医学应用拟招收2021年调剂生学硕和专硕若干名&am…...

浙江省网站重点学科建设/网站开发用什么语言

我保证这篇文章会给你一些不一样的东西&#xff0c;I promise. Docker大红大紫之时&#xff0c;我错过了什么&#xff0c;可能是因为我并没有必须使用Docker的动机&#xff0c;毕竟我不是编程者&#xff0c;我也不需要发布什么配置复杂的系统&#xff0c;我是一个典型的实用主义…...

装修网站大全/怎么做盲盒

NC52 有效括号序列 有效括号序列_牛客题霸_牛客网 (nowcoder.com) import java.util.*; public class Solution {public boolean isValid (String str) {Stack<Character> stnew Stack<>();//辅助栈for(int i0;i<str.length();i){if(str.charAt(i)(){st.push()…...

wordpress转程序/资源搜索器

MySQL HA方案之MySQL半复制MHAKeepalivedAtlasLVS 简介 目前Mysql高可用的方案有好多&#xff0c;比如MMM&#xff0c;heartbeatdrbd&#xff0c;Cluster等&#xff0c;还有percona的Galera Cluster等。这些高可用软件各有优劣。在进行高可用方案选择时&#xff0c;主要是看业务…...

网站备案的要求是什么/seo排名软件免费

SQL优化与诊断 Explain诊断 Explain各参数的含义如下&#xff1a; 列名说明id执行编号&#xff0c;标识select所属的行。如果在语句中没有子查询或关联查询&#xff0c;只有唯一的select&#xff0c;每行都将显示1.否则&#xff0c;内层的select语句一般会顺序编号&#xff0…...