技术成神之路:设计模式(十三)访问者模式

介绍

访问者模式(Visitor Pattern)是一种行为型设计模式,它允许你在不改变对象结构的前提下,定义作用于这些对象的新操作。这种模式通过将操作逻辑从对象结构中抽离出来,使得新的操作可以无缝地添加到现有对象中。

1.定义


访问者模式定义了一个访问者接口,它包含了访问不同元素的操作方法。具体的元素类接受访问者并调用相应的访问方法。通过这种分离,新增的操作可以直接通过访问者来实现,而不需要修改元素类。

2. 主要作用


  • 允许在不修改元素类的情况下,定义新的操作。
  • 提高了系统的可扩展性。
  • 避免了对复杂对象结构的直接修改。

3. 解决的问题


访问者模式解决了如何在不修改对象结构的情况下,向对象添加新的操作的问题。尤其在系统需要频繁添加新操作时,显得尤为重要。

4. 模式原理


包含角色:

  1. Visitor:定义了对各类元素对象的操作接口。
  2. ConcreteVisitor:实现Visitor接口,具体实现访问操作。
  3. Element:定义接受访问者的方法accept(), 通常由具体元素实现。
  4. ConcreteElement:实现Element接口,实现accept()方法。
  5. ObjectStructure:维护Element对象的集合,并提供遍历功能。

看到这么多的角色,就知道访问者模式并不简单,毕竟它是 《设计模式》中较为复杂的一个。不用怕,先以了解为主,因为它在实际开发中毕竟不常用。

UML类图:
在这里插入图片描述

示例:
假设我们有一个表示不同形状(如圆形和矩形)的对象结构,我们希望对这些形状执行不同的操作(如计算面积和绘制形状)。

定义形状接口和具体形状类:

// Shape接口
interface Shape {void accept(Visitor visitor);
}// 圆形类
class Circle implements Shape {double radius;Circle(double radius) {this.radius = radius;}public double getRadius() {return radius;}@Overridepublic void accept(Visitor visitor) {visitor.visit(this);}
}// 矩形类
class Rectangle implements Shape {double width;double height;Rectangle(double width, double height) {this.width = width;this.height = height;}public double getWidth() {return width;}public double getHeight() {return height;}@Overridepublic void accept(Visitor visitor) {visitor.visit(this);}
}

定义访问者接口和具体访问者类:

// 访问者接口
interface Visitor {void visit(Circle circle);void visit(Rectangle rectangle);
}// 具体访问者类 - 计算面积
class AreaVisitor implements Visitor {@Overridepublic void visit(Circle circle) {double area = Math.PI * circle.getRadius() * circle.getRadius();System.out.println("Circle area: " + area);}@Overridepublic void visit(Rectangle rectangle) {double area = rectangle.getWidth() * rectangle.getHeight();System.out.println("Rectangle area: " + area);}
}// 具体访问者类 - 绘制形状
class DrawVisitor implements Visitor {@Overridepublic void visit(Circle circle) {System.out.println("Drawing a Circle with radius " + circle.getRadius());}@Overridepublic void visit(Rectangle rectangle) {System.out.println("Drawing a Rectangle with width " + rectangle.getWidth() + " and height " + rectangle.getHeight());}
}

使用访问者模式:

public class VisitorPatternDemo {public static void main(String[] args) {Shape circle = new Circle(5);Shape rectangle = new Rectangle(4, 6);Visitor areaVisitor = new AreaVisitor();Visitor drawVisitor = new DrawVisitor();System.out.println("Calculating areas:");circle.accept(areaVisitor);rectangle.accept(areaVisitor);System.out.println("\nDrawing shapes:");circle.accept(drawVisitor);rectangle.accept(drawVisitor);}
}

打印输出:

Calculating areas:
Circle area: 78.53981633974483
Rectangle area: 24.0Drawing shapes:
Drawing a Circle with radius 5.0
Drawing a Rectangle with width 4.0 and height 6.0

说真的,写到这里我还是懵懵的,但隐约感觉这个设计不错,哈哈哈。

举个栗子,假如你是个想了解学生信息的老师(Visitor),你可以是班主任也可以是体育老师(ConcreteVisitor),因为他们的关注点不同(例如,班主任关注学生的学习成绩,体育老师关注学生的运动能力),学校里的不同类型的学生(Element),具体的学生(ConcreteElement)(例如文艺生A,运动生B)。

此时,假设我们有一个学校系统,其中有多种学生类型和评价标准。

  • 学生接口(Student):定义一个 accept(Visitor visitor) 方法。
  • 具体学生(SpecificStudent):实现 Student 接口,能够接受不同的访问者。
  • 访问者接口(Visitor):定义访问不同学生类型的方法,如 visit(ArtStudent artStudent)visit(SportsStudent sportsStudent)
  • 具体访问者(ConcreteVisitor):实现具体的访问逻辑,比如 AcademicEvaluator 关注学术成绩,PhysicalEducationEvaluator 关注体育表现。

回头再看一遍定义,访问者模式定义了一个访问者接口,它包含了访问不同元素的操作方法,此处的不同元素就是不同的学生,具体的元素类接受访问者并调用相应的访问方法,此处的相应的访问方法就是 学术成绩 和 体育表现,通过这种方式,可以在不改变学生对象结构的前提下,增加新的评价逻辑或操作,而不需要修改学生类本身。

到这里,是不是更进一步了解访问者模式了,不明白也不要紧,记住定义就行了。我突然想到我高中数学老师说的一句话:别管为啥这样写,你就记住,这样写就给分!哈哈。有时候不必太纠结,现在不明白 后面你也会明白的😉

5. 优缺点


优点:

  1. 扩展性强:新增功能时无需改动现有类。
  2. 操作集中:相关操作集中在访问者中,易于维护。

缺点:

  1. 增加复杂性:增加了类的数量,可能使系统变得复杂。
  2. 难以扩展元素:如果需要增加新的元素类,则需要修改访问者接口和所有具体访问者。

6. 应用场景


  • 当需要对一组对象进行不同的操作而又不希望修改这些对象时。
  • 需要对对象结构进行多种操作而操作逻辑复杂的情况下。
  • 系统中的对象结构比较复杂且稳定,而操作经常变化时。

7. 总结


访问者模式是一种强大的设计模式,可以方便地向对象结构中添加新的操作,而无需修改对象结构本身。然而,这种模式也有其局限性,主要在于它要求对象结构相对稳定,在对象结构频繁变化的系统中使用会增加维护成本。因此,在使用访问者模式时,需要根据具体情况权衡其优缺点,选择合适的应用场景。

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

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

相关文章

PDF转Excel小达人养成记

在现代职场,数据管理与格式转换可谓是日常任务的重头戏;有时我们手头有一份PDF文件,但需要将其中的数据整理成Excel表格,这该如何是好?别急,今天我就来给大家介绍几款好用的PDF转Excel工具,以及…

【CanMV K230 AI视觉】 人体关键点检测

【CanMV K230 AI视觉】 人体关键点检测 人体关键点检测 动态测试效果可以去下面网站自己看。 B站视频链接:已做成合集 抖音链接:已做成合集 人体关键点检测 人体关键点检测是指标注出人体关节等关键信息,分析人体姿态、运动轨迹、动作角度等…

【python】OpenCV—Age and Gender Classification

文章目录 1、任务描述2、网络结构2.1 人脸检测2.2 性别分类2.3 年龄分类 3、代码实现4、结果展示5、参考 1、任务描述 性别分类和年龄分类预测 2、网络结构 2.1 人脸检测 输出最高的 200 个 RoI,每个 RoI 7 个值,(xx,xx&#x…

chapter14-集合——(List-HashSet)——day18

目录 519-HashSet全面说明 520-数组链表模拟 521-HashSet扩容机制 重要 522-HashSet源码解读1 526-HashSet最佳实践 527-hashSet思考题 519-HashSet全面说明 题一、 两个tom都可以添加成功是因为这是两个对象 看源码做分析:不是直接指向常量池的吗?…

【Python篇】matplotlib超详细教程-由入门到精通(下篇)

文章目录 前言第六部分:保存与导出图表6.1 保存为图片文件示例:保存图表为 PNG 文件解释:关键点: 6.2 保存为高分辨率图片示例:保存为高分辨率图片解释: 6.3 保存为不同文件格式示例:保存为不同…

程序员问题社区

CSDN有问必答 – 程序员问题社区 ★★★★★ 点击我进入程序员问题社区 ★★★★★

OrionX GPU算力池助力AI OCR场景应用

01 AI OCR的历史及概念 OCR(Optical Character Recognition,光学字符识别)是指采用光学的方式将纸质文档中的文字转换成为黑白点阵的图像文件,通过检测暗、亮的模式确定其形状,然后用字符识别方法将形状翻译成计算机文…

ARM 工业计算机搭载 FUXA 组态软件:开启智能制造新时代

工业自动化已经成为提高生产效率、保证产品质量以及提升企业竞争力的关键因素。而在工业自动化的舞台上,FUXA 组态软件与 ARM 工业计算机的组合正发挥着越来越重要的作用,以其高效稳定、数据可视化、实时监控等优势,在复杂场景应用中展现出卓…

JavaScript第五天(函数,this,严格模式,高阶函数,闭包,递归,正则,ES6)高级

这里写目录标题 JavaScript高级第03天1.函数的定义和调用1.1函数的定义方式1.2函数的调用 2.this2.1函数内部的this指向2.2改变函数内部 this 指向2.2.1 call方法2.2.2 apply方法2.2.3 bind方法2.2.4 call、apply、bind三者的异同 3.严格模式3.1什么是严格模式3.2开启严格模式3…

opencv图像透视处理

引言 在图像处理与计算机视觉领域,透视变换(Perspective Transformation)是一种重要的图像校正技术,它允许我们根据图像中已知的四个点(通常是矩形的四个角)和目标位置的四个点,将图像从一个视…

【鸿蒙开发从0到1 day09】

鸿蒙开发基础-ArkUI基本布局 一 .设计资源-图标库1.阿里矢量图图标库2.HarmonyOS图标库 二.布局属性1.内边距2.外边距3.边框线4.边框圆角 三.背景属性1.背景颜色2.背景图片(1)背景图的缩放(2)背景图的显示位置 四.颜色渐变1.线性渐变2.径向渐变 五.阴影六.可选择链操作符(?)七…

如何更改磁盘卷标名称?

磁盘卷标(Volume Label)是用来标识和管理磁盘驱动器的名称,通常在文件资源管理器中显示。卷标有助于用户快速识别和区分不同的磁盘或分区。 为什么要更改磁盘卷标名称? 磁盘卷标作为磁盘的名字,可以帮助用户更容易地识…

通过C# 裁剪PDF页面

在处理PDF文档时,有时需要精确地裁剪页面以适应特定需求,比如去除广告、背景信息或者仅仅是为了简化文档内容。 本文将指导如何使用免费.NET控件通过C#实现裁剪PDF页面。 免费库 Free Spire.PDF for .NET 支持在 .NET (C#, VB.NET, ASP.NET, .NET Core)…

【特点】浅谈大模型的特点

在人工智能(AI)的发展历程中,大模型无疑是一个重要的里程碑。大模型是指利用海量数据,通过先进的算法和技术,训练得到的具有强大预测和决策能力的模型,这类模型具备了强大的语言理解和生成能力,能够完成各种复杂的自然…

搬运5款冷门但值得下载的PC软件

​ 分享5款冷门但值得下载的Windows软件,个个都很实用,你可能一个都没见过,但是我觉得你用过之后可能就再也离不开了。 1. 图片管理——Picasa ​ Picasa 是一款由谷歌开发的图片管理和编辑软件,能够帮助用户轻松地组织、编辑和…

电子邮件加密软件哪个好用?分享这五款加密工具,防范邮件泄密!2024企业必备!

"密语藏锋刃,安全重于山。" 在数字洪流中,电子邮件是企业沟通的重要桥梁,其安全性不容忽视。 因此,选择一款高效可靠的电子邮件加密软件,是企业保障信息安全的关键。 本文将为您推荐五款2024年企业必备的电…

基于SpringBoot+Vue+MySQL的垃圾分类回收管理系统

系统展示 用户前台界面 管理员后台界面 系统背景 二十一世纪互联网的出现,改变了几千年以来人们的生活,不仅仅是生活物资的丰富,还有精神层次的丰富。在互联网诞生之前,地域位置往往是人们思想上不可跨域的鸿沟,信息的…

Uniapp + Vite + Vue3 + uView + Pinia 实现自定义底部 Tabbar(最新保姆级教程)

Uniapp Vite Vue3 uView Pinia 实现自定义底部 Tabbar(最新保姆级教程) 1、效果展示2、环境准备2.1 新建 uniapp 项目2.2. 安装 uView2.3 安装 pinia 3. 配置环境4. 创建目录结构5、编写 pages.json 页面路由6、编写 tabbar.js 状态数据7、编写 tabb…

软件测试之压力测试

🍅 点击文末小卡片,免费获取软件测试全套资料,资料在手,涨薪更快 压力测试 压力测试是一种软件测试,用于验证软件应用程序的稳定性和可靠性。压力测试的目标是在极其沉重的负载条件下测量软件的健壮性和错误处理能力&…

日本IT工作内容---一篇梗概

日本IT工作现场是一个充满活力、技术导向且多元化的工作环境。以下是对日本IT工作内容的详细概述: 1. 软件开发(Software Engineering, SE) 主要任务:编写、测试和维护软件,以满足客户需求。这包括使用多种编程语言和…