基于ArkUI Emitter对象实现自定义事件订阅系统 原创
@[toc]
一、引言
在现代计算机编程中,事件驱动编程是一种非常重要的编程范式。它允许程序在特定事件发生时执行相应的操作,从而提高程序的灵活性和可维护性。ArkUI 的 Emitter 对象提供了持续订阅事件、单次订阅事件、取消订阅事件以及触发事件的能力,为我们提供了一个很好的封装参考。
在本文中,我们将探讨如何自己实现一个类似的事件订阅系统。
二、什么是订阅模式
2.1 订阅模式
订阅模式,也称为发布 - 订阅模式(Publish - Subscribe Pattern),是一种消息传递模式,其中发送者(发布者)不会直接将消息发送给特定的接收者(订阅者),而是将消息发布到一个中间的消息代理(通常称为主题或频道),订阅者可以选择订阅他们感兴趣的主题。当有新的消息发布到某个主题时,所有订阅了该主题的订阅者都会收到通知。
2.2 订阅模式的优点
- 松耦合:发布者和订阅者之间不需要直接了解对方的存在,它们只需要通过主题进行通信,从而降低了代码的耦合度。
- 可扩展性:可以轻松地添加新的发布者和订阅者,而不需要修改现有的代码。
- 异步通信:发布者和订阅者可以在不同的线程或进程中运行,从而实现异步通信,提高程序的性能。
2.3 订阅模式的应用场景
- 消息队列:在分布式系统中,消息队列是一种常见的实现订阅模式的方式,用于实现不同服务之间的异步通信。
- 事件驱动编程:在图形用户界面(GUI)编程、游戏开发等领域,事件驱动编程是一种常见的编程范式,订阅模式可以用于处理各种事件,如鼠标点击、键盘输入等。
三、订阅接口监听器设计
3.1 接口的作用
在设计事件订阅系统时,我们需要定义一个接口来规范订阅者的行为。这个接口通常包含一个方法,用于处理接收到的事件。通过定义接口,我们可以确保所有的订阅者都实现了相同的方法,从而方便发布者调用。
3.2 订阅接口的设计
以下是订阅接口的设计:
# 定义订阅接口
class EventListener:
def on_event(self, event):
"""
处理事件的方法
:param event: 接收到的事件
"""
raise NotImplementedError("Subclasses should implement this method.")
在这个示例中,定义了一个名为 EventListener
的接口,其中包含一个 on_event
方法。所有实现了这个接口的类都必须实现 on_event
方法,用于处理接收到的事件。
3.3 实现订阅接口
以下是一个实现了 EventListener
接口类:
# 实现订阅接口的类
class MyEventListener(EventListener):
def on_event(self, event):
print(f"Received event: {event}")
在这个示例中,定义了一个名为 MyEventListener
的类,它实现了 EventListener
接口的 on_event
方法。当接收到事件时,它会打印出接收到的事件信息。
四、事件类型定义
4.1 事件类型的作用
在事件订阅系统中,不同的事件可能需要不同的处理方式。因此,我们需要定义不同的事件类型,以便订阅者可以根据事件类型来选择是否处理该事件。
4.2 事件类型的设计
以下是一个事件类型定义:
# 定义事件类型
class EventType:
EVENT_TYPE_1 = "EVENT_TYPE_1"
EVENT_TYPE_2 = "EVENT_TYPE_2"
在这个示例中,定义了两个事件类型:EVENT_TYPE_1
和 EVENT_TYPE_2
。订阅者可以根据这些事件类型来选择是否处理相应的事件。
4.3 事件类的设计
为了方便传递事件信息,我们可以定义一个事件类,包含事件类型和事件数据。以下是一个简单的事件类的设计示例:
# 定义事件类
class Event:
def __init__(self, event_type, data):
"""
初始化事件对象
:param event_type: 事件类型
:param data: 事件数据
"""
self.event_type = event_type
self.data = data
在这个示例中,我们定义了一个名为 Event
的类,它包含两个属性:event_type
和 data
,分别表示事件类型和事件数据。
五、自定义Emitter类结构
5.1 Emitter类的功能
自定义的 Emitter
类将实现持续订阅事件、单次订阅事件、取消订阅事件以及触发事件的功能。
5.2 Emitter类的设计
以下是一个自定义 Emitter
类的设计:
class Emitter:
def __init__(self):
# 存储持续订阅者的字典,键为事件类型,值为订阅者列表
self.subscribers = {}
# 存储单次订阅者的字典,键为事件类型,值为订阅者列表
self.once_subscribers = {}
def subscribe(self, event_type, listener):
"""
持续订阅事件
:param event_type: 事件类型
:param listener: 订阅者
"""
if event_type not in self.subscribers:
self.subscribers[event_type] = []
self.subscribers[event_type].append(listener)
def subscribe_once(self, event_type, listener):
"""
单次订阅事件
:param event_type: 事件类型
:param listener: 订阅者
"""
if event_type not in self.once_subscribers:
self.once_subscribers[event_type] = []
self.once_subscribers[event_type].append(listener)
def unsubscribe(self, event_type, listener):
"""
取消订阅事件
:param event_type: 事件类型
:param listener: 订阅者
"""
if event_type in self.subscribers:
if listener in self.subscribers[event_type]:
self.subscribers[event_type].remove(listener)
if event_type in self.once_subscribers:
if listener in self.once_subscribers[event_type]:
self.once_subscribers[event_type].remove(listener)
def emit(self, event):
"""
触发事件
:param event: 事件对象
"""
event_type = event.event_type
if event_type in self.subscribers:
for listener in self.subscribers[event_type]:
listener.on_event(event)
if event_type in self.once_subscribers:
for listener in self.once_subscribers[event_type]:
listener.on_event(event)
# 清空单次订阅者列表
self.once_subscribers[event_type] = []
在这个示例中,定义了一个名为 Emitter
的类,它包含以下几个方法:
__init__
:初始化Emitter
对象,创建两个字典subscribers
和once_subscribers
,分别用于存储持续订阅者和单次订阅者。subscribe
:用于持续订阅事件,将订阅者添加到subscribers
字典中。subscribe_once
:用于单次订阅事件,将订阅者添加到once_subscribers
字典中。unsubscribe
:用于取消订阅事件,从subscribers
和once_subscribers
字典中移除订阅者。emit
:用于触发事件,遍历subscribers
和once_subscribers
字典中相应事件类型的订阅者列表,调用它们的on_event
方法处理事件。对于单次订阅者,在处理完事件后,将其从once_subscribers
字典中移除。
六、调用示例
6.1 调用代码
# 定义订阅接口
class EventListener:
def on_event(self, event):
"""
处理事件的方法
:param event: 接收到的事件
"""
raise NotImplementedError("Subclasses should implement this method.")
# 实现订阅接口的类
class MyEventListener(EventListener):
def on_event(self, event):
print(f"Received event: {event.event_type}, Data: {event.data}")
# 定义事件类型
class EventType:
EVENT_TYPE_1 = "EVENT_TYPE_1"
EVENT_TYPE_2 = "EVENT_TYPE_2"
# 定义事件类
class Event:
def __init__(self, event_type, data):
"""
初始化事件对象
:param event_type: 事件类型
:param data: 事件数据
"""
self.event_type = event_type
self.data = data
# 自定义Emitter类
class Emitter:
def __init__(self):
# 存储持续订阅者的字典,键为事件类型,值为订阅者列表
self.subscribers = {}
# 存储单次订阅者的字典,键为事件类型,值为订阅者列表
self.once_subscribers = {}
def subscribe(self, event_type, listener):
"""
持续订阅事件
:param event_type: 事件类型
:param listener: 订阅者
"""
if event_type not in self.subscribers:
self.subscribers[event_type] = []
self.subscribers[event_type].append(listener)
def subscribe_once(self, event_type, listener):
"""
单次订阅事件
:param event_type: 事件类型
:param listener: 订阅者
"""
if event_type not in self.once_subscribers:
self.once_subscribers[event_type] = []
self.once_subscribers[event_type].append(listener)
def unsubscribe(self, event_type, listener):
"""
取消订阅事件
:param event_type: 事件类型
:param listener: 订阅者
"""
if event_type in self.subscribers:
if listener in self.subscribers[event_type]:
self.subscribers[event_type].remove(listener)
if event_type in self.once_subscribers:
if listener in self.once_subscribers[event_type]:
self.once_subscribers[event_type].remove(listener)
def emit(self, event):
"""
触发事件
:param event: 事件对象
"""
event_type = event.event_type
if event_type in self.subscribers:
for listener in self.subscribers[event_type]:
listener.on_event(event)
if event_type in self.once_subscribers:
for listener in self.once_subscribers[event_type]:
listener.on_event(event)
# 清空单次订阅者列表
self.once_subscribers[event_type] = []
# 调用示例
if __name__ == "__main__":
# 创建Emitter对象
emitter = Emitter()
# 创建订阅者对象
listener1 = MyEventListener()
listener2 = MyEventListener()
# 持续订阅事件
emitter.subscribe(EventType.EVENT_TYPE_1, listener1)
# 单次订阅事件
emitter.subscribe_once(EventType.EVENT_TYPE_2, listener2)
# 触发事件
event1 = Event(EventType.EVENT_TYPE_1, "Data for event type 1")
emitter.emit(event1)
event2 = Event(EventType.EVENT_TYPE_2, "Data for event type 2")
emitter.emit(event2)
# 再次触发事件
event3 = Event(EventType.EVENT_TYPE_2, "Another data for event type 2")
emitter.emit(event3)
# 取消订阅事件
emitter.unsubscribe(EventType.EVENT_TYPE_1, listener1)
# 再次触发事件
event4 = Event(EventType.EVENT_TYPE_1, "Data for event type 1 after unsubscribe")
emitter.emit(event4)
6.2 调用示例解释
- 创建
Emitter
对象:首先创建一个Emitter
对象,用于管理事件的订阅和触发。 - 创建订阅者对象:创建两个
MyEventListener
对象listener1
和listener2
,用于处理事件。 - 持续订阅事件:使用
subscribe
方法让listener1
持续订阅EVENT_TYPE_1
事件。 - 单次订阅事件:使用
subscribe_once
方法让listener2
单次订阅EVENT_TYPE_2
事件。 - 触发事件:创建
Event
对象event1
和event2
,分别表示EVENT_TYPE_1
和EVENT_TYPE_2
事件,并使用emit
方法触发这些事件。 - 再次触发事件:创建
Event
对象event3
,再次触发EVENT_TYPE_2
事件,由于listener2
是单次订阅,所以不会再次处理该事件。 - 取消订阅事件:使用
unsubscribe
方法取消listener1
对EVENT_TYPE_1
事件的订阅。 - 再次触发事件:创建
Event
对象event4
,再次触发EVENT_TYPE_1
事件,由于listener1
已经取消订阅,所以不会处理该事件。
七、总结
通过本文的介绍,我们了解了订阅模式的概念、优点和应用场景,并基于 ArkUI 的 Emitter 对象实现了一个自定义的事件订阅系统。设计了订阅接口监听器、定义了事件类型、创建了自定义的 Emitter
类,并提供了完整的调用示例。这个自定义的事件订阅系统可以帮助我们更好地实现事件驱动编程,提高程序的灵活性和可维护性。在实际应用中,可以根据具体需求对这个系统进行扩展和优化,例如添加错误处理、异步处理等功能。
收藏了🌟🌟