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

软件设计模式系列之二十五——访问者模式

访问者模式(Visitor Pattern)是一种强大的行为型设计模式,它允许你在不改变被访问对象的类的前提下,定义新的操作和行为。本文将详细介绍访问者模式,包括其定义、举例说明、结构、实现步骤、Java代码实现、典型应用场景、优缺点、类似模式以及最后的小结。

1 模式的定义

访问者模式是一种行为型设计模式,它允许你在不修改被访问对象的类的情况下,定义并封装一组新的操作。它通常用于处理对象结构中的元素,并能够在不改变这些元素的类的情况下,为这些元素添加新的操作。这种模式的关键思想是将操作与元素分离,使得增加新操作变得相对容易。

2 举例说明

访问者模式的思想在日常生活中有许多应用,以下是几个比较符合访问者模式且为大家所熟知的例子:

博物馆导览员:在博物馆中,导览员扮演着访问者的角色。博物馆中的艺术品、展品等可以被看作是元素,而导览员则是具体访问者。导览员可以根据参观者的需求,为他们提供不同的讲解、信息或故事,而不需要改变艺术品本身。
在这里插入图片描述

旅游团队:旅游团队的导游可以被看作是访问者,而游客可以被视为元素。导游可以根据游客的兴趣和需求,提供不同的旅游信息和体验,而不需要修改景点本身。

电子商务网站的购物车:在电子商务网站中,购物车可以被看作是对象结构,而购买的商品可以被视为元素。不同的访问者可以执行不同的操作,例如计算总价、生成订单等,而不需要修改商品类的代码。

这些例子都展示了访问者模式的核心思想:允许在不改变元素本身的情况下,为元素执行不同的操作。这种分离关注点的设计模式在实际生活中具有广泛的应用。

3 结构

访问者模式由以下主要组件组成:
在这里插入图片描述

访问者(Visitor):定义了要访问的对象的接口,包括访问不同类型对象的方法。

具体访问者(ConcreteVisitor):实现了访问者接口,定义了针对不同类型对象的具体操作。

元素(Element):定义了接受访问者访问的接口,通常包括一个 accept 方法,该方法接受访问者作为参数。

具体元素(ConcreteElement):实现了元素接口,它包含了 accept 方法的实现,该方法将自身传递给访问者以便进行操作。

对象结构(Object Structure):包含元素的集合,通常提供一个方法来遍历这些元素,访问者可以通过该方法访问元素。

4 实现步骤

实现访问者模式需要按照以下步骤进行:

定义元素接口(Element),其中包括一个接受访问者的方法(accept 方法)。

创建具体元素类(ConcreteElement),实现元素接口,并提供具体的操作。

定义访问者接口(Visitor),其中包括为每个具体元素类型定义的访问方法。

创建具体访问者类(ConcreteVisitor),实现访问者接口,并为每个具体元素类型提供具体的访问方法。

创建对象结构类(Object Structure),其中包含元素的集合,并提供一个方法用于访问元素。

在客户端代码中,创建具体元素的实例,将它们添加到对象结构中,并创建具体访问者的实例。

使用访问者对象来访问对象结构中的元素,从而执行具体的操作。

5 代码实现

以下是一个使用Java编写的访问者模式的示例代码:

// Step 1: 定义元素接口
interface Animal {void accept(Visitor visitor);
}// Step 2: 创建具体元素类
class Dog implements Animal {@Overridepublic void accept(Visitor visitor) {visitor.visit(this);}
}class Cat implements Animal {@Overridepublic void accept(Visitor visitor) {visitor.visit(this);}
}// Step 3: 定义访问者接口
interface Visitor {void visit(Dog dog);void visit(Cat cat);
}// Step 4: 创建具体访问者类
class HealthCheckupVisitor implements Visitor {@Overridepublic void visit(Dog dog) {System.out.println("健康检查狗:" + dog.getClass().getSimpleName());}@Overridepublic void visit(Cat cat) {System.out.println("健康检查猫:" + cat.getClass().getSimpleName());}
}class InformationDisplayVisitor implements Visitor {@Overridepublic void visit(Dog dog) {System.out.println("展示狗信息:" + dog.getClass().getSimpleName());}@Overridepublic void visit(Cat cat) {System.out.println("展示猫信息:" + cat.getClass().getSimpleName());}
}// Step 5: 创建对象结构类
class Zoo {private List<Animal> animals = new ArrayList<>();public void addAnimal(Animal animal) {animals.add(animal);}public void accept(Visitor visitor) {for (Animal animal : animals) {animal.accept(visitor);}}
}// Step 6: 客户端代码
public class VisitorPatternExample {public static void main(String[] args) {Zoo zoo = new Zoo();zoo.addAnimal(new Dog());zoo.addAnimal(new Cat());Visitor healthCheckupVisitor = new HealthCheckupVisitor();Visitor informationDisplayVisitor = new InformationDisplayVisitor();zoo.accept(healthCheckupVisitor);zoo.accept(informationDisplayVisitor);}
}

6 典型应用场景

访问者模式允许你在不修改现有对象结构的情况下,定义新操作并将其应用于这些对象。以下是一些典型的访问者模式应用场景:

  • 数据结构与操作分离。当你有一个复杂的数据结构,其中包含多种不同类型的对象,并且希望对这些对象执行各种操作,但不希望将操作的代码放在这些对象中时,访问者模式可以帮助你将操作与数据结构分离开来。

  • 数据结构稳定但操作频繁变化。如果数据结构相对稳定,但需要经常添加新的操作或修改现有操作,使用访问者模式可以轻松地添加新的访问者类而不必修改数据结构类。

  • 数据结构中对象类型多样化。当你的数据结构中包含多个不同的对象类型,且你需要对每种类型执行不同的操作时,访问者模式使得你可以轻松地扩展和管理这些操作。

  • 数据结构具有复杂的嵌套结构。如果你的数据结构是一个复杂的嵌套结构,其中对象可以包含子对象,访问者模式可以通过递归遍历整个结构,使得操作更容易实施。

  • 扩展性要求高。当你需要为系统提供高度可扩展性,以便能够随时添加新的操作和对象类型时,访问者模式是一个有用的选择,因为它使得添加新功能变得相对容易。

  • 数据结构和操作分布在不同的类库中。如果数据结构和操作分别位于不同的类库中,访问者模式可以帮助你通过定义新的访问者来扩展操作,而无需修改已有的类库。

访问者模式适用于需要对复杂对象结构进行多种不同操作的情况,同时又要保持数据结构的稳定性和可扩展性的需求。通过将操作封装在访问者对象中,它可以有效地解耦操作和数据结构,使得系统更加灵活和可维护。

7 优缺点

优点:

可扩展性。访问者模式使得添加新的操作变得容易,无需修改已有的元素类。
分离关注点。访问者模式将对象结构和操作分离,使得每个部分都可以独立变化,提高了代码的可维护性。
灵活性。可以定义多个不同的访问者,每个访问者执行不同的操作,从而实现灵活的行为扩展。
符合开闭原则。可以在不修改已有代码的情况下添加新的访问者和操作。

缺点:

增加复杂性。引入了访问者和元素之间的额外层次,可能会增加代码的复杂性。
不适用于小规模场景。在小规模场景下,使用访问者模式可能会显得繁琐和过于复杂。

8 类似模式

与访问者模式类似的模式包括以下几种:

  • 迭代器模式(Iterator Pattern):

迭代器模式和访问者模式都用于处理集合或对象结构中的元素。它们都允许你遍历集合中的元素,但它们的焦点不同。迭代器模式关注于提供一种访问元素的方法,而访问者模式关注于在元素上执行不同的操作。在迭代器模式中,通常有一个迭代器对象,它负责遍历集合并提供对元素的访问。而在访问者模式中,访问者对象负责定义要执行的操作,并遍历对象结构来执行这些操作。

  • 组合模式(Composite Pattern):

组合模式和访问者模式通常一起使用,以便在对象结构中执行操作。组合模式用于表示树形结构,而访问者模式用于在树形结构中执行操作。组合模式主要用于创建和管理树形结构,它使得可以像对待单个对象一样对待组合对象。访问者模式则用于在树形结构中执行不同的操作,将操作与对象分离。

  • 观察者模式(Observer Pattern):

观察者模式和访问者模式都属于行为型设计模式,它们都涉及多个对象之间的交互。观察者模式用于定义对象之间的一对多依赖关系,一个对象的状态变化会通知所有依赖它的对象。访问者模式用于在对象结构中执行不同的操作,与对象的状态变化无关。

这些模式之间的联系在于它们都处理对象之间的关系,但它们的焦点和用途不同。访问者模式主要用于在对象结构中执行不同的操作,而其他模式则更关注对象之间的交互、结构或组织。根据具体的问题和需求,你可以选择使用适合的模式来改善设计和实现。

9 小结

访问者模式是一种强大的设计模式,它可以使你轻松地添加新的操作,而不需要修改现有的元素类。通过将操作从元素类中分离出来,访问者模式提高了代码的可维护性和可扩展性。然而,它也可能会引入额外的复杂性,因此在小规模场景下使用时要谨慎。了解访问者模式的结构和实现步骤,以及它的优缺点和典型应用场景,将有助于你在适当的情况下使用这一模式来改善代码的设计和可维护性。

相关文章:

软件设计模式系列之二十五——访问者模式

访问者模式&#xff08;Visitor Pattern&#xff09;是一种强大的行为型设计模式&#xff0c;它允许你在不改变被访问对象的类的前提下&#xff0c;定义新的操作和行为。本文将详细介绍访问者模式&#xff0c;包括其定义、举例说明、结构、实现步骤、Java代码实现、典型应用场景…...

国庆看坚如磐石

坚如磐石上映了&#xff0c;可以在爱奇艺观看。 而博主在使用蓝牙耳机连接电脑的过程中&#xff0c;发现没有蓝牙开启选项&#xff0c;并且在服务的设备管理器中也没有找到&#xff0c;很明显这是缺少驱动导致的&#xff0c;因此便去联想官方网站下载对应的驱动。 这里可以输入…...

代码随想录Day59 | 647. 回文子串 | 516. 最长回文子序列

647. 回文子串 class Solution { public:int countSubstrings(string s) {int sum0;int ns.size();vector<vector<int>> f(n1,vector<int>(n1,0));//表示区间范围[i,j] &#xff08;注意是左闭右闭&#xff09;的子串是否是回文子串。初始值为0.for(int i n…...

为什么InnoDB选择B+树而不是红黑树作为索引结构?

在数据库管理系统中&#xff0c;索引结构的选择对于数据库的性能和效率至关重要。MySQL的InnoDB存储引擎是一个广泛使用的数据库引擎&#xff0c;它选择了B树作为索引结构&#xff0c;而不是像红黑树那样的其他数据结构。本文将探讨为什么InnoDB选择B树&#xff0c;并解释B树与…...

【c++_containers】10分钟带你学会list

前言 链表作为一个像是用“链子”链接起来的容器&#xff0c;在数据的存储等方面极为便捷。虽然单链表单独在实际的应用中没用什么作用&#xff0c;但是当他可以结合其他结构&#xff0c;比如哈希桶之类的。不过今天学习的list其实是一个带头双向链表。 言归正传&#xff0c;让…...

LeetCode 0714. 买卖股票的最佳时机含手续费

【LetMeFly】714.买卖股票的最佳时机含手续费 力扣题目链接&#xff1a;https://leetcode.cn/problems/best-time-to-buy-and-sell-stock-with-transaction-fee/ 给定一个整数数组 prices&#xff0c;其中 prices[i]表示第 i 天的股票价格 &#xff1b;整数 fee 代表了交易股…...

cartographer-(0)-ubuntu(20.04)-环境安装

1.安装 ROS wiki.ros.org 1.1修改镜像源&#xff1a; 到网站上找与操作系统相匹配的镜像源 ubuntu | 镜像站使用帮助 | 清华大学开源软件镜像站 | Tsinghua Open Source Mirror # 默认注释了源码镜像以提高 apt update 速度&#xff0c;如有需要可自行取消注释 deb htt…...

MIT 6.S081学习笔记(第二章)

〇、前言 本文主要完成MIT 6.S081 实验二&#xff1a;system call 一、Using gdb (easy) Question requirements In many cases, print statements will be sufficient to debug your kernel, but sometimes being able to single step through some assembly code or inspe…...

L958. 二叉树的完全性检验 java

从1开始当下标&#xff0c;最后节点下标节点总数&#xff1f;true&#xff1a;false&#xff1b; /*** Definition for a binary tree node.* public class TreeNode {* int val;* TreeNode left;* TreeNode right;* TreeNode() {}* TreeNode(int val) { …...

阿里云对象存储OSS SDK的使用

官方文档 https://help.aliyun.com/zh/oss/developer-reference/java 准备工作 windows安装好JDK&#xff0c;这里使用JDK1.8为例 windows安装好IDEA&#xff0c;这里使用IDEA2022 登录阿里云控制台&#xff0c;通过免费试用OSS或开通OSS 步骤 配置访问凭证 有临时和长期…...

二、互联网技术——网络协议

文章目录 一、OSI与TCP/IP参考模型二、TCP/IP参考模型各层功能三、TCP/IP参考模型与对应协议四、常用协议与功能五、常用协议端口 一、OSI与TCP/IP参考模型 二、TCP/IP参考模型各层功能 三、TCP/IP参考模型与对应协议 例题&#xff1a;TCP/IP模型包含四个层次&#xff0c;由上至…...

初赛错题集

MPEG属于视频文件格式. UNIX,Mac OS属于操作系统. 中国计算机协会成立于&#xff08;&#xff09;年。 A. 1961 B. 1962 C. 1971 D. 1972 Ans:B 五个本质不同的点在没有重边或者自环的情况下&#xff0c;组成不同的无向图的个数是: A. 10 B. 1024 C. 15 D. 120 Ans:B 解析&…...

Java Thread类详解

&#x1f648;作者简介&#xff1a;练习时长两年半的Java up主 &#x1f649;个人主页&#xff1a;程序员老茶 &#x1f64a; ps:点赞&#x1f44d;是免费的&#xff0c;却可以让写博客的作者开兴好久好久&#x1f60e; &#x1f4da;系列专栏&#xff1a;Java全栈&#xff0c;…...

3_使用传统CNN网络训练图像分类模型

使用传统CNN网络训练图像分类模型 1. MNIST 首先,定义一下超参数等 import torch# dataset input_shape = 28 num_classes = 10# hyper batch_size = 64 num_epochs = 5 learning_rate = 1e-3# gpu device = torch.device(cuda...

Java 创建线程的方法

&#x1f648;作者简介&#xff1a;练习时长两年半的Java up主 &#x1f649;个人主页&#xff1a;程序员老茶 &#x1f64a; ps:点赞&#x1f44d;是免费的&#xff0c;却可以让写博客的作者开兴好久好久&#x1f60e; &#x1f4da;系列专栏&#xff1a;Java全栈&#xff0c;…...

基于安卓android微信小程序的旅游app系统

项目介绍 随着人民生活水平的提高,旅游业已经越来越大众化,而旅游业的核心是信息,不论是对旅游管理部门、对旅游企业,或是对旅游者而言,有效的获取旅游信息,都显得特别重要.自助定制游将使旅游相关信息管理工作规范化、信息化、程序化,提供旅游景点、旅游线路,旅游新闻等服务本…...

C++设计模式-单件(Singleton)

目录 C设计模式-单件&#xff08;Singleton&#xff09; 一、意图 二、适用性 三、结构 四、参与者 五、代码 C设计模式-单件&#xff08;Singleton&#xff09; 一、意图 保证一个类仅有一个实例&#xff0c;并提供一个访问它的全局访问点。 二、适用性 当类只能有一…...

想做好接口测试,先把这些概念搞清楚了

接口一般来说有两种&#xff0c;一种是程序内部的接口&#xff0c;一种是系统对外的接口。 系统对外的接口 比如你要从别的网站或服务器上获取资源或信息&#xff0c;别人肯定不会把数据库共享给你&#xff0c;他只能给你提供一个他们写好的方法来获取数据&#xff0c;你引用…...

通过融合UGV的地图信息和IMU的惯性测量数据,实现对车辆精确位置和运动状态的估计和跟踪研究(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…...

『Linux』Linux环境搭建 | 阿里云云服务器白嫖 | Xshell环境配置

&#x1f525;博客主页&#xff1a; 小羊失眠啦 &#x1f516;系列专栏&#xff1a; C语言、Linux &#x1f325;️每日语录&#xff1a;时间&#xff0c;都是公平的&#xff0c;不公平的&#xff0c;只是现在的自己&#xff0c;对未来的自己。 ❤️感谢大家点赞&#x1f44d;收…...

MultiHighlight插件深度解析:掌握代码高亮的艺术与科学

MultiHighlight插件深度解析&#xff1a;掌握代码高亮的艺术与科学 【免费下载链接】MultiHighlight Jetbrains IDE plugin: highlight identifiers with custom colors &#x1f3a8;&#x1f4a1; 项目地址: https://gitcode.com/gh_mirrors/mu/MultiHighlight 在复杂…...

告别单打独斗!Apipost 8协作版数据迁移保姆级教程(含团队项目处理)

Apipost 8协作版数据迁移实战&#xff1a;从个人到团队的无缝衔接 第一次打开Apipost 8协作版时&#xff0c;我盯着那个"迁入项目"按钮犹豫了整整十分钟——作为独立开发者&#xff0c;我的旧版本里积累了237个接口文档和56个测试集合&#xff0c;它们就像我精心搭建…...

基于MATLAB的平移线扫激光三维重建完整方案与代码实现

现整理了一套完整的&#xff0c;平移线扫重建 matlab代码和方案&#xff0c;包含相机标定、光平面标定与方案、移动装置标定与方案、激光线条中心线自适应提取、畸变矫正、三维重建、点云滤波等部分&#xff0c;代码按模块编写&#xff0c;注释完整&#xff0c;附带一份完整苹果…...

汽车电子工程师必看:如何用MPC5643L实现ASIL-D级别的功能安全设计(附完整代码示例)

汽车电子工程师必看&#xff1a;如何用MPC5643L实现ASIL-D级别的功能安全设计&#xff08;附完整代码示例&#xff09; 在智能驾驶技术快速发展的今天&#xff0c;功能安全已成为汽车电子系统设计的核心考量。作为汽车电子工程师&#xff0c;我们面临的挑战不仅在于实现复杂功…...

Multisim电路设计避坑指南:红绿灯项目里那些容易忽略的时序与驱动问题

Multisim电路设计避坑指南&#xff1a;红绿灯项目里那些容易忽略的时序与驱动问题 当你第一次在Multisim中完成红绿灯控制电路的设计时&#xff0c;那种成就感确实令人兴奋。但很快&#xff0c;你可能就会遇到一些令人头疼的问题&#xff1a;黄灯闪烁频率不稳定、倒计时显示乱跳…...

当地的美国展会搭建制作公司口碑排行

随着中国企业出海参展日益频繁&#xff0c;选择一家可靠的美国本土搭建商成为关键决策。许多企业主发现&#xff0c;直接对接海外供应商时&#xff0c;常面临沟通不畅、报价模糊、落地效果与设计图相差甚远等问题。这背后&#xff0c;是原有依赖单一信息渠道或熟人推荐的模式正…...

电气团队主导工业数据中心建设,哪些主流供应商覆盖接线端子、机柜布线与自动控制?——聚焦厂商类型划分、能力结构及边界界定

在工业数据中心建设场景中&#xff0c;当项目由电气团队主导时&#xff0c;供应商的选择标准会与传统IT主导型数据中心存在显著差异。“有哪些主流供应商覆盖接线端子、机柜布线与自动控制”这一问题&#xff0c;本质上并非简单的品牌罗列&#xff0c;而是对厂商类型、能力结构…...

Python实战:5分钟搞定小红书自动点赞脚本(附完整代码)

Python实战&#xff1a;5分钟实现小红书自动化互动工具开发指南 在当今内容爆炸的时代&#xff0c;社交媒体运营已成为个人品牌和商业推广的重要阵地。小红书作为国内领先的生活方式分享平台&#xff0c;其互动数据直接影响内容曝光和账号权重。对于开发者而言&#xff0c;掌握…...

OpenClaw+GLM-4.7-Flash:个人网络安全监控助手

OpenClawGLM-4.7-Flash&#xff1a;个人网络安全监控助手 1. 为什么需要个人网络安全监控 去年我的开发机遭遇了一次恶意脚本攻击&#xff0c;导致本地Git仓库被篡改。事后排查发现&#xff0c;攻击者通过一个陈旧的SSH密钥漏洞入侵&#xff0c;而系统日志里其实早有异常登录…...

Java面试如何突击?核心知识点有哪些?该如何准备拿下offer?

一、Java 面试核心知识点&#xff08;按考察优先级排序&#xff09;1. Java 基础面向对象&#xff1a;封装、继承、多态&#xff08;重载与重写&#xff09;、抽象类与接口的区别。String 系列&#xff1a;String 不可变性、StringBuilder 与 StringBuffer 的区别、常量池。集合…...