第4章 事件总线核心接口设计:注册、注销、发送、接收回调的抽象或接口

事件总线的核心是围绕注册、注销、发送、接收回调四个操作定义一套稳定的抽象契约。密封类方案下的接口设计既要兼容传统EventBus的语义,又要借助Kotlin类型系统提升安全性与可维护性。本章将定义事件总线的基础抽象接口,并分析各方法在密封类场景下的设计考量。

4.1 抽象接口定义

基础接口必须包含注册、注销、发送三个核心方法,以及一个可选的观察者回调注册方式(用于避免反射)。推荐使用泛型限定事件类型为密封类或其子类。

interface EventBus {
    fun register(subscriber: Any)
    fun unregister(subscriber: Any)
    fun post(event: Any)

    // 类型安全的观察者模式(替代反射回调)
    fun <T : SealedEvent> observe(
        eventType: Class<T>,
        callback: (T) -> Unit
    ): Disposable
}

4.2 注册与注销的设计原则

  • 生命周期绑定:注册通常在onStart/onResume中进行,注销在onStop/onPause中执行;接口不强制生命周期管理,但实现类应提供Disposable返回。
  • 重复注册防护:接口不做去重,由实现层通过Set或Map维护唯一性。
  • 性能优化:注销时建议使用迭代器安全移除,并清理引用避免内存泄漏。

4.3 发送与接收回调

发送方法post接收任意对象,但在密封类方案中通常只接受SealedEvent的子类。接收回调有两种模式:

  1. 注解反射模式:沿用EventBus的@Subscribe注解,通过反射匹配事件类型(性能较低,但兼容旧代码)。
  2. lambda观察者模式:通过observe方法注册指定类型的回调,返回Disposable用于取消订阅。这是密封类方案推荐的方式,类型安全且无需反射。
// 密封类事件定义
sealed class AppEvent : SealedEvent()
class LoginSuccess(val user: User) : AppEvent()
class LogoutAction : AppEvent()

// 注册观察者
val disposable = eventBus.observe(LoginSuccess::class.java) { event ->
    updateUI(event.user)
}

// 发送事件
eventBus.post(LoginSuccess(user))

4.4 接口对比:传统EventBus vs 密封类方案

维度传统EventBus密封类方案(接口抽象)
事件类型限制任意Object强制继承SealedEvent,编译期检查
回调方式注解+反射lambda观察者+类型传参
注册/注销register/unregisterregister/unregister + observe返回Disposable
线程调度内置线程模式注解可由实现层封装CoroutineDispatcher
空安全无保障Kotlin空安全+sealed class穷举

4.5 内联SVG:事件总线核心接口架构图

事件总线核心接口架构 EventBus 接口 register() unregister() post() observe() Subscriber (Any) 回调 Lambda SealedEvent 子类 虚线表示可选方法(observe用于类型安全的lambda回调注册)
设计提示: 将observe返回Disposable对象可以更灵活地取消单个观察者,而不必调用unregister整个订阅者。实现时建议组合使用CoroutineScope与Channel,使回调与生命周期自动绑定。

4.6 实现注意事项

  • 接口的post方法应同步分发事件(或交由调度层异步处理),但接口本身不规定线程模型。
  • 使用密封类后,observe的泛型参数T被限定为SealedEvent子类,编译期即可确保接收正确类型。
  • 如果需要兼容旧项目中的反射注册,可将register实现为混合模式:先扫描注解方法,再注册lambda观察者。