设计模式1-访问者模式

访问者模式是一种行为设计模式,它允许你定义在对象结构中的元素上进行操作的新操作,而无需修改这些元素的类。这种模式的主要思想是将算法元素的结构分离开,使得可以在不修改元素结构的情况下定义新的操作。

所谓算法与元素结构分离,即保持元素(被访问对象)结构的稳定,而将算法置于访问者之中,因为访问者可以新建,这样就符合了OCP(开闭原则)。

在访问者模式中,有两个主要的角色:

  1. 访问者(Visitor)
    定义了在对象结构中访问元素时的新操作接口。通常会有多个不同的访问者,每个访问者实现一组特定的操作。

  2. 元素(Element)
    定义了接受访问者的接口,通常会有多个不同的元素,每个元素实现了接口并提供了接受访问者的方法。

访问者模式的主要优势在于当需要在一组对象上执行一些复杂的操作时,你可以通过添加新的访问者而不是修改每个元素的类来扩展系统。

类图:

下面是一个简单的 Java 示例,演示了访问者模式的基本结构:

// 访问者接口
interface Visitor {void visit(ElementA elementA);void visit(ElementB elementB);
}// 元素接口
interface Element {void accept(Visitor visitor);
}// 具体的元素A
class ElementA implements Element {@Overridepublic void accept(Visitor visitor) {visitor.visit(this);}// 元素A的特定操作void operationA() {System.out.println("Performing operation A on ElementA");}
}// 具体的元素B
class ElementB implements Element {@Overridepublic void accept(Visitor visitor) {visitor.visit(this);}// 元素B的特定操作void operationB() {System.out.println("Performing operation B on ElementB");}
}// 具体的访问者
class ConcreteVisitor implements Visitor {@Overridepublic void visit(ElementA elementA) {elementA.operationA();}@Overridepublic void visit(ElementB elementB) {elementB.operationB();}
}// 客户端代码
public class VisitorPatternExample {public static void main(String[] args) {Element elementA = new ElementA();Element elementB = new ElementB();Visitor visitor = new ConcreteVisitor();elementA.accept(visitor); // 执行 ElementA 的操作elementB.accept(visitor); // 执行 ElementB 的操作}
}

在这个例子中,Visitor 接口定义了两个访问方法,每个方法对应一个具体的元素。Element 接口定义了接受访问者的方法。具体的元素类 ElementAElementB 实现了 Element 接口,并分别实现了自己的特定操作。ConcreteVisitor 是一个具体的访问者类,实现了对每个元素的访问操作。

在客户端代码中,我们创建了一个 ConcreteVisitor 实例,并让每个元素接受这个访问者。换言之,是在Client中操作了访问者与元素的连接印证了类图。这样,通过不同的访问者,我们可以执行不同的操作,而不需要修改元素的类。这是访问者模式的一种简单示例,实际中可能涉及更复杂的场景和多个元素。

怎么定义新的操作?

当使用访问者模式时,定义新的操作就是创建新的实现了访问者接口的具体访问者类。每个具体访问者类负责实现一组特定的操作,而这些操作可以是全新的、与原有操作不相关的,或者是对现有操作的扩展。

举个例子,假设我们有一个图形结构,包括圆形(Circle)和矩形(Rectangle)两种图形。现在我们希望实现两种不同的操作:计算图形的面积和计算图形的周长。

首先,定义图形接口和具体的图形类:

// 图形接口
interface Shape {void accept(Visitor visitor);
}// 圆形类
class Circle implements Shape {private double radius;public Circle(double radius) {this.radius = radius;}public double getRadius() {return radius;}@Overridepublic void accept(Visitor visitor) {visitor.visit(this);}
}// 矩形类
class Rectangle implements Shape {private double width;private double height;public 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 AreaCalculator implements Visitor {@Overridepublic void visit(Circle circle) {double area = Math.PI * circle.getRadius() * circle.getRadius();System.out.println("Area of Circle: " + area);}@Overridepublic void visit(Rectangle rectangle) {double area = rectangle.getWidth() * rectangle.getHeight();System.out.println("Area of Rectangle: " + area);}
}// 计算周长的具体访问者类
class PerimeterCalculator implements Visitor {@Overridepublic void visit(Circle circle) {double perimeter = 2 * Math.PI * circle.getRadius();System.out.println("Perimeter of Circle: " + perimeter);}@Overridepublic void visit(Rectangle rectangle) {double perimeter = 2 * (rectangle.getWidth() + rectangle.getHeight());System.out.println("Perimeter of Rectangle: " + perimeter);}
}

现在我们可以在不修改图形类的情况下定义新的操作。例如,创建了两个具体的访问者类 AreaCalculatorPerimeterCalculator 分别用于计算图形的面积和周长。在客户端代码中,我们可以通过接受不同的访问者来执行不同的操作:

public class VisitorExample {public static void main(String[] args) {Shape circle = new Circle(5);Shape rectangle = new Rectangle(4, 6);Visitor areaCalculator = new AreaCalculator();Visitor perimeterCalculator = new PerimeterCalculator();circle.accept(areaCalculator); // 计算圆形的面积circle.accept(perimeterCalculator); // 计算圆形的周长rectangle.accept(areaCalculator); // 计算矩形的面积rectangle.accept(perimeterCalculator); // 计算矩形的周长}
}

这样,通过定义不同的访问者,我们可以轻松地扩展系统,而无需修改图形类的结构。

结论:

访问者模式很好地实现了访问算法开放被访问元素封闭,有这种需求时就可以考虑使用访问者模式。

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

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

相关文章

极速上手:使用Jmeter轻松实现N种参数化

参数化的方式: 一、使用用户自定义变量 一种方式:直接在测试计划中添加用户自定义变量 另外一种方式:配置元件——用户自定义变量 示例:用户自定义变量,登录手机号码 在接口请求的时候,进行引用 请求之后&…

32ADC模数转换器&AD单通道&多通道

目录 一.简介 二.逐次逼近法​编辑 三.结构框图 四.小tips (1)转换模式 (2)触发控制 (3)数据对齐 (4)转换时间 (5)校准 (6)硬件电路 五.相关函数 …

vue使用es的reduce方法编译报错Error: Can‘t resolve ‘core-js/modules/es.array.reduce.js‘

哈喽 大家好啊 最近在vue使用es的reduce方法编译报错Error: Cant resolve core-js/modules/es.array.reduce.js 报错如图所示: 解决方案: npm install --save core-js 然后重新编译下将正常了 参考原文: 使用import异步加载语法报错_module not foun…

Android Split APK介绍

文章目录 Split APKSplit APK 详细介绍概念Android App Bundle(AAB)Split APK 的优势动态分发减小安装包大小模块化和渠道分发 Split APK 的类型基于屏幕密度### 基于 CPU 架构基于语言 实现 Split APK Split APK Split APK 是 Android 中一种应用程序安…

SpringBoot实战第二天

今日战报 继续完善用户相关接口开发: 1.完成获取用户信息功能 2.完成更新用户信息功能 3.完成更新用户头像功能 4.完成更新用户密码功能 获取用户信息 接口文档 如接口文档所示,我们需要做的就是从header中的Authorization中读取token,解码…

问题:测风站应设置在平直的巷道中,其前后()范围内不得有障碍物和拐弯等局部阻力。 #微信#媒体

问题:测风站应设置在平直的巷道中,其前后()范围内不得有障碍物和拐弯等局部阻力。 参考答案如图所示

stable-diffusion | v1-5-pruned.ckpt和v1-5-pruned-emaonly.ckpt的区别

https://github.com/runwayml/stable-diffusion?tabreadme-ov-file#reference-sampling-script 对于 1.5 模型,其中可能包括四部分:标准模型、文本编码器、VAE模型、EMA模型。 标准模型:生成图片的核心模块,潜空间中的前向扩散和…

C语言中那些后知后觉的细节冷知识(二)typedef、死循环、位移、内存访问

系列文章目录 C语言中那些后知后觉的细节冷知识(一)static、const、volatile、数组、宏 C语言中那些后知后觉的细节冷知识(二)typedef、死循环、位移、内存访问 持续更新中… … 文章目录 系列文章目录前言一、typedef二、死循环…

Qt之漂亮的地球

这个画的是一个东西围绕着中心的地球不停的旋转,可以放在界面的中部,增加美感。 展示 界面展示 设计过程 标题在之前的博客有写过,这里不再重复 下面是关于地球旋转的相关 1.资源文件添加 先将相关的资源文件添加,三个图片 2…

【lesson32】MySQL用户管理

文章目录 用户管理介绍用户用户信息创建用户 删除用户修改用户密码数据库的权限给用户授权回收权限 用户管理介绍 用户 用户信息 MySQL中的用户,都存储在系统数据库mysql的user表中 //操作语法 mysql> use mysql; Database changed mysql> select host,use…

微信小程序封装wx.request以及小程序登录

1.封装wx.request const GET GET; const POST POST; const PUT PUT; const FORM FORM; const DELETE DELETE;const baseURL https://alimini.ck9696.com/wxmall; // const baseURL http://192.168.0.17:8601/wxmall; var app getApp(); function request(method, url…

VR全景技术可以应用在哪些行业,VR全景技术有哪些优势

引言: VR全景技术(Virtual Reality Panorama Technology)是一种以虚拟现实技术为基础,通过360度全景影像、立体声音、交互元素等手段,创造出沉浸式的虚拟现实环境。该技术不仅在娱乐领域有着广泛应用,还可…

ABAC模型简单介绍——通过casbin进行简单举例

ABAC模型简单介绍——通过casbin进行简单举例 文章目录 ABAC模型简单介绍——通过casbin进行简单举例定义相关术语Casbin实现ABAC(Python版)假设情境定义对象定义静态模型模板测试代码最终结果 相关链接 定义 Attribute Based Access Control (基于属性…

Git使用命令大全

命令大全参考阮一峰的博客,根据自己的使用习惯作了调整。 Git常用命令 其他常用的命令 配置Git # 显示当前的Git配置 $ git config --list# 编辑Git配置文件 $ git config -e [--global]# 设置提交代码时的用户信息 $ git config [--global] user.name "[nam…

第14章_视图

第14章_视图 1.常见的数据库对象 对象描述表(TABLE)表是存储数据的逻辑单元,以行和列的形式存在,列就是字段,行就是记录数据字典就是系统表,存放数据库相关信息的表。系统表的数据通常由数据库系统维护, 程序员通常不…

MDK Keil uVision5 cannot read project file 解决办法

MDK Keil uVision5 cannot read project file 解决办法 问题描述 我的系统重装过后是英文版的Windows 10,在打开别人/以前中文系统环境下保存的Keil Project文件(uvprojx文件)会报错,内容大致是 Cannot read project file D:\xx…

JAVA生成Word文档

第一步&#xff1a;导入依赖 <!--生成word文档--> <dependency><groupId>com.deepoove</groupId><artifactId>poi-tl</artifactId><version>1.10.3</version> </dependency> <!--数字转为汉字大写--> <depend…

《代码之丑》学习笔记18——写代码是一件可以一生精进的事

结束语 | 写代码是一件可以一生精进的事 文章目录 结束语 | 写代码是一件可以一生精进的事代码的敏感度 在很多人心目中&#xff0c;程序员是一个辛苦的职业&#xff0c;一方面&#xff0c;各种新东西层出不穷&#xff0c;程序员们要努力追随&#xff0c;另一方面&#xff0c;业…

十、VTK创建圆锥体vtkConeSource 带颜色

为圆锥体的每一面,添加一种颜色: 上述效果的代码: #include <vtkSmartPointer.h> #include <vtkPoints.h> #include <vtkLine.h> #include <vtkPolyData.h> #include <vtkPolyDataWriter.h> #include <vtkPolyDataMapper.h> #incl…

机器学习复习(6)——numpy的数学操作

加减法运算 # 创建两个不同的数组 a np.arange(4) #list(0,1,2,3 b np.array([5,10,15,20]) # 两个数组做减法运算 b-a 运行结果&#xff1a; 计算数组的平方 #b*2代表数组b每个元素乘以2 #b**2代表数组b每个元素的2次方 b**2 运行结果&#xff1a; 计算数组的正弦值 #…