当前位置: 首页 > news >正文

设计模式】Listener模式和Visitor模式的区别

文章目录

  • 前言
  • 一、介绍
      • Listener模式
      • Visitor模式
  • 二、代码实现
      • 2.1 Listener模式的Java实现
      • 2.2Listener模式的Go实现
      • 2.3Visitor模式的Java实现
      • 2.4Visitor模式的Go实现
  • 三、总结


前言

在软件设计中,设计模式是解决特定问题的通用解决方案。Listener模式和Visitor模式是两种常见的行为设计模式,它们在不同的场景下提供了解决问题的有效方法。本文将详细解释这两种模式,并通过Java和Go语言的代码示例展示它们的实现,最后总结它们的区别和适用场景。


一、介绍

Listener模式

Listener模式(监听器模式) 是一种行为设计模式,主要用于事件驱动的编程。它允许一个对象(监听器)注册到另一个对象(事件源),以便在特定事件发生时接收通知。

主要特点:
1.解耦: 事件源和监听器之间是松耦合的,事件源只需要知道监听器实现了某个接口,而不需要知道具体的实现细节。
2.灵活性: 可以动态添加或移除监听器。
3.异步处理: 事件通知通常是异步的,这意味着事件源在触发事件后可以继续执行其他任务,而不需要等待监听器处理完事件。

典型应用:

  • GUI应用程序中的按钮点击事件。
  • 网络编程中的数据接收事件。

Visitor模式

Visitor模式(访问者模式) 是一种行为设计模式,它允许你在不改变对象结构的前提下,定义作用于这些对象的新操作。它将操作的定义与对象结构分离,使得新的操作可以很容易地添加。

主要特点:
1.双重分派: Visitor模式使用双重分派机制,即首先调用对象的accept方法,然后在accept方法中调用访问者的visit方法。
2.扩展性: 可以很容易地添加新的操作,而不需要修改对象结构。
**3.复杂性:**增加了系统的复杂性,因为需要定义多个访问者类和accept方法。

典型应用:

  • 编译器中的语法树遍历。
  • 复杂对象结构的操作,如文件系统遍历。

二、代码实现

2.1 Listener模式的Java实现

// 定义监听器接口
public interface EventListener {void onEvent();
}// 事件源类
public class EventSource {private List<EventListener> listeners = new ArrayList<>();public void addListener(EventListener listener) {listeners.add(listener);}public void removeListener(EventListener listener) {listeners.remove(listener);}public void triggerEvent() {for (EventListener listener : listeners) {listener.onEvent();}}
}// 实现监听器
public class MyEventListener implements EventListener {@Overridepublic void onEvent() {System.out.println("Event triggered!");}
}// 使用示例
public class Main {public static void main(String[] args) {EventSource eventSource = new EventSource();MyEventListener listener = new MyEventListener();eventSource.addListener(listener);eventSource.triggerEvent();}
}

2.2Listener模式的Go实现

package mainimport ("fmt"
)// 定义监听器接口
type EventListener interface {OnEvent()
}// 事件源类
type EventSource struct {listeners []EventListener
}func (es *EventSource) AddListener(listener EventListener) {es.listeners = append(es.listeners, listener)
}func (es *EventSource) RemoveListener(listener EventListener) {for i, l := range es.listeners {if l == listener {es.listeners = append(es.listeners[:i], es.listeners[i+1:]...)break}}
}func (es *EventSource) TriggerEvent() {for _, listener := range es.listeners {listener.OnEvent()}
}// 实现监听器
type MyEventListener struct{}func (mel *MyEventListener) OnEvent() {fmt.Println("Event triggered!")
}func main() {eventSource := &EventSource{}listener := &MyEventListener{}eventSource.AddListener(listener)eventSource.TriggerEvent()
}

2.3Visitor模式的Java实现

// 定义访问者接口
public interface Visitor {void visit(ElementA element);void visit(ElementB element);
}// 定义元素接口
public interface Element {void accept(Visitor visitor);
}// 具体元素A
public class ElementA implements Element {@Overridepublic void accept(Visitor visitor) {visitor.visit(this);}
}// 具体元素B
public class ElementB implements Element {@Overridepublic void accept(Visitor visitor) {visitor.visit(this);}
}// 具体访问者
public class ConcreteVisitor implements Visitor {@Overridepublic void visit(ElementA element) {System.out.println("Visiting ElementA");}@Overridepublic void visit(ElementB element) {System.out.println("Visiting ElementB");}
}// 使用示例
public class Main {public static void main(String[] args) {List<Element> elements = Arrays.asList(new ElementA(), new ElementB());Visitor visitor = new ConcreteVisitor();for (Element element : elements) {element.accept(visitor);}}
}

2.4Visitor模式的Go实现

package mainimport ("fmt"
)// 定义访问者接口
type Visitor interface {VisitElementA(*ElementA)VisitElementB(*ElementB)
}// 定义元素接口
type Element interface {Accept(Visitor)
}// 具体元素A
type ElementA struct{}func (e *ElementA) Accept(visitor Visitor) {visitor.VisitElementA(e)
}// 具体元素B
type ElementB struct{}func (e *ElementB) Accept(visitor Visitor) {visitor.VisitElementB(e)
}// 具体访问者
type ConcreteVisitor struct{}func (cv *ConcreteVisitor) VisitElementA(e *ElementA) {fmt.Println("Visiting ElementA")
}func (cv *ConcreteVisitor) VisitElementB(e *ElementB) {fmt.Println("Visiting ElementB")
}func main() {elements := []Element{&ElementA{}, &ElementB{}}visitor := &ConcreteVisitor{}for _, element := range elements {element.Accept(visitor)}
}

三、总结

Listener模式和Visitor模式虽然都是行为设计模式,但它们解决的问题和应用场景有所不同。

  • Listener模式主要用于事件驱动的编程,适用于需要在特定事件发生时通知多个监听器的场景。它通过解耦事件源和监听器,使得系统更加灵活和可扩展。

  • Visitor模式则用于在不改变对象结构的前提下,定义新的操作。它通过双重分派机制,使得新的操作可以很容易地添加,适用于需要对复杂对象结构进行操作的场景。

通过本文的解释和代码示例,希望你能更好地理解这两种设计模式的区别和应用场景。在实际开发中,根据具体需求选择合适的设计模式,可以提高代码的可维护性和扩展性。

相关文章:

设计模式】Listener模式和Visitor模式的区别

文章目录 前言一、介绍Listener模式Visitor模式 二、代码实现2.1 Listener模式的Java实现2.2Listener模式的Go实现2.3Visitor模式的Java实现2.4Visitor模式的Go实现 三、总结 前言 在软件设计中&#xff0c;设计模式是解决特定问题的通用解决方案。Listener模式和Visitor模式是…...

基于事件序列的数据获取

Data Get 31670 /S Update 2 AI_PC 3Mins /次 Import "Hggw" PI Data AABB020240908_115221_31781 AABB020240908_115521_31781 AABB020240908_115821_31781 1、From PIdata Copy 2 AI PC 2、AI PC UI Chart & Logic OK NG Pump&#xff1a;&#x…...

太速科技-基于XC7Z100+AD9361的双收双发无线电射频板卡

基于XC7Z100AD9361的双收双发无线电射频板卡 一、板卡概述 基于XC7Z100AD9361的双收双发无线电射频板卡是基于Xilinx ZYNQ FPGA和ADI的无线收发芯片AD9361开发的专用功能板卡&#xff0c;用于4G小基站&#xff0c;无线图传&#xff0c;数据收发等领域。 二、板卡…...

探索UWB技术的独特优势:实现高精度定位

UWB定位技术是一种利用无线信号进行精确位置定位的技术&#xff0c;它利用超宽带无线电信号通过测量信号的到达时间、相位差和信号能量等参数来确定物体的精确位置。 UWB定位技术具有多种优势&#xff0c;首先&#xff0c;它具有较高的定位精度&#xff0c;可实现毫米级的精确…...

软件安装攻略:Sublime Text 下载安装和使用教程

Sublime Text 下载安装和使用教程 Sublime Text是一个流行的跨平台文本编辑器&#xff0c;它具有以下一些主要功能和特点&#xff1a; &#xff08;1&#xff09;简洁的界面和快速的速度&#xff1a;Sublime Text拥有简约干净的界面&#xff0c;启动和响应速度很快。 &#…...

ip地址为什么要轮换

在网络世界中&#xff0c;IP地址是设备与互联网通信的身份证。然而&#xff0c;单一的IP地址可能会因为各种原因而需要轮换。IP轮换是指在一定时间内更换正在使用的IP地址&#xff0c;这一策略在多种网络应用中发挥着重要作用。本文将探讨IP地址轮换的原因、其带来的优势以及实…...

C++ 继承【一篇让你学会继承】

1. 继承的概念及定义 1.1 继承的概念 继承机制是面向对象程序设计使代码可以复用的最重要的手段&#xff0c;它允许程序员在保持原有类特征的基础上进行扩展&#xff0c;增加功能&#xff0c;这样产生新的类&#xff0c;称派生类。继承呈现了面向对象程序设计的层次结构&…...

DeviceNet网关HT3S-DNS-MDN读取七星华创CS310空气流量计数据应用案例

七星华创流量计CS310系列 (MODBUS RTU) 通过DeviceNet网关HT3S-DNS-MDN 与台达DVP系列的PLC进行交换数据应用案例 一、概述 本文主要介绍使用HI-TOP网关 HT3S-DNS-MDN在台达DVP系列 PLC和七星华创CS310流量计之间进行数据交换。 解决的问题&#xff1a;台达DVP系列如何通过…...

Smartbi体验中心新增系列Demo,用户体验更丰富

为进一步提升用户体验&#xff0c;让大家更直观地了解Smartbi产品在数据分析方面的功能优势&#xff0c;Smartbi体验中心近期新增了一系列Demo。这些更新旨在优化产品操作流程&#xff0c;并为用户提供更多真实场景下的应用参考。接下来&#xff0c;我们一起简要浏览此次体验中…...

Kubernetes 与 springboot集成

Kubernetes 与 Spring Boot 集成详解 Kubernetes&#xff08;简称 K8s&#xff09;是一个用于自动化部署、扩展和管理容器化应用的开源平台&#xff0c;而 Spring Boot 是 Java 开发领域中非常流行的微服务框架。将这两者结合&#xff0c;可以充分利用 Kubernetes 强大的容器编…...

以太网传输出现不分包

最近对手件反馈,在传输文件的时候,我们这边发包太快,导致对手件网络出现了拥塞,把他们程序给搞死了。他们抓了一下他们收到的包,发现我们发送的数据包都大于了MTU设置的值。现在被要求更改。 排查方法:为什么我们发送的数据包会大于MTU的值。 可能性一:配置了Dont Fra…...

[实践应用] 深度学习之激活函数

文章总览&#xff1a;YuanDaiMa2048博客文章总览 深度学习之激活函数 激活函数基本概念分类常见的激活函数2. Tanh/双曲正切激活函数3. ReLU激活函数4. Softmax激活函数 PyTorch中如何使用1. 线性激活函数2. 非线性激活函数SigmoidTanhReLULeaky ReLUParametric ReLU (PReLU) 使…...

Java基础之数组

文章地址&#xff1a;Java基础之数组 码农爱刷题 为计算机编程爱好者和从业人士提供技术总结和分享 &#xff01;为前行者蓄力&#xff0c;为后来者探路&#xff01;...

基于SpringBoot+Vue的智慧自习室预约管理系统

作者&#xff1a;计算机学姐 开发技术&#xff1a;SpringBoot、SSM、Vue、MySQL、JSP、ElementUI、Python、小程序等&#xff0c;“文末源码”。 专栏推荐&#xff1a;前后端分离项目源码、SpringBoot项目源码、SSM项目源码 系统展示 【2025最新】基于JavaSpringBootVueMySQL的…...

pptpd配置文件/etc/pptpd.conf详解

正文共&#xff1a;1111 字 2 图&#xff0c;预估阅读时间&#xff1a;1 分钟 如果要在Linux系统配置PPTP&#xff08;Point-to-Point Tunneling Protocol&#xff0c;点到点隧道协议&#xff09;VPN&#xff0c;一般是使用pptpd软件。pptpd命令通常从配置文件/etc/pptpd.conf中…...

springboot对数据库进行备份+对一个文件夹内的文件按时间排序,只保留最近的8个文件

首先&#xff0c;对数据库进行备份&#xff0c;用到的命令&#xff1a; mysqldump --opt -h 192.168.1.200 --userroot --passwordxxx --result-fileE://data//20240911141400.sql --default-character-setutf8 xxx&#xff08;数据库名&#xff09; 直接上代码 配置文件部分…...

【软考中级攻略站】-软件设计师(4)-计算机网络基础

计算机网络的分类 1. 局域网&#xff08;Local Area Network, LAN&#xff09; 局域网是指在一个较小的地理区域内连接的计算机网络&#xff0c;比如学校的机房、公司的办公室或者家里的Wi-Fi网络。在这个网络内的计算机可以直接相互通信&#xff0c;速度很快&#xff0c;延迟…...

Android以及IoT设备传感器软件开发总结

1 传感器选型 1.1 传感器选型 6 axis&#xff1a;Bosch BMI160&#xff08;比较差&#xff09;&#xff0c;InvenSense MPU6050&#xff08;DMP&#xff09;&#xff0c;ST LSM6Dxx Acc: Freescale MMA7450L (MicroMachined Accelerometer/MC Multi-Axis, iMX31), Kionix KXSD9…...

Vue2/Vue3中编程式路由导航实践总结

【1】Vue2编程式路由导航 ① router.push 除了使用 <router-link> 创建 a 标签来定义导航链接&#xff0c;我们还可以借助 router 的实例方法&#xff0c;通过编写代码来实现。 router.push(location, onComplete?, onAbort?)注意&#xff1a;在 Vue 实例内部&#…...

【nginx】ngx_http_proxy_connect_module 正向代理

50.65无法访问 服务器, (403 错误) 50.196 可以访问服务器。 那么,配置65 通过196 访问。 需要一个nginx作为代理 【nginx】搭配okhttp 配置反向代理 发送原生的nginx是不支持okhttp的CONNECT请求的。 大神竟然给出了一个java工程 GINX编译ngx_http_proxy_connect_module及做…...

告别激活弹窗:KMS_VL_ALL_AIO智能激活工具完全指南

告别激活弹窗&#xff1a;KMS_VL_ALL_AIO智能激活工具完全指南 【免费下载链接】KMS_VL_ALL_AIO Smart Activation Script 项目地址: https://gitcode.com/gh_mirrors/km/KMS_VL_ALL_AIO 还在为Windows系统激活烦恼吗&#xff1f;每次开机都看到"需要激活"的提…...

用Python和OpenCV手把手教你搞定自动驾驶图像坐标系转换(附NuScenes数据集实战代码)

用Python和OpenCV手把手教你搞定自动驾驶图像坐标系转换&#xff08;附NuScenes数据集实战代码&#xff09; 自动驾驶技术的核心在于让车辆"看懂"周围环境&#xff0c;而坐标系转换正是连接物理世界与数字世界的桥梁。想象一下&#xff0c;当一辆自动驾驶汽车行驶在…...

抖音图片怎么去水印?2026年在线去水印工具+方法盘点,总有一款适合你

开篇&#xff1a;为什么要去水印&#xff1f; 保存抖音图片时&#xff0c;总会遇到水印的困扰。这些水印包含抖音logo、发布者名称&#xff0c;有时还会有账号信息。对于自媒体创作者、内容整理者或普通用户来说&#xff0c;去除水印往往是必需的。本文将介绍当下最实用的抖音图…...

Solidworks PDM二次开发实战:文件夹权限与数据卡配置详解

1. Solidworks PDM二次开发入门指南 如果你正在使用Solidworks PDM管理产品数据&#xff0c;可能会遇到需要批量创建文件夹并设置权限的场景。比如新项目启动时&#xff0c;需要为不同部门创建标准化的文件夹结构&#xff0c;同时设置工程师只读、管理员完全控制的权限规则。手…...

基于大语言模型的本地语义搜索工具LLocalSearch部署与应用指南

1. 项目概述&#xff1a;一个能“读懂”你电脑的本地搜索工具 如果你和我一样&#xff0c;电脑里塞满了各种文档、邮件、聊天记录和代码片段&#xff0c;那么“找东西”这件事&#xff0c;绝对能排进日常最耗时的任务前三。传统的文件搜索&#xff0c;比如Windows自带的搜索或者…...

Claude API企业准入最后窗口期:2024Q3起强制启用OAuth 2.1+硬件级密钥绑定,现在不升级将无法续签

更多请点击&#xff1a; https://intelliparadigm.com 第一章&#xff1a;Claude API企业准入政策的演进与合规紧迫性 随着Anthropic对Claude模型商用边界的持续收束&#xff0c;企业级API接入正从“技术可用性”转向“治理可验证性”。2024年Q2起&#xff0c;所有新注册企业账…...

AI驱动代码审查:Cursor与Git工作流融合实践

1. 项目概述&#xff1a;当AI代码助手遇上代码审查最近在GitHub上看到一个挺有意思的项目&#xff0c;叫guinacio/cursor-review。光看名字&#xff0c;你可能会觉得这又是一个普通的代码审查工具&#xff0c;但点进去仔细研究&#xff0c;你会发现它的核心思路非常巧妙&#x…...

基于意图与技能解耦的智能对话系统构建指南

1. 项目概述&#xff1a;一个意图与技能驱动的AI对话引擎最近在折腾AI应用开发&#xff0c;特别是对话型AI助手时&#xff0c;发现一个核心痛点&#xff1a;如何让AI不仅能理解用户说了什么&#xff08;意图识别&#xff09;&#xff0c;还能精准地调用相应的功能&#xff08;技…...

基于树莓派与QT Py的本地化物联网红外遥控器DIY指南

1. 项目概述与核心价值想没想过&#xff0c;把家里那堆遥控器——电视的、机顶盒的、空调的、音响的——统统集成到一个你手机能打开的网页里&#xff1f;而且这个控制中心完全在你家局域网里运行&#xff0c;不依赖任何云服务&#xff0c;不用担心厂商倒闭后设备变砖。今天分享…...

从零打造专业GitHub个人资料页:Markdown与动态集成实战指南

1. 项目概述与核心价值 在技术圈子里混了十几年&#xff0c;我越来越觉得&#xff0c;一个开发者的“数字门面”和代码能力同等重要。这个门面&#xff0c;很多时候就是你的GitHub主页。早些年&#xff0c;大家的GitHub个人页面就是个简单的仓库列表&#xff0c;加上一些贡献图…...