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

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

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

 

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/7033.shtml

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

相关文章

SpringBoot自动连接数据库的解决方案

在一次学习设计模式的时候&#xff0c;沿用一个旧的boot项目&#xff0c;想着简单&#xff0c;就把数据库给关掉了&#xff0c;结果报错 Consider the following: If you want an embedded database (H2, HSQL or Derby), please put it on the classpath. 没有数据库的需…

一款开源的原神工具箱,专为现代化 Windows 平台设计,旨在改善桌面端玩家的游戏体验

Snap.Hutao 胡桃工具箱是一款以 MIT 协议开源的原神工具箱&#xff0c;专为现代化 Windows 平台设计&#xff0c;旨在改善桌面端玩家的游戏体验。通过将既有的官方资源与开发团队设计的全新功能相结合&#xff0c;提供了一套完整且实用的工具集&#xff0c;且无需依赖任何移动设…

ICode国际青少年编程竞赛- Python-1级训练场-变量入门

ICode国际青少年编程竞赛- Python-1级训练场-变量入门 1、 a 4 Dev.turnRight() Dev.step(a)2、 a 4 Spaceship.step(a) Dev.step(a)3、 a 4 Dev.step(a) Dev.turnLeft() Dev.step(a)4、 a 5 Dev.step(a) Spaceship.step(a) Dev.step(a)5、 a 3 Dev.step(a) Dev.tur…

查看编译库的使用的gcc版本

strings libtlsdk.a | grep GCC这个命令是用来查看静态库&#xff08;在这里是libtlsdk.a&#xff09;中包含的字符串&#xff0c;并从中筛选出包含GCC的行。 具体来说&#xff1a; strings命令用于从二进制文件中提取出可打印的字符串。在这个命令中&#xff0c;它被用来从l…

【如此简单!数据库入门系列】之存储设备简介

文章目录 1 前言2 存储设备分类3 主存层次结构4 磁盘结构5 RAID6 总结7 系列文章 1 前言 没有存储&#xff0c;就没有数据&#xff01; 如果说ER模型和数据库规范化是数据库概念模式的技术和方法&#xff0c;那么存储设备就是数据库物理模式的基础。 物理存储设备包含哪些类型…

风扇开启执行逻辑

执行流程 public static void businessExecutionWork(){//以下为业务逻辑部分System.out.println("1、根据电池包控制风扇服务执行 开始!");//1、获取电池包电压、电流、环境温度//获取电池包电压、电流、环境温度ObtainBatteryDataService obtainBatteryDataServic…

【目标检测】Deformable DETR

一、前言 论文&#xff1a; Deformable DETR: Deformable Transformers for End-to-End Object Detection 作者&#xff1a; SenseTime Research 代码&#xff1a; Deformable DETR 特点&#xff1a; 提出多尺度可变形注意力 (Multi-scale Deformable Attention) 解决DETR收敛…

柯桥西语培训之在西班牙旅游点菜哪些坑不能踩?

Por muy bien que se coma en Espaa —que es mucho— hay una cosa innegable: lo que pasa en la cocina se queda en la cocina. No todos los alimentos son igualmente seguros o sabrosos cuando se encuentran fuera de la comodidad de nuestra propia casa. Ya sea po…

数据库大作业——基于qt开发的图书管理系统 (一)环境的配置与项目需求的分析

前言 博主最近数据库原理结课要做课程设计了,要求开发基于数据库实现的图书管理系统&#xff0c;博主想了想决定做一个基于Qt的图书管理系统,博主在此之前其实也没有用过多少Qt&#xff0c;仅以此专栏记录博主学习与开发的全过程&#xff0c;大家一起学习&#xff0c;一起进步…

DS二叉搜索树

前言 我们在数据结构初阶专栏已经对二叉树进行了介绍并用C语言做了实现&#xff0c;但是当时没有对二叉搜树进行介绍&#xff0c;而是把他放到数据结构进阶构专栏的第一期来介绍&#xff0c;原因是后面的map和set&#xff08;红黑树&#xff09;是基于搜索树的&#xff0c;这里…

Shell脚本编写-定时清空文件内容,定时记录文件内容大小

find命令 – 根据路径和条件搜索指定文件 – Linux命令大全(手册)find命令的功能是根据给定的路径和条件查找相关文件或目录&#xff0c;其参数灵活方便&#xff0c;且支持正则表达式&#xff0c;结合管道符后能够实现更加复杂的功能&#xff0c;是Linux系统运维人员必须掌握的…

学习Rust的第29天: cat in Rust

今天即将是这个系列的最后一次内容&#xff0c;我们正在catRust 中从 GNU 核心实用程序进行重建。cat用于将文件内容打印到STDOUT.听起来很容易构建&#xff0c;所以让我们开始吧。 GitHub 存储库&#xff1a;GitHub - shafinmurani/gnu-core-utils-rust 伪代码 function read(…

省公派出国|社科类普通高校教师限期内赴英国访学交流

在国外访问学者申请中&#xff0c;人文社科类相对难度更大&#xff0c;尤其是英语语言学&#xff0c;作为非母语研究并不被国外高校看重。经过努力&#xff0c;最终我们帮助Z老师申请到英国坎特伯雷基督教会大学的访学职位&#xff0c;并在限期内出国。 Z老师背景&#xff1a; …

TypeScript学习日志-第二十天(模块解析)

模块解析 一、ES6之前的模块规范 前端模块化规范是有很多的&#xff0c;在es6模块化规范之前分别有一下的模块化规范 一、Commonjs 这是 NodeJs 里面的模块化规范 // 导入 require("xxx"); require("../xxx.js"); // 导出 exports.xxxxxx function() …

Java 【数据结构】常见排序算法实用详解(上) 插入排序/希尔排序/选择排序/堆排序【贤者的庇护】

登神长阶 上古神器-常见排序算法 插入排序/选择排序/堆排序 &#x1f4d4; 一.排序算法 &#x1f4d5;1.排序的概念 排序 &#xff1a;所谓排序&#xff0c;就是使一串记录&#xff0c;按照其中的某个或某些关键字的大小&#xff0c;递增或递减的排列起来的操作。 稳定性&a…

数据结构===树

文章目录 概要概念相关概念 有哪些常用的树小结 概要 树是一种新的数据结构&#xff0c;不同于数组&#xff0c;链表。就像大自然中的树&#xff0c;看下这个数据结构&#xff0c;很有意思&#xff0c;有一个主干&#xff0c;然后还有很多树叉&#xff0c;即支干。不错&#xf…

微信视频号如何变现呢,视频号涨粉最快方法

今天给大家带来的是视频号分成计划 视频号流量主这个项目&#xff0c;可以说这是目前的一个蓝海赛道&#xff0c;做的人也少&#xff0c;外面开的培训也很少&#xff0c;作为副业还是比较适合个人的&#xff0c;如果想批量操作这个项目&#xff0c;也比较适合工作室的。而且这…

51-48 CVPR 2024 | Vlogger: make your dream a vlog 自编剧制作视频博客

24年1月&#xff0c;上海交大、上海人工智能实验室、中科院联合发布Vlogger&#xff1a;make your dream a vlog。该论文主要工作是生成超过5分钟的视频博客vlog。鉴于现有文本到视频T2V生成方法很难处理复杂的故事情节和多样化的场景&#xff0c;本文提出了一个名为Vlogger的通…

Ansible的安装与基础命令的使用

Ansible Ansible 是一个开源的自动化工具&#xff0c;用于配置管理、应用部署和任务自动化。它由 Michael DeHaan 于 2012 年创建&#xff0c;后来被 Red Hat 收购。Ansible 的设计理念是简单易用&#xff0c;不需要在受管节点上安装任何代理软件&#xff0c;它通过 SSH&#…

-LAW5556

1 SCHOOL OF LAW Module Code: LAW5556 Module title: Corporate Finance and Securities Law Provisional Assessed Essay – Semester 2 – 2023-2024 Submission Date: Thursday 6 th June 2024 Word Limit: 3,000 INSTRUCTIONS 1. The assessment will count for 1…