陕西城乡建设部网站/淘宝推广
访问者模式(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 🌥️每日语录:时间,都是公平的,不公平的,只是现在的自己,对未来的自己。 ❤️感谢大家点赞👍收…...

C++ 类和对象篇(五) 析构函数
目录 一、概念 1. 析构函数是什么? 2. 为什么要有析构函数? 3. 怎么用析构函数? 3.1 创建析构函数 3.2 调用析构函数 二、特性 三、由编译器生成的默认析构函数 四、对象的析构顺序 1. 局部对象 2. new出来的堆对象 3. 全局对象 一、概念 1…...

find 与 cp 命令组合使用
查找到文件后,拷贝到指定路径 find ~/Downloads/ -name *.torrent -exec cp {} ~/Downloads/myTorrent \;\;前面有个空格,要注意,这是固定结构,请不要尝试改变 上面命令是在Downloads 目标中查找后缀为torrent所有文件࿰…...

用VLD调查VC内存泄漏
一、发现内存泄漏 使用VS2022,发现提示有内存泄漏,检查了所有的new,确认都有相应的delete释放。 Detected memory leaks! Dumping objects -> {1914} normal block at 0x0000021FDFFBD2E0, 48 bytes long.Data: < >…...

【Java 进阶篇】使用 JDBCTemplate 执行 DQL 语句详解
在前面的文章中,我们已经学习了如何使用 Spring 的 JDBCTemplate 执行 DML(Data Manipulation Language)操作,包括插入、更新和删除操作。现在,让我们来深入了解如何使用 JDBCTemplate 执行 DQL(Data Query…...

了解了spring mvc web容器中一个http请求的全过程,能给我们提升多少武力值
继上一篇文章什么,这年头还有人不知道404_cow__sky的博客-CSDN博客后,有些同学发现,学了之后有啥用,有什么实际场景可以用到吗?程序员就是这样,不习惯于纸上谈兵,给一个场景show me code才是最实…...

【BBC新闻文章分类】使用 TF 2.0和 LSTM 的文本分类
一、说明 NLP上的许多创新是如何将上下文添加到词向量中。常见的方法之一是使用递归神经网络...

set和map的封装
目录 介绍 红黑树代码 set insert的迭代器转换问题 为什么会有这样的问题? 如何解决 代码 map 注意点 代码 介绍 set和map的底层都是红黑树,所以我们可以在自己实现的红黑树(简易版)的基础上,进行封装,成为简易的set和map 红黑树代码 #pragma once#include <…...

java基础练习--基础语法
预备知识:Java基本语法、分支、循环、数组和字符串 7-1 累加器 请你实现一个累加器。输入n个非负整数,输出他们的和。 1<n<1000,而每个数则<10000。 输入格式: 输入包括两行。 第一行:包括一个整数n,表示总共有n个数。 第二行:包…...

Android12 OTA编译差分包报错问题
前言 在Ubuntu 20.04.4 LTS系统中编译Android12 OTA差分包的时候提示如下报错log: Warning: releasetools script should be invoked as hermetic Python executable -- build and run ota_from_target_files directly. Traceback (most recent call last):File "./bu…...

现代c++手撸2309神经网络最简化版230901
用c++输入数据:vector<vector<float>> inputs = { {1, 1}, {1, 0} };数据targets={0,1}; 测试:vector<vector<float>> inputs22 = { {1, 0}, {1,1} }; 构建神经网络,例如:NeuralNetwork nn({ 2, 4, 1 }); 则网络有四层、输入层2个节点、输出层1个节…...