访问者模式(Visitor)

访问者模式是一种行为设计模式,可封装一些作用于当前数据结构的各元素的操作,它可以在不改变数据结构的前提下定义作用于这些元素的新的操作。

Visitor is a behavior design pattern that encapsulates some operations that act on the elements of the current 
data structure. It can define new operations that act on these elements without changing the data structure.  

结构设计

访问者模式包含如下角色:
Visitor,访问者基类,声明了一系列以对象结构的具体元素为参数的访问者方法。这些方法的名称可能是相同的,但是其参数一定是不同的。
ConcreteVisitor,具体访问者,会为不同的具体元素类实现相同行为的几个不同版本。
ObjectStructure,对象结构类,该类能枚举它包含的元素,可以提供一个高层的接口以允许访问者访问它的元素。
Element,元素,声明了一个方法来“接收”(accept)访问者。该方法必须有一个参数被声明为访问者接口类型。
ConcreteElement,具体元素,实现Element声明的接口。该方法的目的是根据当前元素类将其调用重定向到相应访问者的方法。
Client,客户端,客户端通常不知晓所有的具体元素类,因为它们会通过抽象接口与集合中的对象进行交互。
访问者模式类图表示如下:
请添加图片描述
访问者模式可将数据结构与数据操作分离,可以解决稳定的数据结构和易变的操作耦合问题。

伪代码实现

接下来将使用代码介绍下访问者模式的实现。

// 1、访问者基类,声明了对对象结构的具体元素为参数的访问者方法
public interface IVisitor {void visitElement(ConcreteElementA element);void visitElement(ConcreteElementB element);
}//2、具体访问者,为不同的具体元素类实现相同行为的几个不同版本
public class ConcreteVisitorA implements IVisitor {@Overridepublic void visitElement(ConcreteElementA element) {System.out.println("handle a ConcreteElementA instance in ConcreteVisitorA");}@Overridepublic  void visitElement(ConcreteElementB element) {System.out.println("handle a ConcreteElementB instance in ConcreteVisitorA");}
}
public class ConcreteVisitorB implements IVisitor {@Overridepublic void visitElement(ConcreteElementA element) {System.out.println("handle a ConcreteElementA instance in ConcreteVisitorB");}@Overridepublic  void visitElement(ConcreteElementB element) {System.out.println("handle a ConcreteElementB instance in ConcreteVisitorB");}
}// 3、元素,声明了一个方法来“接收”(accept)访问者。该方法必须有一个参数被声明为访问者接口类型
public interface IElement {void accept(IVisitor visitor);
}// 4、具体元素,实现Element声明的接口
public class ConcreteElementA implements IElement {public void accept(IVisitor visitor) {visitor.visitElement(this);}
}
public class ConcreteElementB implements IElement {public void accept(IVisitor visitor) {visitor.visitElement(this);}
}// 5、对象结构类,可枚举它包含的元素,可以提供一个高层的接口以允许访问者访问它的元素
public class ObjectStructure {private IElement elementA;private IElement elementB;public ObjectStructure(IElement elementA, IElement elementB) {this.elementA = elementA;this.elementB = elementB;}public IElement getElementA() {return this.elementA;}public IElement getElementB() {return this.elementB;}
}// 6、客户端
public class VisitorClient {public void test() {// (1) 创建元素实例IElement elementA = new ConcreteElementA();IElement elementB = new ConcreteElementB();// (2) 创建对象结构实例ObjectStructure objectStructure = new ObjectStructure(elementA, elementB);// (3) 创建具体访问者实例IVisitor visitorA = new ConcreteVisitorA();// (4) 调用访问者方法visitorA.visitElement((ConcreteElementA) objectStructure.getElementA());visitorA.visitElement((ConcreteElementB) objectStructure.getElementB());IVisitor visitorB = new ConcreteVisitorB();visitorB.visitElement((ConcreteElementA) objectStructure.getElementA());visitorB.visitElement((ConcreteElementB) objectStructure.getElementB());}
}

适用场景

在以下情况下可以考虑使用访问者模式:
(1) 如果需要对一个复杂对象结构中的所有元素执行某些操作,可考虑使用访问者模式。访问者模式通过在访问者对象中为多个目标类提供相同操作的变体,
让开发者能在属于不同类的一组对象上执行同一操作。
(2) 可使用访问者模式来清理辅助行为的业务逻辑。访问者模式可将所有非主要的行为抽取到一组访问者类中,使得程序的主要类能更专注于主要的工作。
(3) 当某个行为仅在类层次结构中的一些类中有意义,而在其他类中没有意义时,可考虑使用访问者模式。可将该行为抽取到单独的访问者类中,
只需实现接收相关类的对象作为参数的访问者方法并将其他方法留空即可。

优缺点

访问者模式有以下优点:
(1) 符合开闭原则。以引入在不同类对象上执行的新行为, 且无需对这些类做出修改。
(2) 符合单一职责原则。可将同一行为的不同版本移到同一个类中。
但是该模式也存在以下缺点:
(1) 代码可能会变得更加复杂。使用访问者模式可能会导致某些系统有过多的具体访问者类。
(2) 每次在元素层次结构中添加或移除一个类时,都要更新所有的访问者,所以该模式对于频繁调整对象结构的类并不友好。
(3) 在访问者同某个元素进行交互时,可能没有访问元素私有成员变量和方法的必要权限。这与迪米特法则相违背。
(4) 违背了依赖倒转原则。访问者依赖的是具体元素,而不是抽象元素。

参考

《设计模式 可复用面向对象软件的基础》 Erich Gamma, Richard Helm, Ralph Johnson, John Vlissides 著, 李英军, 马晓星等译
https://refactoringguru.cn/design-patterns/visitor 访问者模式
https://www.runoob.com/design-pattern/visitor-pattern.html 访问者模式
https://www.cnblogs.com/adamjwh/p/10968634.html 简说设计模式——访问者模式

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

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

相关文章

在前端中如何创建表单并提交数据到服务器?

聚沙成塔每天进步一点点 ⭐ 专栏简介⭐ 通过from表单⭐ 代码讲解⭐ 注意事项⭐ 写在最后 ⭐ 专栏简介 前端入门之旅:探索Web开发的奇妙世界 记得点击上方或者右侧链接订阅本专栏哦 几何带你启航前端之旅 欢迎来到前端入门之旅!这个专栏是为那些对Web开发…

积累常见的有针对性的python面试题---python面试题001

1.考点列表的.remove方法的参数是传入的对应的元素的值,而不是下标 然后再看remove这里,注意这个是,删除写的那个值,比如这里写3,就是删除3, 而不是下标. remove不是下标删除,而是内容删除. 2.元组操作,元组不支持修改,某个下标的内容 可以问他如何修改元组的某个元素 3.…

Vue3 第五节 一些组合式API和其他改变

1.provide和inject 2.响应式数据判断 3.Composition API的优势 4.新的组件 5.其他改变 一.provide和inject 作用:实现祖与后代组件间通信 套路:父组件有一个provide选项来提供数据,后代组件有一个inject选项来开始使用这些数据 &…

PHP生成随机数

要在 PHP 中生成随机密码,可以使用 rand() 函数和字符串操作函数。以下是一个示例代码来生成包含字母、数字和特殊字符的随机密码 function generateRandomPassword($length 8) {// 定义包含字母、数字和特殊字符的字符集$characters abcdefghijklmnopqrstuvwxyz…

概念解析 | AutoFed:面向异构数据的联邦多模态自动驾驶的学习框架

AutoFed:面向异构数据的联邦多模态自动驾驶的学习框架 注1:本文系“概念解析”系列之一,致力于简洁清晰地解释、辨析复杂而专业的概念。本次辨析的概念是:面向异构数据的联邦学习在自动驾驶中的应用。 参考文献:Zheng T, Li A, Chen Z, et al. AutoFed: Heterogeneity-Aware F…

AcWing算法提高课-1.3.17背包问题求具体方案

宣传一下算法提高课整理 <— CSDN个人主页&#xff1a;更好的阅读体验 <— 本题链接&#xff08;AcWing&#xff09; 点这里 题目描述 有 N N N 件物品和一个容量是 V V V 的背包。每件物品只能使用一次。 第 i i i 件物品的体积是 v i v_i vi​&#xff0c;价值…

HEIF—— 1、vs2017编译Nokia - heif源码

HEIF(高效图像文件格式) 一种图片有损压缩格式,它的后缀名通常为".heic"或".heif"。 HEIF 是由运动图像专家组 (MPEG) 标准化的视觉媒体容器格式,用于存储和共享图像和图像序列。它基于著名的 ISO 基本媒体文件格式 (ISOBMFF) 标准。HEIF读写器引擎…

【C++】位图|布隆过滤器|海量数据处理面试题

文章目录 一.位图1. 位图的概念2. 位图的使用3. 位图的实现 二.布隆过滤器1. 布隆过滤器2. 布隆过滤器的实现 三.海量数据处理面试题1.位图2.布隆过滤器3.哈希切割 一.位图 1. 位图的概念 所谓位图&#xff0c;就是用每一位来存放某种状态&#xff0c;适用于海量数据&#xf…

android模拟器创建失败,出现“The emulator process for AVD xxx has terminated.”的错误

查找问题&#xff1a; 参考文章&#xff1a; 解决 Android studio 出现“The emulator process for AVD xxx has terminated.”的错误_the emulator process for avd pixel_3a_api_34_exten_千里未归jan的博客-CSDN博客

【LeetCode】删除并获得点数

删除并获得点数 题目描述算法分析编程代码空间优化 链接: 删除并获得点数 题目描述 算法分析 编程代码 class Solution { public:int deleteAndEarn(vector<int>& nums) {const int N 10001;int arr[N] {0};for(const auto& n : nums){arr[n]n;}vector<in…

2.安装Docker-ce

一、删除之前安装的docker(若之前未安装过&#xff0c;此步骤省略…) 进入centos根目录执行以下命令&#xff08;\ 是linux系统种命令换行符&#xff0c;如果命令过长&#xff0c;可以用\来换行&#xff09; yum remove docker \ docker-client \ docker-client-latest \ doc…

尚品汇总结十:秒杀模块(面试专用)

1、需求分析 所谓“秒杀”&#xff0c;就是商家发布一些超低价格的商品&#xff0c;所有买家在同一时间网上抢购的一种销售方式。通俗一点讲就是商家为促销等目的组织的网上限时抢购活动。由于商品价格低廉&#xff0c;往往一上架就被抢购一空&#xff0c;有时只用一秒钟。 秒…

状态模式(State)

状态模式是一种行为设计模式&#xff0c;允许一个对象在其内部状态改变时改变它的行为&#xff0c;使其看起来修改了自身所属的类。其别名为状态对象(Objects for States)。 State is a behavior design pattern that allows an object to change its behavior when its inter…

AI五子棋——超强改进版本

AI五子棋的改进版本来啦~~ 我们发现&#xff0c;原版的AI五子棋如果调成4的话&#xff0c;非常之慢&#xff01;&#xff01;下面给出原版的链接 AI五子棋&#xff08;原版本&#xff09; 因此我对其进行了改进&#xff0c;由于正常人下五子棋不会东下一颗棋&#xff0c;西下…

Flutter Dart语言(05)异步

0 说明 该系列教程主要是为有一定语言基础 C/C的程序员&#xff0c;快速学习一门新语言所采用的方法&#xff0c;属于在C/C基础上扩展新语言的模式。 1 async和await 在Dart语言中&#xff0c;虽然没有像其他语言&#xff08;如Java、C、Python&#xff09;中的传统多线程概…

Java怎么手动将对象注入到springboot

在Java中&#xff0c;可以使用Spring的ApplicationContext来手动将对象注入到Spring Boot中。 1. 首先&#xff0c;确保你已经在Spring Boot应用程序中引入了Spring的依赖&#xff0c;比如 spring-boot-starter 。 2. 在你的类中注入ApplicationContext对象&#xff1a; Autowi…

谷歌广告(Google ads)如何投放?新手必看的超全教程

Google是公认的全球最大的搜索引擎&#xff0c;同时&#xff0c;Google还通过旗下的 YouTube、Gmail、Google Play、Android等产品&#xff0c;汇集了海量的海外用户。对于跨境出海商家来说&#xff0c;谷歌广告是提高销售额、提高产品流量、拓展全球市场的重要推广渠道。 那么…

一文走进时序数据库性能测试工具 TSBS

一、背景 在物联网、车联网等时序数据场景中&#xff0c;数据的高速写入能力至关重要&#xff0c;会对产品方案的可用性、可靠性和扩展性产生影响。 以物联网为例&#xff0c;当面临千万甚至上亿设备、平均每个设备采集几十个到几百个指标时&#xff0c;每秒生成的数据将达到…

Docker+Consul+Registrator 实现服务注册与发现

第四阶段 时 间&#xff1a;2023年8月8日 参加人&#xff1a;全班人员 内 容&#xff1a; DockerConsulRegistrator 实现服务注册与发现 目录 一、服务注册中心引言 CAP理论是分布式架构中重要理论&#xff1a; 二、服务注册中心软件 &#xff08;一&#xff09;Zoo…

ELK 将数据流转换回常规索引

ELK 将数据流转换回常规索引 现象&#xff1a;创建索引模板是打开了数据流&#xff0c;导致不能创建常规索引&#xff0c;并且手动修改、删除索引模板失败 "reason" : "composable template [logs_template] with index patterns [new-pattern*], priority [2…