Go和Java实现访问者模式
Go和Java实现访问者模式
我们下面通过一个解压和压缩各种类型的文件的案例来说明访问者模式的使用。
1、访问者模式
在访问者模式中,我们使用了一个访问者类,它改变了元素类的执行算法。通过这种方式,元素的执行算法可以随
着访问者改变而改变。这种类型的设计模式属于行为型模式。根据模式,元素对象已接受访问者对象,这样访问者
对象就可以处理元素对象上的操作。
-
意图:主要将数据结构与数据操作分离。
-
主要解决:稳定的数据结构和易变的操作耦合问题。
-
何时使用:需要对一个对象结构中的对象进行很多不同的并且不相关的操作,而需要避免让这些操作"污染"这
些对象的类,使用访问者模式将这些封装到类中。
-
如何解决:在被访问的类里面加一个对外提供接待访问者的接口。
-
关键代码:在数据基础类里面有一个方法接受访问者,将自身引用传入访问者。
-
应用实例:您在朋友家做客,您是访问者,朋友接受您的访问,您通过朋友的描述,然后对朋友的描述做出一
个判断,这就是访问者模式。
-
优点:1、符合单一职责原则。 2、优秀的扩展性。 3、灵活性。
-
缺点:1、具体元素对访问者公布细节,违反了迪米特原则。 2、具体元素变更比较困难。 3、违反了依赖倒
置原则,依赖了具体类,没有依赖抽象。
-
使用场景:1、对象结构中对象对应的类很少改变,但经常需要在此对象结构上定义新的操作。 2、需要对一
个对象结构中的对象进行很多不同的并且不相关的操作,而需要避免让这些操作"污染"这些对象的类,也不希
望在增加新操作时修改这些类。
-
注意事项:访问者可以对功能进行统一,可以做报表、UI、拦截器与过滤器。
-
适用性:
一个对象结构包含很多类对象,它们有不同的接口,而你想对这些对象实施一些依赖于其具体类的操作。
需要对一个对象结构中的对象进行很多不同的并且不相关的操作,让你想避免让这些操作污染这些对象的类。
Visitor使得你可以将相关的操作集中起来定义在一个类中,当该对象结构被很多应用共享时,用Visitor模
式让每个应用仅包含需要用到的操作。
定义对象结构的类很少改变,但经常需要在此结构上定义新的操作。改变对象结构类需要重定义对所有访问者
的接口,这可能想要很大的代价。如果对象结构类经常改变,那么可能还是在这些类中定义这些操作较好。
2、Go实现访问者模式
package visitor// ========== 访问者FileUseVisitor ==========
type FileUseVisitor interface {// 为每一个类声明一个visit操作visitPdfFile(FileResourceVisitable)visitPPTFile(FileResourceVisitable)visitTextFile(FileResourceVisitable)
}
package visitorimport "fmt"// ========== 访问者Compress ==========
type Compress struct {
}func (compress *Compress) visitPdfFile(fileResourceVisitable FileResourceVisitable) {fmt.Println("Compress file: " + fileResourceVisitable.(*PdfFile).Path)
}func (compress *Compress) visitPPTFile(fileResourceVisitable FileResourceVisitable) {fmt.Println("Compress file: " + fileResourceVisitable.(*PPTFile).Path)
}func (compress *Compress) visitTextFile(fileResourceVisitable FileResourceVisitable) {fmt.Println("Compress file: " + fileResourceVisitable.(*TextFile).Path)
}
package visitorimport "fmt"// ========== 访问者Decompress ==========
type Decompress struct {
}func (decompress *Decompress) visitPdfFile(fileResourceVisitable FileResourceVisitable) {fmt.Println("Decompress file: " + fileResourceVisitable.(*PdfFile).Path)
}func (decompress *Decompress) visitPPTFile(fileResourceVisitable FileResourceVisitable) {fmt.Println("Decompress file: " + fileResourceVisitable.(*PPTFile).Path)
}func (decompress *Decompress) visitTextFile(fileResourceVisitable FileResourceVisitable) {fmt.Println("Decompress file: " + fileResourceVisitable.(*TextFile).Path)
}
package visitor// ========== 接收者FileResourceVisitable ==========
type FileResourceVisitable interface {accept(FileUseVisitor)
}
package visitor// ========== 接收者PdfFile ==========
type PdfFile struct {Path string
}func (pdfFile *PdfFile) accept(fileUseVisitor FileUseVisitor) {fileUseVisitor.visitPdfFile(pdfFile)
}
package visitor// ========== 接收者PPTFile ==========
type PPTFile struct {Path string
}func (pPTFile *PPTFile) accept(fileUseVisitor FileUseVisitor) {fileUseVisitor.visitPPTFile(pPTFile)
}
package visitor// ========== 接收者TextFile ==========
type TextFile struct {Path string
}func (textFile *TextFile) accept(fileUseVisitor FileUseVisitor) {fileUseVisitor.visitTextFile(textFile)
}
package visitor// ========== FileStructure ==========
type FileStructure struct {fileResourceVisitableList []FileResourceVisitable
}func (fileStructure *FileStructure) Attach(fileResourceVisitable FileResourceVisitable) {fileStructure.fileResourceVisitableList = append(fileStructure.fileResourceVisitableList, fileResourceVisitable)
}func (fileStructure *FileStructure) Detach(fileResourceVisitable FileResourceVisitable) {for i := 0; i < len(fileStructure.fileResourceVisitableList); i++ {if fileStructure.fileResourceVisitableList[i] == fileResourceVisitable {fileStructure.fileResourceVisitableList = append(fileStructure.fileResourceVisitableList[:i], fileStructure.fileResourceVisitableList[i+1:]...)}}
}func (fileStructure *FileStructure) Accept(fileUseVisitor FileUseVisitor) {for _, fileResourceVisitable := range fileStructure.fileResourceVisitableList {fileResourceVisitable.accept(fileUseVisitor)}
}
package mainimport . "proj/visitor"func main() {fileStructure := FileStructure{}fileStructure.Attach(&PPTFile{Path: "test.ppt"})fileStructure.Attach(&PdfFile{Path: "test.pdf"})fileStructure.Attach(&TextFile{Path: "test.txt"})fileStructure.Accept(&Decompress{})fileStructure.Accept(&Compress{})
}
# 输出
Decompress file: test.ppt
Decompress file: test.pdf
Decompress file: test.txt
Compress file: test.ppt
Compress file: test.pdf
Compress file: test.txt
3、Java实现访问者模式
package com.visitor;// ========== 访问者FileUseVisitor ==========
public interface FileUseVisitor {// 为每一个类声明一个visit操作void visitPdfFile(FileResourceVisitable fileResourceVisitable);void visitPPTFile(FileResourceVisitable fileResourceVisitable);void visitTextFile(FileResourceVisitable fileResourceVisitable);
}
package com.visitor;// ========== 访问者Compress ==========
public class Compress implements FileUseVisitor{@Overridepublic void visitPdfFile(FileResourceVisitable fileResourceVisitable) {System.out.println("Compress file: "+fileResourceVisitable.path);}@Overridepublic void visitPPTFile(FileResourceVisitable fileResourceVisitable) {System.out.println("Compress file: "+fileResourceVisitable.path);}@Overridepublic void visitTextFile(FileResourceVisitable fileResourceVisitable) {System.out.println("Compress file: "+fileResourceVisitable.path);}
}
package com.visitor;// ========== 访问者Decompress ==========
public class Decompress implements FileUseVisitor{@Overridepublic void visitPdfFile(FileResourceVisitable fileResourceVisitable) {System.out.println("Decompress file: "+fileResourceVisitable.path);}@Overridepublic void visitPPTFile(FileResourceVisitable fileResourceVisitable) {System.out.println("Decompress file: "+fileResourceVisitable.path);}@Overridepublic void visitTextFile(FileResourceVisitable fileResourceVisitable) {System.out.println("Decompress file: "+fileResourceVisitable.path);}
}
package com.visitor;// ========== 接收者FileResourceVisitable ==========
public abstract class FileResourceVisitable {protected String path;abstract void accept(FileUseVisitor fileUseVisitor);
}
package com.visitor;// ========== 接收者PdfFile ==========
public class PdfFile extends FileResourceVisitable {public PdfFile(String path){this.path = path;}@Overridepublic void accept(FileUseVisitor fileUseVisitor) {fileUseVisitor.visitPdfFile(this);}
}
package com.visitor;// ========== 接收者PPTFile ==========
public class PPTFile extends FileResourceVisitable {public PPTFile(String path){this.path = path;}@Overridepublic void accept(FileUseVisitor fileUseVisitor) {fileUseVisitor.visitPPTFile(this);}
}
package com.visitor;// ========== 接收者TextFile ==========
public class TextFile extends FileResourceVisitable {public TextFile(String path){this.path = path;}@Overridepublic void accept(FileUseVisitor fileUseVisitor) {fileUseVisitor.visitTextFile(this);}
}
package com.visitor;import java.util.ArrayList;
import java.util.List;
import java.util.Objects;// ========== FileStructure ==========
public class FileStructure {List<FileResourceVisitable> fileResourceVisitableList = new ArrayList<>();public void attach(FileResourceVisitable fileResourceVisitable){fileResourceVisitableList.add(fileResourceVisitable);}public void detach(FileResourceVisitable fileResourceVisitable){Objects.requireNonNull(fileResourceVisitable);}public void accept(FileUseVisitor fileUseVisitor){for(FileResourceVisitable fileResourceVisitable:fileResourceVisitableList){fileResourceVisitable.accept(fileUseVisitor);}}
}
package com.visitor;public class Test {public static void main(String[] args) {FileStructure fileStructure = new FileStructure();fileStructure.attach(new PPTFile("test.pdf"));fileStructure.attach(new PdfFile("test.pdf"));fileStructure.attach(new TextFile("test.txt"));fileStructure.accept(new Compress());fileStructure.accept(new Decompress());}
}
# 输出
Compress file: test.pdf
Compress file: test.pdf
Compress file: test.txt
Decompress file: test.pdf
Decompress file: test.pdf
Decompress file: test.txt
相关文章:
Go和Java实现访问者模式
Go和Java实现访问者模式 我们下面通过一个解压和压缩各种类型的文件的案例来说明访问者模式的使用。 1、访问者模式 在访问者模式中,我们使用了一个访问者类,它改变了元素类的执行算法。通过这种方式,元素的执行算法可以随 着访问者改变而…...
想要通过软件测试的面试,都需要学习哪些知识
很多人认为,软件测试是一个简单的职位,职业生涯走向也不会太好,但是随着时间的推移,软件测试行业的变化,人们开始对软件测试行业的认知有了新的高度,越来越多的人开始关注这个行业,开始重视这个…...
MySQL的索引使用的数据结构,事务知识
一、索引的数据结构🌸 索引的数据结构(非常重要) mysql的索引的数据结构,并非定式!!!取决于MySQL使用哪个存储引擎 数据库这块组织数据使用的数据结构是在硬盘上的。我们平时写的代码是存在内存…...
普及100Hz高刷+1ms响应 微星发布27寸显示器:仅售799元
不论办公还是游戏,高刷及低响应时间都很重要,微星现在推出了一款27寸显示器PRO MP273A, 售价只有799元,但支持100Hz高刷、1ms响应时间,还有FreeSync技术减少撕裂。 PRO MP273A的100Hz高刷新率是其最大的卖点之一&#…...
Java课题笔记~6个重要注解参数含义
1、[掌握]Before 前置通知-方法有 JoinPoint 参数 在目标方法执行之前执行。被注解为前置通知的方法,可以包含一个 JoinPoint 类型参数。 该类型的对象本身就是切入点表达式。通过该参数,可获取切入点表达式、方法签名、目标对象等。 不光前置通知的方…...
Windows Docker Desk环境时区问题导致的时间问题解决?
大多docker镜像为了保持镜像大小,采用了alpine linux。 但经常由于时区问题导致时间不准确,解决也很简单。 1.查看事件文件 cd /usr/share/zoneinfo 2.复制时区文件 将文件copy到 /etc/localtime 路径下即可(重庆时区,上海也…...
SpringBoot复习:(22)ConfigurationProperties和@PropertySource配合使用及JSR303校验
一、配置类 package cn.edu.tju.config;import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.context.annotation.PropertySource; import org.springframework.stereotype.Component;Component ConfigurationPropertie…...
Spring IoC (控制反转)
IoC 是 Inversion of Control 的简写,译为“控制反转”,它不是一门技术,而是一种设计思想,是一个重要的面向对象编程法则。 Spring 通过 IoC 容器来管理所有 Java 对象的实例化和初始化,控制对象与对象之间的依赖关系。…...
安卓下模拟渲染EGLImageKHR
创建AHardwareBuffer并填充颜色 AHardwareBuffer_Desc desc = {static_cast<uint32_t>(screenW),static_cast<uint32_t>(screenH),...
Spring MVC 框架学习总结
文章目录 初步认识 Spring MVC 框架 一、初识 Spring MVC 框架 二、 三、 四、 五、 六、 七、 八、 九、...
2、简单上手+el挂载点+v-xx(v-text、v-html、v-on、v-show、v-if、v-bind、v-for)
官网: vue3:https://cn.vuejs.org/ vue2:https://v2.cn.vuejs.org/v2/guide/ 简单上手: 流程: 导入开发版本的Vue.js <!--开发环境版本,包含了有帮助的命令行警告--> <script src"https…...
C++初阶语法——命名空间
前言:C,即cplusplus,顾名思义,是C语言promax版本,C兼容C语言。 C的诞生是因为贝尔实验室的本贾尼等大佬认为C语言的语法坑实在太多,拥有许多不足之处(比如命名冲突,)&…...
Axwing.878 线性同余方程
题目 给定n组数据ai, bi , mi,对于每组数求出一个xi,使其满足ai * xibi (mod mi),如果无解则输出impossible。 输入格式 第一行包含整数n。 接下来n行,每行包含一组数据ai , bi , mi。 输出格式 输出共n行,每组数…...
【Pytorch+torchvision】MNIST手写数字识别
深度学习入门项目,含代码详细解析 在本文中,我们将在PyTorch中构建一个简单的卷积神经网络,并使用MNIST数据集训练它识别手写数字。 MNIST包含70,000张手写数字图像: 60,000张用于培训,10,000张用于测试。图像是灰度(即…...
spring boot 集成rocketmq
集成Spring Boot和RocketMQ 在现代的微服务架构中,消息队列已经成为一种常见的异步处理模式,它能解决服务间的同步调用、耦合度高、流量高峰等问题。RocketMQ是阿里巴巴开源的一款消息中间件,性能优秀,功能齐全,被广泛…...
redis Hash类型命令
Redis中的Hash类型有多个常用命令可用于对Hash键进行操作。以下是一些常见的Redis Hash类型命令: HSET:设置Hash字段的值。 它将指定字段与相应的值关联起来,如果字段已经存在,则更新其值,如果字段不存在,…...
P1194 买礼物(最小生成树)(内附封面)
买礼物 题目描述 又到了一年一度的明明生日了,明明想要买 B B B 样东西,巧的是,这 B B B 样东西价格都是 A A A 元。 但是,商店老板说最近有促销活动,也就是: 如果你买了第 I I I 样东西࿰…...
oracle基础语法和备份恢复
Oracle总结 sql命令分类 1.DDL,数据定义语言,create创建/drop销毁 2.DCL,数据库控制语言,grant授权/revoke撤销 3.DML,数据操纵语言,insert/update/delete等sql语句 4.DQL,数据查询语言&am…...
【MATLAB第66期】#源码分享 | 基于MATLAB的PAWN全局敏感性分析模型(有条件参数和无条件参数)
【MATLAB第66期】#源码分享 | 基于MATLAB的PAWN全局敏感性分析模型(有条件参数和无条件参数) 文献参考 Pianosi, F., Wagener, T., 2015. A simple and efficient method for global sensitivity analysis based on cumulative distribution functions.…...
vue2过渡vue3技术差异点指南
基础点 reactive() 定义响应式变量(仅仅引用类型有效:对象数组map,set):reactive(),类似于data中return的数据 例子: import { reactive } from vueexport default {setup() {const state reactive({ count: 0 })function in…...
eNSP-Cloud(实现本地电脑与eNSP内设备之间通信)
说明: 想象一下,你正在用eNSP搭建一个虚拟的网络世界,里面有虚拟的路由器、交换机、电脑(PC)等等。这些设备都在你的电脑里面“运行”,它们之间可以互相通信,就像一个封闭的小王国。 但是&#…...
装饰模式(Decorator Pattern)重构java邮件发奖系统实战
前言 现在我们有个如下的需求,设计一个邮件发奖的小系统, 需求 1.数据验证 → 2. 敏感信息加密 → 3. 日志记录 → 4. 实际发送邮件 装饰器模式(Decorator Pattern)允许向一个现有的对象添加新的功能,同时又不改变其…...
中南大学无人机智能体的全面评估!BEDI:用于评估无人机上具身智能体的综合性基准测试
作者:Mingning Guo, Mengwei Wu, Jiarun He, Shaoxian Li, Haifeng Li, Chao Tao单位:中南大学地球科学与信息物理学院论文标题:BEDI: A Comprehensive Benchmark for Evaluating Embodied Agents on UAVs论文链接:https://arxiv.…...
在HarmonyOS ArkTS ArkUI-X 5.0及以上版本中,手势开发全攻略:
在 HarmonyOS 应用开发中,手势交互是连接用户与设备的核心纽带。ArkTS 框架提供了丰富的手势处理能力,既支持点击、长按、拖拽等基础单一手势的精细控制,也能通过多种绑定策略解决父子组件的手势竞争问题。本文将结合官方开发文档,…...
抖音增长新引擎:品融电商,一站式全案代运营领跑者
抖音增长新引擎:品融电商,一站式全案代运营领跑者 在抖音这个日活超7亿的流量汪洋中,品牌如何破浪前行?自建团队成本高、效果难控;碎片化运营又难成合力——这正是许多企业面临的增长困局。品融电商以「抖音全案代运营…...
相机从app启动流程
一、流程框架图 二、具体流程分析 1、得到cameralist和对应的静态信息 目录如下: 重点代码分析: 启动相机前,先要通过getCameraIdList获取camera的个数以及id,然后可以通过getCameraCharacteristics获取对应id camera的capabilities(静态信息)进行一些openCamera前的…...
C# 类和继承(抽象类)
抽象类 抽象类是指设计为被继承的类。抽象类只能被用作其他类的基类。 不能创建抽象类的实例。抽象类使用abstract修饰符声明。 抽象类可以包含抽象成员或普通的非抽象成员。抽象类的成员可以是抽象成员和普通带 实现的成员的任意组合。抽象类自己可以派生自另一个抽象类。例…...
HTML前端开发:JavaScript 常用事件详解
作为前端开发的核心,JavaScript 事件是用户与网页交互的基础。以下是常见事件的详细说明和用法示例: 1. onclick - 点击事件 当元素被单击时触发(左键点击) button.onclick function() {alert("按钮被点击了!&…...
【JavaSE】绘图与事件入门学习笔记
-Java绘图坐标体系 坐标体系-介绍 坐标原点位于左上角,以像素为单位。 在Java坐标系中,第一个是x坐标,表示当前位置为水平方向,距离坐标原点x个像素;第二个是y坐标,表示当前位置为垂直方向,距离坐标原点y个像素。 坐标体系-像素 …...
代理篇12|深入理解 Vite中的Proxy接口代理配置
在前端开发中,常常会遇到 跨域请求接口 的情况。为了解决这个问题,Vite 和 Webpack 都提供了 proxy 代理功能,用于将本地开发请求转发到后端服务器。 什么是代理(proxy)? 代理是在开发过程中,前端项目通过开发服务器,将指定的请求“转发”到真实的后端服务器,从而绕…...
