Unity 事件管理器(EventManager)与事件分发器(EventDispatcher)对比
1. 核心定位差异
特性 | EventManager | EventDispatcher |
---|---|---|
设计模式 | 全局单例,集中式管理 | 模块化设计,独立分发 |
耦合度 | 高(全局依赖) | 低(局部自治) |
作用域 | 全局范围 | 对象/模块级别 |
2. 实现方式对比
EventManager(静态单例)
// 静态单例模式
public class EventManager {
private static Dictionary<string, Action<object>> _events = new();
public static void Subscribe(string eventName, Action<object> handler) {
if (!_events.ContainsKey(eventName)) _events[eventName] = null;
_events[eventName] += handler;
}
public static void Trigger(string eventName, object data = null) {
_events[eventName]?.Invoke(data);
}
}
// 使用示例
EventManager.Subscribe("PlayerDeath", HandleDeath);
EventManager.Trigger("PlayerDeath", deathData);
EventDispatcher(对象级组件)
// 可附加到任意对象的组件
public class EventDispatcher : MonoBehaviour {
private Dictionary<string, UnityEvent> _events = new();
public void AddListener(string eventName, UnityAction handler) {
if (!_events.ContainsKey(eventName)) _events[eventName] = new UnityEvent();
_events[eventName].AddListener(handler);
}
public void Dispatch(string eventName) {
_events[eventName]?.Invoke();
}
}
// 使用示例(对象级通信)
enemyDispatcher.AddListener("Attack", OnEnemyAttack);
enemyDispatcher.Dispatch("Attack");
3. 关键特性对比
特性 | EventManager | EventDispatcher |
---|---|---|
作用域 | 全局应用范围 | 局部作用域(对象/模块级别) |
耦合度 | 高(全局依赖) | 低(局部自治) |
事件冲突风险 | 高(全局命名需严格规范) | 低(隔离作用域) |
内存管理 | 需手动清理全局监听 | 可随对象销毁自动释放 |
适用场景 | 跨系统通信(如游戏状态变更) | 对象间通信(如UI交互、实体行为) |
4. 性能与安全性
-
EventManager
✅ 适合低频全局事件(如GamePause、LevelLoaded)
❌ 高频事件可能导致性能瓶颈
⚠️ 需防范事件名冲突和无效监听 -
EventDispatcher
✅ 高频局部事件更高效(如ButtonClick、DamageTaken)
✅ 天然支持事件作用域隔离
✅ 通过对象生命周期自动管理监听
5. 设计哲学对比
-
EventManager → 中心化控制
符合传统事件总线模式,适合需要跨层级通信的场景,但需警惕成为"上帝对象" -
EventDispatcher → 去中心化架构
符合ECS/组件化设计思想,通过职责分离提高代码可维护性,更适合复杂项目
6. 最佳实践建议
-
混合使用
-
用 EventManager 处理全局系统级事件(如场景加载、游戏暂停)
-
用 EventDispatcher 处理对象/模块内部通信(如UI按钮点击、敌人受击)
-
-
使用强类型事件
避免字符串匹配,改用 enum 或自定义事件类:
public enum GameEventType { PlayerSpawn, EnemyDestroyed }
// 或
public class PlayerDeathEvent : UnityEvent<Vector3, int> {}
- 结合 ScriptableObject
创建可配置的事件通道(Event Channels)实现解耦:
[CreateAssetMenu]
public class GameEventChannel : ScriptableObject {
public UnityAction OnTriggered;
public void Trigger() => OnTriggered?.Invoke();
}
总结选择策略
-
选择 EventManager:
- 项目规模较小
- 需要快速实现跨系统通信
- 不介意全局依赖
-
选择 EventDispatcher:
- 项目复杂度高
- 需要模块化、可测试的架构
- 关注内存安全性和作用域隔离