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…...
C++初阶-list的底层
目录 1.std::list实现的所有代码 2.list的简单介绍 2.1实现list的类 2.2_list_iterator的实现 2.2.1_list_iterator实现的原因和好处 2.2.2_list_iterator实现 2.3_list_node的实现 2.3.1. 避免递归的模板依赖 2.3.2. 内存布局一致性 2.3.3. 类型安全的替代方案 2.3.…...
Lombok 的 @Data 注解失效,未生成 getter/setter 方法引发的HTTP 406 错误
HTTP 状态码 406 (Not Acceptable) 和 500 (Internal Server Error) 是两类完全不同的错误,它们的含义、原因和解决方法都有显著区别。以下是详细对比: 1. HTTP 406 (Not Acceptable) 含义: 客户端请求的内容类型与服务器支持的内容类型不匹…...
全球首个30米分辨率湿地数据集(2000—2022)
数据简介 今天我们分享的数据是全球30米分辨率湿地数据集,包含8种湿地亚类,该数据以0.5X0.5的瓦片存储,我们整理了所有属于中国的瓦片名称与其对应省份,方便大家研究使用。 该数据集作为全球首个30米分辨率、覆盖2000–2022年时间…...
华为OD机试-食堂供餐-二分法
import java.util.Arrays; import java.util.Scanner;public class DemoTest3 {public static void main(String[] args) {Scanner in new Scanner(System.in);// 注意 hasNext 和 hasNextLine 的区别while (in.hasNextLine()) { // 注意 while 处理多个 caseint a in.nextIn…...
【Zephyr 系列 10】实战项目:打造一个蓝牙传感器终端 + 网关系统(完整架构与全栈实现)
🧠关键词:Zephyr、BLE、终端、网关、广播、连接、传感器、数据采集、低功耗、系统集成 📌目标读者:希望基于 Zephyr 构建 BLE 系统架构、实现终端与网关协作、具备产品交付能力的开发者 📊篇幅字数:约 5200 字 ✨ 项目总览 在物联网实际项目中,**“终端 + 网关”**是…...
前端开发面试题总结-JavaScript篇(一)
文章目录 JavaScript高频问答一、作用域与闭包1.什么是闭包(Closure)?闭包有什么应用场景和潜在问题?2.解释 JavaScript 的作用域链(Scope Chain) 二、原型与继承3.原型链是什么?如何实现继承&a…...
3403. 从盒子中找出字典序最大的字符串 I
3403. 从盒子中找出字典序最大的字符串 I 题目链接:3403. 从盒子中找出字典序最大的字符串 I 代码如下: class Solution { public:string answerString(string word, int numFriends) {if (numFriends 1) {return word;}string res;for (int i 0;i &…...
Web 架构之 CDN 加速原理与落地实践
文章目录 一、思维导图二、正文内容(一)CDN 基础概念1. 定义2. 组成部分 (二)CDN 加速原理1. 请求路由2. 内容缓存3. 内容更新 (三)CDN 落地实践1. 选择 CDN 服务商2. 配置 CDN3. 集成到 Web 架构 …...
sipsak:SIP瑞士军刀!全参数详细教程!Kali Linux教程!
简介 sipsak 是一个面向会话初始协议 (SIP) 应用程序开发人员和管理员的小型命令行工具。它可以用于对 SIP 应用程序和设备进行一些简单的测试。 sipsak 是一款 SIP 压力和诊断实用程序。它通过 sip-uri 向服务器发送 SIP 请求,并检查收到的响应。它以以下模式之一…...
智能AI电话机器人系统的识别能力现状与发展水平
一、引言 随着人工智能技术的飞速发展,AI电话机器人系统已经从简单的自动应答工具演变为具备复杂交互能力的智能助手。这类系统结合了语音识别、自然语言处理、情感计算和机器学习等多项前沿技术,在客户服务、营销推广、信息查询等领域发挥着越来越重要…...
