定义事件通用基类:sealed class Event 与派生事件
为什么选择密封类作为事件基类
事件总线的核心是事件类型定义。传统事件总线(如 EventBus)使用 Object 或任意 Any 作为事件载体,导致类型不安全、运行时强制转换、订阅者需要手动检查类型。Kotlin 密封类提供了 受限的类层次,所有事件必须声明在同一个编译单元内,编译器能够穷举所有子类型,搭配 when 表达式实现编译期安全检查。
核心优势:无反射、无字符串标签、无运行时类型擦除——每个事件都是确定的、类型安全的。
密封事件基类定义
定义一个 sealed class Event 作为所有事件的统一基类。派生类使用 data class、object 或 data class 来表达不同复杂度的事件载荷。
// 事件基类
sealed class Event {
// 防止外部直接继承,所有子类必须在同一文件或嵌套声明
}
// 带用户数据的事件(数据类)
data class LoginEvent(val userId: String, val timestamp: Long) : Event()
// 无参数事件(单例对象)
object LogoutEvent : Event()
// 带泛型载荷的事件
data class DataEvent<T>(val payload: T, val source: String) : Event()
| 派生类型 | Kotlin 关键词 | 典型用途 | 内存开销 |
|---|---|---|---|
| 数据类(data class) | data class | 携带多字段、必须对比相等性的事件(如网络响应、表单提交) | 每个实例独立 |
| 对象类(object) | object | 无额外数据、全局唯一的信号(如退出登录、切换主题) | 单例,零重复 |
| 泛型数据类 | data class<T> | 载荷类型可变的事件(如列表刷新、泛型消息) | 泛型擦除,实例化后与具体类型绑定 |
实战建议:将
Event 定义为 sealed interface 也可行,但 sealed class 允许在基类中存储通用属性(如事件 ID、分发时间戳),且兼容 Java 互调(密封接口需要 Kotlin 1.5+)。本课程统一使用 sealed class。
密封类层次结构图示
下图展示了事件基类与三种典型派生事件的继承关系,以及编译期穷举检查的工作点:
事件分发的 when 穷举处理
密封类最大的实战价值在于 when 表达式必须是穷举的(exhaustive)。增加新事件类型时,所有使用 when 订阅的地方会产生编译错误,强迫开发者处理新事件,避免遗漏逻辑。
fun handleEvent(event: Event) {
when (event) {
is LoginEvent -> {
// event 已自动智能转换为 LoginEvent
saveLogin(event.userId, event.timestamp)
}
is LogoutEvent -> {
clearSession()
}
is DataEvent<*> -> {
// 泛型擦除,payload 只能作为 Any 使用
processPayload(event.payload)
}
// 无需 else 分支——编译器证明已穷举
}
}
注意:当使用
DataEvent<T> 时,由于泛型类型擦除,when 分支中不能直接获取 T 的具体类型。建议在事件内部提供类型判断辅助函数,或者避免使用泛型事件作为唯一区分条件。
通用事件基类的扩展设计
实际项目中,可以在 Event 基类中加入通用字段,例如事件发布时间戳、事件优先级,所有派生类自动继承:
sealed class Event(
val id: Long = System.currentTimeMillis() // 每个事件带唯一时间戳ID
) {
open val priority: Int = 0 // 默认优先级
}
data class LoginEvent(val userId: String) : Event() {
override val priority: Int = 10 // 登录事件高优先级
}
| 基类能力 | 实现方式 | 典型应用 |
|---|---|---|
| 时间戳 | 构造函数默认值 | 日志追踪、事件顺序 |
| 事件优先级 | open val | 分发队列调度 |
| 取消标记 | var isConsumed | 防止重复处理 |
| 来源标识 | val source: String | 事件溯源、调试 |
通过合理设计基类,可以将事件总线的共性逻辑上移,减少每个派生类的重复代码,同时保持密封类的类型安全特性。