GeWuYou a79f02c987 docs(api): 添加 Core API 参考文档与事件系统接口文档
- 新增 Core API 参考文档,涵盖架构与模块、数据模型与系统、命令与查询等核心组件
- 添加事件系统接口详细文档,包括 IEvent、IEventBus、IUnRegister 等接口说明
- 提供完整的 API 使用示例路径、最佳实践与性能建议
- 包含架构图、依赖关系图与故障排查指南
- 添加测试用例参考与扩展方法说明
- [skip ci]
2026-01-21 23:45:10 +08:00

19 KiB
Raw Blame History

事件系统设计

**本文引用的文件** - [EasyEvent.cs](file://GFramework.Core/events/EasyEvent.cs) - [EasyEventGeneric.cs](file://GFramework.Core/events/EasyEventGeneric.cs) - [EventBus.cs](file://GFramework.Core/events/EventBus.cs) - [EasyEvents.cs](file://GFramework.Core/events/EasyEvents.cs) - [ArchitectureEvents.cs](file://GFramework.Core/events/ArchitectureEvents.cs) - [OrEvent.cs](file://GFramework.Core/events/OrEvent.cs) - [DefaultUnRegister.cs](file://GFramework.Core/events/DefaultUnRegister.cs) - [UnRegisterList.cs](file://GFramework.Core/events/UnRegisterList.cs) - [IEvent.cs](file://GFramework.Core.Abstractions/events/IEvent.cs) - [IEventBus.cs](file://GFramework.Core.Abstractions/events/IEventBus.cs) - [OrEventExtensions.cs](file://GFramework.Core/extensions/OrEventExtensions.cs) - [UnRegisterListExtension.cs](file://GFramework.Core/extensions/UnRegisterListExtension.cs) - [SettingsChangedEvent.cs](file://GFramework.Game/setting/events/SettingsChangedEvent.cs) - [SettingsBatchChangedEvent.cs](file://GFramework.Game/setting/events/SettingsBatchChangedEvent.cs) - [EventTests.cs](file://GFramework.Core.Tests/events/EventTests.cs)

目录

  1. 引言
  2. 项目结构
  3. 核心组件
  4. 架构总览
  5. 详细组件分析
  6. 依赖分析
  7. 性能考虑
  8. 故障排查指南
  9. 结论
  10. 附录:事件命名与结构最佳实践

引言

本文件面向GFramework的事件系统系统性阐述事件命名规范、事件结构设计以及事件处理职责分配的最佳实践并结合仓库中的具体实现给出类型安全的事件结构、单一职责的事件处理器设计、性能优化建议与测试与调试策略。读者无需深入源码即可理解并应用这些实践。

项目结构

事件系统位于GFramework.Core/events目录围绕“事件类型 + 事件总线 + 注销机制”构建同时提供组合事件与全局事件管理能力。游戏层在GFramework.Game/setting/events中提供了领域事件示例设置变更事件体现事件在业务场景中的落地方式。

graph TB
subgraph "核心事件模块(GFramework.Core)"
A["EasyEvent.cs"]
B["EasyEventGeneric.cs"]
C["EventBus.cs"]
D["EasyEvents.cs"]
E["OrEvent.cs"]
F["DefaultUnRegister.cs"]
G["UnRegisterList.cs"]
H["IEvent.cs"]
I["IEventBus.cs"]
J["OrEventExtensions.cs"]
K["UnRegisterListExtension.cs"]
end
subgraph "游戏层事件(GFramework.Game)"
L["SettingsChangedEvent.cs"]
M["SettingsBatchChangedEvent.cs"]
end
C --> D
C --> B
D --> B
E --> F
J --> E
K --> G
L --> I
M --> I

图表来源

章节来源

核心组件

  • 事件接口与基础事件
    • IEvent定义无参事件注册接口便于统一处理。
    • EasyEvent无参事件支持注册/注销/触发。
    • Event、Event<T,TK>:单/双参数泛型事件显式实现IEvent以支持无参订阅。
  • 事件总线与全局事件管理
    • IEventBus定义Send/Register/UnRegister接口。
    • EventBus基于类型分发的事件总线内部使用EasyEvents管理事件实例。
    • EasyEvents全局事件容器按类型缓存事件实例支持Get/GetOrAdd/Add。
  • 组合与注销
    • OrEvent事件“或”组合任一子事件触发即触发自身。
    • DefaultUnRegister一次性注销器执行回调并清理引用。
    • UnRegisterList批量注销器集中管理多个注销器。
  • 游戏层事件示例
    • SettingsChangedEvent类型化设置变更事件。
    • SettingsBatchChangedEvent批量设置变更事件。

章节来源

架构总览

事件系统采用“类型驱动 + 全局容器 + 总线分发”的架构。事件通过类型标识由EventBus统一调度EasyEvents负责事件实例的缓存与复用OrEvent支持事件组合DefaultUnRegister/UnRegisterList保障生命周期管理。

classDiagram
class IEvent {
+Register(onEvent) IUnRegister
}
class EasyEvent {
+Register(onEvent) IUnRegister
+UnRegister(onEvent) void
+Trigger() void
}
class Event_T_ {
+Register(onEvent) IUnRegister
+UnRegister(onEvent) void
+Trigger(t) void
+Register(Action) IUnRegister
}
class Event_T_TK_ {
+Register(onEvent) IUnRegister
+UnRegister(onEvent) void
+Trigger(t, tk) void
+Register(Action) IUnRegister
}
class IEventBus {
+Send~T~() void
+Send~T~(e) void
+Register~T~(onEvent) IUnRegister
+UnRegister~T~(onEvent) void
}
class EventBus {
-EasyEvents _mEvents
+Send~T~() void
+Send~T~(e) void
+Register~T~(onEvent) IUnRegister
+UnRegister~T~(onEvent) void
}
class EasyEvents {
-Dictionary~Type,IEvent~ _mTypeEvents
+Get~T~() T
+Register~T~() void
+GetOrAdd~T~() T
+AddEvent~T~() void
+GetEvent~T~() T
+GetOrAddEvent~T~() T
}
class OrEvent {
+Or(event) OrEvent
+Register(onEvent) IUnRegister
+UnRegister(onEvent) void
-Trigger() void
}
class DefaultUnRegister {
+UnRegister() void
}
class UnRegisterList {
+Add(unRegister) void
+UnRegisterAll() void
}
IEvent <|.. EasyEvent
IEvent <|.. Event_T_
IEvent <|.. Event_T_TK_
IEventBus <|.. EventBus
EventBus --> EasyEvents : "使用"
OrEvent --> DefaultUnRegister : "组合"
UnRegisterList --> DefaultUnRegister : "管理"

图表来源

详细组件分析

事件接口与基础事件

  • 设计要点
    • IEvent仅暴露无参注册便于统一处理与扩展。
    • EasyEvent提供最简事件模型适合广播型通知。
    • Event/Event<T,TK>显式实现IEvent.Register(Action),允许“无参订阅”,同时保留强类型参数触发。
  • 使用建议
    • 优先使用Event进行领域事件建模确保参数类型安全。
    • 无参事件仅用于系统级广播,避免承载复杂状态。

章节来源

事件总线与全局事件管理

  • 设计要点
    • EventBus基于类型分发Send()自动构造事件实例Send(e)直接触发实例。
    • 内部使用EasyEvents缓存事件实例避免重复创建。
    • Register/UnRegister通过类型键控保证事件隔离。
  • 使用建议
    • 事件类型应具备无参构造函数以便自动构造。
    • 对于频繁触发的事件优先使用EventBus.Send(e)传入实例,减少构造开销。

章节来源

组合事件与注销机制

  • 设计要点
    • OrEvent将多个事件“或”组合任一子事件触发即触发自身通过扩展方法Or(IEvent)链式组合。
    • DefaultUnRegister封装一次性的注销回调避免重复注销。
    • UnRegisterList集中管理多个注销器提供批量注销能力。
  • 使用建议
    • 使用OrEvent简化多事件聚合场景如“任意加载完成”
    • 在对象生命周期结束时调用UnRegisterAll确保资源回收。

章节来源

游戏层事件示例

  • 设计要点
    • SettingsChangedEvent携带类型化设置实例与变更时间便于处理器按类型处理。
    • SettingsBatchChangedEvent表示批量变更适合聚合处理。
  • 使用建议
    • 领域事件尽量携带必要上下文(如时间戳、来源),提升可观测性。
    • 批量事件用于降低事件风暴,提高处理效率。

章节来源

事件序列与调用流程

以下序列图展示了EventBus.Send()的典型调用路径。

sequenceDiagram
participant Sender as "发送方"
participant Bus as "EventBus"
participant Events as "EasyEvents"
participant EventT as "Event<T>"
participant Handler as "事件处理器"
Sender->>Bus : "Send<T>() 或 Send<T>(e)"
Bus->>Events : "GetOrAddEvent<Event<T>>()"
Events-->>Bus : "Event<T> 实例"
Bus->>EventT : "Trigger(实例或new T())"
EventT->>Handler : "回调执行"
Handler-->>EventT : "处理完成"
EventT-->>Bus : "全部回调完成"
Bus-->>Sender : "发送完成"

图表来源

依赖分析

  • 组件耦合
    • EventBus依赖EasyEvents与Event族形成“总线-容器-事件”的分层。
    • OrEvent依赖DefaultUnRegisterUnRegisterList管理多个注销器。
  • 外部接口
    • IEvent/IEventBus提供抽象契约便于替换实现与测试。
  • 循环依赖
    • 未发现循环依赖;事件类型通过类型键控,避免运行时耦合。
graph LR
IEvent["IEvent 接口"] --> EasyEvent["EasyEvent"]
IEvent --> EventT["Event<T>"]
IEvent --> EventTTK["Event<T,TK>"]
IEventBus["IEventBus 接口"] --> EventBus["EventBus"]
EventBus --> EasyEvents["EasyEvents"]
EventBus --> EventT
OrEvent["OrEvent"] --> DefaultUnRegister["DefaultUnRegister"]
UnRegisterList["UnRegisterList"] --> DefaultUnRegister

图表来源

章节来源

性能考虑

  • 事件过滤
    • 使用EventBus.Send(e)传入实例,避免每次触发都构造新事件对象。
    • 对高频事件建议复用事件实例并更新字段减少GC压力。
  • 批量处理
    • 使用UnRegisterList集中注销避免逐个注销带来的遍历成本。
    • 使用OrEvent组合多个事件减少多次订阅与触发的成本。
  • 内存管理
    • 事件处理器应尽快UnRegister防止闭包捕获导致的长生命周期对象滞留。
    • 对长生命周期对象,避免在事件处理器中持有强引用。
  • 并发与线程
    • 事件回调在触发时同步执行,避免跨线程访问共享状态;如需异步处理,请在回调内调度至目标线程。

[本节为通用性能建议,不直接分析具体文件]

故障排查指南

  • 常见问题
    • 回调未触发检查是否正确注册、是否被提前UnRegister、事件类型是否匹配。
    • 内存泄漏确认处理器在对象销毁时调用UnRegisterAll或单独UnRegister。
    • 事件风暴:合并为批量事件或引入节流/去抖策略。
  • 调试技巧
    • 在事件处理器中记录上下文(如时间戳、来源),便于定位问题。
    • 使用单元测试验证事件注册/注销/触发的正确性。
  • 单元测试参考
    • 测试覆盖了EasyEvent与Event/Event<T,TK>的注册、注销与多处理器调用行为,可作为编写自测的模板。

章节来源

结论

GFramework的事件系统以类型安全为核心通过EventBus与EasyEvents实现高效分发与复用OrEvent与注销机制保障了组合与生命周期管理。遵循本文的命名与结构规范、单一职责的处理器设计、以及性能与测试策略可在复杂游戏中稳定地构建可维护的事件体系。

[本节为总结性内容,不直接分析具体文件]

附录:事件命名与结构最佳实践

事件命名规范

  • 无参事件:使用动词短语,如“系统就绪”、“开始销毁”等,体现广播性质。
    • 示例ArchitectureLifecycleReadyEvent、ArchitectureDestroyingEvent、ArchitectureDestroyedEvent、ArchitectureFailedInitializationEvent
  • 领域事件:使用“名词+动作+对象”的结构,明确事件主体与影响对象。
    • 示例PlayerHealthChangedEvent、PlayerDiedEvent、LevelCompletedEvent、SettingsChangedEvent
  • 批量事件:描述聚合行为,强调“批量”而非单点。
    • 示例SettingsBatchChangedEvent

章节来源

事件结构设计

  • 类型安全
    • 使用Event或Event<T,TK>承载参数避免使用object或动态类型。
    • 领域事件尽量携带必要上下文(如时间戳、来源、类型信息)。
  • 不变性与复用
    • 对高频事件复用事件实例并更新字段减少GC。
    • 避免在事件中保存长生命周期对象的强引用。
  • 可观测性
    • 为事件添加时间戳与来源标识,便于日志与追踪。

章节来源

事件处理职责分配

  • 单一职责
    • UIHealthBarController仅处理与健康值显示相关的事件避免混入音频、逻辑等职责。
    • AudioController仅处理与音效播放相关的事件避免混入UI逻辑。
  • 分层解耦
    • 事件总线负责分发,处理器负责具体业务逻辑,避免处理器直接依赖其他处理器。
  • 生命周期管理
    • 在对象销毁时统一调用UnRegisterAll确保事件链路完整释放。

章节来源

事件系统测试策略

  • 行为验证
    • 验证注册/注销是否生效、多处理器是否均被调用、参数传递是否正确。
  • 边界条件
    • 空处理器集合、重复注册/注销、并发触发等。
  • 回归测试
    • 使用EventTests类似的断言模式覆盖关键事件路径。

章节来源