基于ArkUI Emitter对象实现自定义事件订阅系统 原创

炒香菇的书呆子
发布于 2025-3-31 02:08
1420浏览
1收藏

Table of Contents

一、引言

在现代计算机编程中,事件驱动编程是一种非常重要的编程范式。它允许程序在特定事件发生时执行相应的操作,从而提高程序的灵活性和可维护性。ArkUI 的 Emitter 对象提供了持续订阅事件、单次订阅事件、取消订阅事件以及触发事件的能力,为我们提供了一个很好的封装参考。
在本文中,我们将探讨如何自己实现一个类似的事件订阅系统。

二、什么是订阅模式

2.1 订阅模式

订阅模式,也称为发布 - 订阅模式(Publish - Subscribe Pattern),是一种消息传递模式,其中发送者(发布者)不会直接将消息发送给特定的接收者(订阅者),而是将消息发布到一个中间的消息代理(通常称为主题或频道),订阅者可以选择订阅他们感兴趣的主题。当有新的消息发布到某个主题时,所有订阅了该主题的订阅者都会收到通知。

基于ArkUI Emitter对象实现自定义事件订阅系统-鸿蒙开发者社区

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.")
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.

在这个示例中,定义了一个名为 EventListener 的接口,其中包含一个 on_event 方法。所有实现了这个接口的类都必须实现 on_event 方法,用于处理接收到的事件。

3.3 实现订阅接口

以下是一个实现了 EventListener 接口类:

# 实现订阅接口的类
class MyEventListener(EventListener):
    def on_event(self, event):
        print(f"Received event: {event}")
  • 1.
  • 2.
  • 3.
  • 4.

在这个示例中,定义了一个名为 MyEventListener 的类,它实现了 EventListener 接口的 on_event 方法。当接收到事件时,它会打印出接收到的事件信息。

四、事件类型定义

4.1 事件类型的作用

在事件订阅系统中,不同的事件可能需要不同的处理方式。因此,我们需要定义不同的事件类型,以便订阅者可以根据事件类型来选择是否处理该事件。

4.2 事件类型的设计

以下是一个事件类型定义:

# 定义事件类型
class EventType:
    EVENT_TYPE_1 = "EVENT_TYPE_1"
    EVENT_TYPE_2 = "EVENT_TYPE_2"
  • 1.
  • 2.
  • 3.
  • 4.

在这个示例中,定义了两个事件类型:EVENT_TYPE_1EVENT_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
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.

在这个示例中,我们定义了一个名为 Event 的类,它包含两个属性:event_typedata,分别表示事件类型和事件数据。

五、自定义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] = []
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.
  • 47.
  • 48.
  • 49.
  • 50.
  • 51.
  • 52.
  • 53.
  • 54.

在这个示例中,定义了一个名为 Emitter 的类,它包含以下几个方法:

  • __init__:初始化 Emitter 对象,创建两个字典 subscribersonce_subscribers,分别用于存储持续订阅者和单次订阅者。
  • subscribe:用于持续订阅事件,将订阅者添加到 subscribers 字典中。
  • subscribe_once:用于单次订阅事件,将订阅者添加到 once_subscribers 字典中。
  • unsubscribe:用于取消订阅事件,从 subscribersonce_subscribers 字典中移除订阅者。
  • emit:用于触发事件,遍历 subscribersonce_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)
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.
  • 47.
  • 48.
  • 49.
  • 50.
  • 51.
  • 52.
  • 53.
  • 54.
  • 55.
  • 56.
  • 57.
  • 58.
  • 59.
  • 60.
  • 61.
  • 62.
  • 63.
  • 64.
  • 65.
  • 66.
  • 67.
  • 68.
  • 69.
  • 70.
  • 71.
  • 72.
  • 73.
  • 74.
  • 75.
  • 76.
  • 77.
  • 78.
  • 79.
  • 80.
  • 81.
  • 82.
  • 83.
  • 84.
  • 85.
  • 86.
  • 87.
  • 88.
  • 89.
  • 90.
  • 91.
  • 92.
  • 93.
  • 94.
  • 95.
  • 96.
  • 97.
  • 98.
  • 99.
  • 100.
  • 101.
  • 102.
  • 103.
  • 104.
  • 105.
  • 106.
  • 107.
  • 108.
  • 109.
  • 110.
  • 111.
  • 112.
  • 113.
  • 114.
  • 115.
  • 116.
  • 117.
  • 118.

6.2 调用示例解释

  • 创建 Emitter 对象:首先创建一个 Emitter 对象,用于管理事件的订阅和触发。
  • 创建订阅者对象:创建两个 MyEventListener 对象 listener1listener2,用于处理事件。
  • 持续订阅事件:使用 subscribe 方法让 listener1 持续订阅 EVENT_TYPE_1 事件。
  • 单次订阅事件:使用 subscribe_once 方法让 listener2 单次订阅 EVENT_TYPE_2 事件。
  • 触发事件:创建 Event 对象 event1event2,分别表示 EVENT_TYPE_1EVENT_TYPE_2 事件,并使用 emit 方法触发这些事件。
  • 再次触发事件:创建 Event 对象 event3,再次触发 EVENT_TYPE_2 事件,由于 listener2 是单次订阅,所以不会再次处理该事件。
  • 取消订阅事件:使用 unsubscribe 方法取消 listener1EVENT_TYPE_1 事件的订阅。
  • 再次触发事件:创建 Event 对象 event4,再次触发 EVENT_TYPE_1 事件,由于 listener1 已经取消订阅,所以不会处理该事件。

七、总结

通过本文的介绍,我们了解了订阅模式的概念、优点和应用场景,并基于 ArkUI 的 Emitter 对象实现了一个自定义的事件订阅系统。设计了订阅接口监听器、定义了事件类型、创建了自定义的 Emitter 类,并提供了完整的调用示例。这个自定义的事件订阅系统可以帮助我们更好地实现事件驱动编程,提高程序的灵活性和可维护性。在实际应用中,可以根据具体需求对这个系统进行扩展和优化,例如添加错误处理、异步处理等功能。

©著作权归作者所有,如需转载,请注明出处,否则将追究法律责任
1
收藏 1
回复
举报
1
1
1
1条回复
按时间正序
/
按时间倒序
虎子船长
虎子船长

收藏了🌟🌟

回复
2025-4-3 08:44:09


回复
    相关推荐
    RHCE、PGCE、Antdb ACP 51CTO、华为云、博客专家
    觉得TA不错?点个关注精彩不错过
    38
    帖子
    0
    视频
    175
    声望
    1
    粉丝
    社区精华内容
    恭喜您,今日已阅读两篇内容,特奖励+2声望, 快来领取吧。