设计模式之访问者模式:一楼千面 各有玄机

在这里插入图片描述

~犬📰余~

“我欲贱而贵,愚而智,贫而富,可乎?
曰:其唯学乎”

一、访问者模式概述

\quad 江湖中有一个传说:在遥远的东方,有一座神秘的玉楼。每当武林中人来访,楼中的各个房间都会根据来访者的身份展现出不同的面貌。练剑之人来访,便见剑术精要;习医之人来访,则现医道真谛。一样的楼阁,却能因来访者的不同而呈现万千气象。这,正是访问者模式的真谛。
\quad 在软件设计的世界里,访问者模式就像这座神奇的玉楼。它允许我们将数据结构和数据操作分离,就像将楼阁和访客分开一样。这种设计模式定义了一种方式,让我们能够在不改变已有对象结构的情况下,向其中添加新的操作行为。
\quad 想象一下游乐园的场景:过山车、旋转木马、海盗船等设施早已固定在那里,但每天都会有不同的人来访问它们 —— 游客来游玩、检查员来检修、维护工来保养。每类访问者都会对这些设施进行不同的操作,但设施本身的结构并不会因此改变。

二、访问者模式的角色组成

\quad 在解析访问者模式的角色构成之前,让我们先看一下它的整体结构::

图片
\quad 就像一座精心设计的园林,访问者模式中的每个角色都各司其职,共同构建出一个优雅的结构体系。让我们一起走进这座代码园林,认识一下其中的主要角色:

  • Element(元素):它就像游乐园中的各个游乐设施。每个Element都定义了一个accept方法,这个方法就像设施的接待窗口,来访者必须通过这个窗口才能与设施互动。在我们的游乐园例子中,它可以是过山车、旋转木马等具体设施。
  • Visitor(访问者):它就像是来游乐园的不同人员。可能是来玩耍的游客、来检修的工程师,或是来检查安全的督察员。每种访问者都定义了一系列visit方法,用于访问不同类型的元素。这些方法就像是不同人员对设施的不同操作方式。
  • ObjectStructure(对象结构):像是整个游乐园的管理处。它知道园内有哪些设施,并且负责安排访问者去访问这些设施。当一个安全检查员来到游乐园时,管理处会安排他依次检查所有的设施。
  • ConcreteElement(具体元素):是Element的实现类,就像具体的过山车、旋转木马。它们都实现了accept方法,在方法中通过调用访问者的visit方法来完成具体的操作。这就像每个设施都知道如何配合不同人员的工作。
  • ConcreteVisitor(具体访问者):Visitor的实现类,例如具体的安全检查员、维修工程师等。他们各自实现了visit方法,定义了对不同设施的具体操作流程。检查员检查安全隐患,工程师进行维护保养,各司其职。

\quad 这些角色之间的互动就像是一场精心编排的舞蹈:当游客(ConcreteVisitor)来到游乐园(ObjectStructure)时,管理处会安排他们依次游览各个设施(ConcreteElement)。每个设施都会根据访问者的身份,展现出相应的互动方式。

三、访问者模式案例

\quad 让我们通过一个完整的游乐园管理系统来深入理解访问者模式。在这个系统中,我们需要对不同的游乐设施进行日常检查和维护。每种设施都有其特定的检查点,而不同的工作人员(访问者)也有着不同的工作职责。
\quad 首先,让我们定义设施接口和具体设施:

// 设施接口
public interface Facility {void accept(FacilityVisitor visitor);
}// 过山车设施
public class RollerCoaster implements Facility {private String name;private int maxSpeed;public RollerCoaster(String name, int maxSpeed) {this.name = name;this.maxSpeed = maxSpeed;}public String getName() { return name; }public int getMaxSpeed() { return maxSpeed; }@Overridepublic void accept(FacilityVisitor visitor) {visitor.visit(this);}
}// 旋转木马设施
public class Carousel implements Facility {private String name;private int capacity;public Carousel(String name, int capacity) {this.name = name;this.capacity = capacity;}public String getName() { return name; }public int getCapacity() { return capacity; }@Overridepublic void accept(FacilityVisitor visitor) {visitor.visit(this);}
}// 访问者接口
public interface FacilityVisitor {void visit(RollerCoaster rollerCoaster);void visit(Carousel carousel);
}// 安全检查员
public class SafetyInspector implements FacilityVisitor {@Overridepublic void visit(RollerCoaster rollerCoaster) {System.out.println("安全检查员正在检查过山车 " + rollerCoaster.getName());System.out.println("检查最高速度: " + rollerCoaster.getMaxSpeed() + "km/h");System.out.println("检查安全带和刹车系统...");}@Overridepublic void visit(Carousel carousel) {System.out.println("安全检查员正在检查旋转木马 " + carousel.getName());System.out.println("检查承载人数: " + carousel.getCapacity() + "人");System.out.println("检查座椅固定装置...");}
}// 维护工程师
public class MaintenanceEngineer implements FacilityVisitor {@Overridepublic void visit(RollerCoaster rollerCoaster) {System.out.println("维护工程师正在保养过山车 " + rollerCoaster.getName());System.out.println("润滑轨道和车轮...");System.out.println("检测电机运行状态...");}@Overridepublic void visit(Carousel carousel) {System.out.println("维护工程师正在保养旋转木马 " + carousel.getName());System.out.println("检查驱动系统...");System.out.println("更换磨损零件...");}
}// 游乐园管理类
public class AmusementPark {private List<Facility> facilities = new ArrayList<>();public void addFacility(Facility facility) {facilities.add(facility);}public void accept(FacilityVisitor visitor) {for(Facility facility : facilities) {facility.accept(visitor);}}
}

\quad 现在让我们通过一个具体的例子来运行这个系统:

public class Test{public static void main(String[] args) {// 创建游乐园AmusementPark park = new AmusementPark();// 添加设施park.addFacility(new RollerCoaster("极速之星", 120));park.addFacility(new Carousel("童话木马", 30));// 创建访问者SafetyInspector inspector = new SafetyInspector();MaintenanceEngineer engineer = new MaintenanceEngineer();// 进行安全检查System.out.println("=== 开始安全检查 ===");park.accept(inspector);System.out.println("\n=== 开始设备维护 ===");park.accept(engineer);}
}

\quad 运行这段代码,我们可以看到不同的访问者对相同设施进行不同的操作,而不需要修改设施类的代码:
在这里插入图片描述

四、访问者模式优缺点

4.1. 优点:

\quad 访问者模式最显著的特点是实现了数据结构与数据操作的分离。就像我们的游乐园案例,无论是增加新的检查员还是维护工程师,都不需要修改原有的设施类代码。这种设计非常符合"开闭原则",对扩展开放,对修改关闭。同时,相关的操作行为被集中在访问者类中,使得操作逻辑更加集中和清晰。例如,所有的安全检查逻辑都在SafetyInspector类中,便于统一管理和维护。

4.2. 缺点:

\quad 首先是对扩展元素类型不友好。如果我们要在游乐园中增加一种全新的设施类型,就需要修改所有现有的访问者类,添加相应的visit方法。这违反了"开闭原则"。其次,访问者模式要求元素类的内部结构对访问者是可见的。比如检查员需要知道过山车的最高速度、旋转木马的承载人数等属性,这在某种程度上破坏了对象的封装性。
\quad 此外,使用访问者模式可能会导致系统变得更复杂。我们需要维护多个访问者类,它们之间可能存在一些交叉的职责。比如安全检查和维护工作可能会有重叠的检查项目,这时就需要考虑如何合理划分职责。

五、访问者模式的适用场景

\quad 访问者模式就像是一位经验丰富的管家,最适合处理"对象结构相对稳定,但操作多种多样"的场景。除了我们讨论的游乐园管理系统,它在许多其他领域也有着广泛的应用。
\quad 比如在编译器设计中,语法树的结构一旦确定就不会改变,但我们需要对语法树进行词法分析、语法分析、代码生成等多种操作。又如在文档处理系统中,文档结构(段落、章节、图表等)相对固定,但我们需要对文档进行打印、预览、格式转换等不同操作。
\quad 当你发现系统中有一个复杂的对象结构,而且经常需要对这些对象进行不同的操作时,不妨考虑使用访问者模式。但如果对象结构经常变动,或者操作比较单一,使用访问者模式可能会适得其反。

六、总结

\quad 访问者模式,讲究的是进退有度,相互尊重。它通过巧妙的设计,让数据结构与数据操作得以分离,就像是让每位访客都能以最适合的方式与主人互动。
\quad 在实际应用中,我们要明智地选择是否使用访问者模式。当面对稳定的对象结构和多变的操作需求时,访问者模式如同一位老成持重的管家,能够有条不紊地处理各种访客的需求。但如果对象结构经常变动,或者操作相对单一,使用访问者模式反而会使系统变得臃肿复杂。
\quad 正如古人云:万物有度,过犹不及。设计模式也是如此,关键在于找到最适合当前场景的解决方案。访问者模式,不过是我们设计工具箱中的一件利器,懂得何时使用,方能游刃有余。

在这里插入图片描述

关注犬余,共同进步

技术从此不孤单

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

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

相关文章

从0到机器视觉工程师(二):封装调用静态库和动态库

目录 静态库 编写静态库 使用静态库 方案一 方案二 动态库 编写动态库 使用动态库 方案一 方案二 方案三 总结 静态库 静态库是在编译时将库的代码合并到最终可执行程序中的库。静态库的优势是在编译时将所有代码包含在程序中&#xff0c;可以使程序独立运行&…

VisualStudio 2019 升级遇到的问题及解决

事件起因 今天计划想研究下.net core&#xff08;后面版本直接称为 .net &#xff09;,发现 .net sdk 5.0 最新版本安装不成功。解决之后&#xff0c;真是手欠&#xff0c;看着Visual Studio 2019 有更新了&#xff0c;就直接点击了&#xff0c;这时才发现问题大了。。。 安装…

Spring Boot教程之四十一:在 Spring Boot 中调用或使用外部 API

如何在 Spring Boot 中调用或使用外部 API&#xff1f; Spring Boot 建立在 Spring 之上&#xff0c;包含 Spring 的所有功能。它现在越来越受到开发人员的青睐&#xff0c;因为它是一个快速的生产就绪环境&#xff0c;使开发人员能够直接专注于逻辑&#xff0c;而不必费力配置…

HTML5实现好看的新年春节元旦网站源码

HTML5实现好看的新年春节元旦网站源码 前言一、设计来源1.1 主界面1.2 新年由来界面1.3 文章详细界面1.4 登录界面1.5 注册界面1.6 新年图册界面1.7 联系我们界面 二、效果和源码2.1 动态效果2.2 源代码 源码下载结束语 HTML5实现好看的新年春节元旦网站源码&#xff0c;春节新…

Python学习(5):数据结构

1 列表 1.1 列表方法 列表数据类型支持很多方法&#xff0c;列表对象的所有方法所示如下&#xff1a; list.append(x)&#xff1a;在列表末尾添加一项。 类似于 a[len(a):] [x]。list.extend(iterable)&#xff1a;通过添加来自 iterable 的所有项来扩展列表。 类似于 a[len…

2021.12.28基于UDP同信的相关流程

作业 1、将TCP的CS模型再敲一遍 服务器 #include <myhead.h> #define PORT 8888 #define IP "192.168.124.123" int main(int argc, const char *argv[]) {//创建套接字//绑定本机IP和端口号//监听客户端请求//接收客户端连接请求//收发消息//创建套接字int…

2024年RAG:回顾与展望

2024年&#xff0c;RAG&#xff08;Retrieval-Augmented Generation&#xff09;技术经历了从狂热到理性的蜕变&#xff0c;成为大模型应用领域不可忽视的关键力量。年初&#xff0c;AI的“无所不能”让市场充满乐观情绪&#xff0c;RAG被视为解决复杂问题的万能钥匙&#xff1…

Python 爬虫

一、创建项目 1.双击打开pycharm&#xff0c;点击新建项目 2.项目设置- 勾选[继承全局站点软件包]- 勾选[可用于所有项目]- 取消勾选[创建main.py欢迎脚本]- 点击创建 3.项目名称右键--新建--python文件 4.输入文件名--回车二、编辑代码 # 导入请求模块 import requests # 如…

idea项目导入gitee 码云

1、安装gitee插件 IDEA 码云插件已由 gitosc 更名为 gitee。 1 在码云平台帮助文档http://git.mydoc.io/?t153739上介绍的很清楚&#xff0c;推荐前两种方法&#xff0c; 搜索码云插件的时候记得名字是gitee&#xff0c;gitosc已经搜不到了。 2、使用码云托管项目 如果之…

基于JAVA+SpringBoot+Vue的机动车号牌管理系统

基于JAVASpringBootVue的机动车号牌管理系统 前言 ✌全网粉丝20W,csdn特邀作者、博客专家、CSDN[新星计划]导师、java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末附源码下载链接&#x1f345; …

活动预告 |【Part1】Microsoft Azure 在线技术公开课:基础知识

课程介绍 参加“Azure 在线技术公开课&#xff1a;基础知识”活动&#xff0c;培养有助于创造新的技术可能性的技能并探索基础云概念。参加我们举办的本次免费培训活动&#xff0c;扩充自身的云模型和云服务类型知识。你还可以查看以计算、网络和存储为核心的 Azure 服务。 活…

郑州时空-TMS运输管理系统 GetDataBase 信息泄露漏洞复现

0x01 产品简介 郑州时空-TMS运输管理系统是一款专为物流运输企业设计的综合性管理软件,旨在提高运输效率、降低运输成本,并实现供应链的协同运作。系统基于现代计算机技术和物流管理方法,结合了郑州时空公司的专业经验和技术优势,为物流运输企业提供了一套高效、智能的运输…

BUUCTF Pwn ciscn_2019_es_2 WP

1.下载 checksec 用IDA32打开 定位main函数 发现了个假的后门函数&#xff1a; 看看vul函数&#xff1a; 使用read读取 想到栈溢出 但是只有48个 只能覆盖EBP和返回地址 长度不够构造 所以使用栈迁移&#xff1a; 栈迁移需要用到leave ret 使用ROPgadget找地址&#xff1a; …

07-ArcGIS For JavaScript--隐藏参数qualitySettings(memory和lod控制)

目录 1、综述2、sceneview.qualitySettings2.1、sceneview.qualitySettings.memoryLimit2.2、lodFactor2.3 additionalCacheMemory 3、结论 1、综述 先上重点&#xff0c;SceneView.qualitySettings为隐藏对象参数&#xff0c;该对象的memoryLimit和lodFactor等值&#xff0c;…

【SQL Server】教材数据库(1)

1 利用sql建立教材数据库&#xff0c;并定义以下基本表&#xff1a; 学生&#xff08;学号&#xff0c;年龄&#xff0c;性别&#xff0c;系名&#xff09; 教材&#xff08;编号&#xff0c;书名&#xff0c;出版社编号&#xff0c;价格&#xff09; 订购&#xff08;学号…

RP2040 C SDK I2C外设使用

RP2040 C SDK I2C外设使用 &#x1f4cc;相关篇《RP2040 VSCode C/C开发环境快速部署》&#x1f4cd;I2C API 外设&#xff1a;https://www.raspberrypi.com/documentation/pico-sdk/hardware.html#group_hardware_i2c&#x1f527;驱动I2C ssd1306 屏幕需要使用到的库&#xf…

模仿微信小程序wx.showModal自定义弹窗,内容可以修改

实现以下弹框样式功能 1.在components新建一个文件showModel.wpy作为组件&#xff0c;复制下面代码 <style lang"less" scoped> .bg_model {display: flex;justify-content: center;align-items: center;// 弹框背景.bg_hui {width: 100%;height: 100%;posi…

WebP Vs. PNG:哪种图像格式适合您的网站?

图像对任何网站都至关重要,可以增强视觉吸引力和用户体验。但是,图像也会显着影响网站的加载时间,因此必须针对 Web 使用对其进行优化。一种方法是使用正确的图像格式。

mysql乱码、mysql数据中文问号

网上排出此错误方法的很多&#xff0c;但是 都不简洁&#xff0c;找不到根本原因 主要排查两点&#xff1a; 1.代码中jdbc链接的编码规则 urljdbc:mysql://localhost:3306/title?useUnicodetrue&amp;characterEncodingutf8 将characterEncoding设置为utf8 2.设置mysq…

INT303 Big Data Analytics 笔记

Lecture1 Introduction 不考&#xff01; “Data Mining is the study of collecting, processing, analyzing, and gaining useful insights from data” EXPLORATORY ANALYSIS Make measurements to understand what the data looks like first steps when collecting da…