第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的子类。接收回调有两种模式:
- 注解反射模式:沿用EventBus的
@Subscribe注解,通过反射匹配事件类型(性能较低,但兼容旧代码)。 - 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/unregister | register/unregister + observe返回Disposable |
| 线程调度 | 内置线程模式注解 | 可由实现层封装CoroutineDispatcher |
| 空安全 | 无保障 | Kotlin空安全+sealed class穷举 |
4.5 内联SVG:事件总线核心接口架构图
设计提示: 将
observe返回Disposable对象可以更灵活地取消单个观察者,而不必调用unregister整个订阅者。实现时建议组合使用CoroutineScope与Channel,使回调与生命周期自动绑定。
4.6 实现注意事项
- 接口的
post方法应同步分发事件(或交由调度层异步处理),但接口本身不规定线程模型。 - 使用密封类后,
observe的泛型参数T被限定为SealedEvent子类,编译期即可确保接收正确类型。 - 如果需要兼容旧项目中的反射注册,可将
register实现为混合模式:先扫描注解方法,再注册lambda观察者。