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

软件设计模式系列之二十五——访问者模式
访问者模式(Visitor Pattern)是一种强大的行为型设计模式,它允许你在不改变被访问对象的类的前提下,定义新的操作和行为。本文将详细介绍访问者模式,包括其定义、举例说明、结构、实现步骤、Java代码实现、典型应用场景…...

国庆看坚如磐石
坚如磐石上映了,可以在爱奇艺观看。 而博主在使用蓝牙耳机连接电脑的过程中,发现没有蓝牙开启选项,并且在服务的设备管理器中也没有找到,很明显这是缺少驱动导致的,因此便去联想官方网站下载对应的驱动。 这里可以输入…...
代码随想录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] (注意是左闭右闭)的子串是否是回文子串。初始值为0.for(int i n…...
为什么InnoDB选择B+树而不是红黑树作为索引结构?
在数据库管理系统中,索引结构的选择对于数据库的性能和效率至关重要。MySQL的InnoDB存储引擎是一个广泛使用的数据库引擎,它选择了B树作为索引结构,而不是像红黑树那样的其他数据结构。本文将探讨为什么InnoDB选择B树,并解释B树与…...

【c++_containers】10分钟带你学会list
前言 链表作为一个像是用“链子”链接起来的容器,在数据的存储等方面极为便捷。虽然单链表单独在实际的应用中没用什么作用,但是当他可以结合其他结构,比如哈希桶之类的。不过今天学习的list其实是一个带头双向链表。 言归正传,让…...
LeetCode 0714. 买卖股票的最佳时机含手续费
【LetMeFly】714.买卖股票的最佳时机含手续费 力扣题目链接:https://leetcode.cn/problems/best-time-to-buy-and-sell-stock-with-transaction-fee/ 给定一个整数数组 prices,其中 prices[i]表示第 i 天的股票价格 ;整数 fee 代表了交易股…...

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

MIT 6.S081学习笔记(第二章)
〇、前言 本文主要完成MIT 6.S081 实验二: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开始当下标,最后节点下标节点总数?true:false; /*** 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,这里使用JDK1.8为例 windows安装好IDEA,这里使用IDEA2022 登录阿里云控制台,通过免费试用OSS或开通OSS 步骤 配置访问凭证 有临时和长期…...

二、互联网技术——网络协议
文章目录 一、OSI与TCP/IP参考模型二、TCP/IP参考模型各层功能三、TCP/IP参考模型与对应协议四、常用协议与功能五、常用协议端口 一、OSI与TCP/IP参考模型 二、TCP/IP参考模型各层功能 三、TCP/IP参考模型与对应协议 例题:TCP/IP模型包含四个层次,由上至…...
初赛错题集
MPEG属于视频文件格式. UNIX,Mac OS属于操作系统. 中国计算机协会成立于()年。 A. 1961 B. 1962 C. 1971 D. 1972 Ans:B 五个本质不同的点在没有重边或者自环的情况下,组成不同的无向图的个数是: A. 10 B. 1024 C. 15 D. 120 Ans:B 解析&…...
Java Thread类详解
🙈作者简介:练习时长两年半的Java up主 🙉个人主页:程序员老茶 🙊 ps:点赞👍是免费的,却可以让写博客的作者开兴好久好久😎 📚系列专栏:Java全栈,…...
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 创建线程的方法
🙈作者简介:练习时长两年半的Java up主 🙉个人主页:程序员老茶 🙊 ps:点赞👍是免费的,却可以让写博客的作者开兴好久好久😎 📚系列专栏:Java全栈,…...

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

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

想做好接口测试,先把这些概念搞清楚了
接口一般来说有两种,一种是程序内部的接口,一种是系统对外的接口。 系统对外的接口 比如你要从别的网站或服务器上获取资源或信息,别人肯定不会把数据库共享给你,他只能给你提供一个他们写好的方法来获取数据,你引用…...

通过融合UGV的地图信息和IMU的惯性测量数据,实现对车辆精确位置和运动状态的估计和跟踪研究(Matlab代码实现)
💥💥💞💞欢迎来到本博客❤️❤️💥💥 🏆博主优势:🌞🌞🌞博客内容尽量做到思维缜密,逻辑清晰,为了方便读者。 ⛳️座右铭&a…...

『Linux』Linux环境搭建 | 阿里云云服务器白嫖 | Xshell环境配置
🔥博客主页: 小羊失眠啦 🔖系列专栏: C语言、Linux 🌥️每日语录:时间,都是公平的,不公平的,只是现在的自己,对未来的自己。 ❤️感谢大家点赞👍收…...

iOS 26 携众系统重磅更新,但“苹果智能”仍与国行无缘
美国西海岸的夏天,再次被苹果点燃。一年一度的全球开发者大会 WWDC25 如期而至,这不仅是开发者的盛宴,更是全球数亿苹果用户翘首以盼的科技春晚。今年,苹果依旧为我们带来了全家桶式的系统更新,包括 iOS 26、iPadOS 26…...
Linux链表操作全解析
Linux C语言链表深度解析与实战技巧 一、链表基础概念与内核链表优势1.1 为什么使用链表?1.2 Linux 内核链表与用户态链表的区别 二、内核链表结构与宏解析常用宏/函数 三、内核链表的优点四、用户态链表示例五、双向循环链表在内核中的实现优势5.1 插入效率5.2 安全…...
前端倒计时误差!
提示:记录工作中遇到的需求及解决办法 文章目录 前言一、误差从何而来?二、五大解决方案1. 动态校准法(基础版)2. Web Worker 计时3. 服务器时间同步4. Performance API 高精度计时5. 页面可见性API优化三、生产环境最佳实践四、终极解决方案架构前言 前几天听说公司某个项…...
django filter 统计数量 按属性去重
在Django中,如果你想要根据某个属性对查询集进行去重并统计数量,你可以使用values()方法配合annotate()方法来实现。这里有两种常见的方法来完成这个需求: 方法1:使用annotate()和Count 假设你有一个模型Item,并且你想…...

智能在线客服平台:数字化时代企业连接用户的 AI 中枢
随着互联网技术的飞速发展,消费者期望能够随时随地与企业进行交流。在线客服平台作为连接企业与客户的重要桥梁,不仅优化了客户体验,还提升了企业的服务效率和市场竞争力。本文将探讨在线客服平台的重要性、技术进展、实际应用,并…...

如何将联系人从 iPhone 转移到 Android
从 iPhone 换到 Android 手机时,你可能需要保留重要的数据,例如通讯录。好在,将通讯录从 iPhone 转移到 Android 手机非常简单,你可以从本文中学习 6 种可靠的方法,确保随时保持连接,不错过任何信息。 第 1…...
Robots.txt 文件
什么是robots.txt? robots.txt 是一个位于网站根目录下的文本文件(如:https://example.com/robots.txt),它用于指导网络爬虫(如搜索引擎的蜘蛛程序)如何抓取该网站的内容。这个文件遵循 Robots…...
【决胜公务员考试】求职OMG——见面课测验1
2025最新版!!!6.8截至答题,大家注意呀! 博主码字不易点个关注吧,祝期末顺利~~ 1.单选题(2分) 下列说法错误的是:( B ) A.选调生属于公务员系统 B.公务员属于事业编 C.选调生有基层锻炼的要求 D…...

UR 协作机器人「三剑客」:精密轻量担当(UR7e)、全能协作主力(UR12e)、重型任务专家(UR15)
UR协作机器人正以其卓越性能在现代制造业自动化中扮演重要角色。UR7e、UR12e和UR15通过创新技术和精准设计满足了不同行业的多样化需求。其中,UR15以其速度、精度及人工智能准备能力成为自动化领域的重要突破。UR7e和UR12e则在负载规格和市场定位上不断优化…...

Java面试专项一-准备篇
一、企业简历筛选规则 一般企业的简历筛选流程:首先由HR先筛选一部分简历后,在将简历给到对应的项目负责人后再进行下一步的操作。 HR如何筛选简历 例如:Boss直聘(招聘方平台) 直接按照条件进行筛选 例如:…...