Event Bus 与观察者模式在 C# (.NET) 中:从理论到实践
在现代 C# (.NET) 开发中,系统组件之间的松耦合(loose coupling)是核心原则之一。观察者模式(Observer)及其演进——Event Bus(事件总线)——提供了一种优雅的机制,用于在对象之间组织交互,而无需直接依赖。本文将详细讲解如何在 C# (.NET) 中实现 Event Bus,分析其架构,并提供实际示例。
什么是观察者模式?
观察者模式定义了对象之间“一对多”的关系:当一个对象(主体)改变状态时,所有依赖它的对象(观察者)都会自动收到通知并更新。在 C# 中,该模式传统上通过事件(event)和委托来实现。
经典实现的问题
虽然 C# 内置的事件机制运行良好,但它存在一些限制:
- 直接耦合:发布者必须显式知道订阅者。
- 取消订阅困难:如果订阅者忘记取消订阅,会导致内存泄漏。
- 灵活性有限:难以实现异步处理或事件过滤。
什么是 Event Bus?
Event Bus 是一个集中式总线(中介者),它实现了发布者-订阅者(Publisher-Subscriber)模式。与经典的观察者模式不同,发布者和订阅者彼此完全不知晓。它们仅通过总线进行通信:
- 发布者 将消息(事件)发送到总线。
- 总线 查找该事件类型的所有订阅者并通知它们。
- 订阅者 注册到特定事件类型并处理它。
Event Bus 的优势
- 松耦合:组件之间互不依赖。
- 可扩展性:易于添加新的订阅者。
- 可测试性:可以用模拟对象替换总线。
- 异步性:可以在后台线程中处理事件。
在 C# (.NET) 中实现 Event Bus
让我们实现一个简单但功能完整的版本。创建一个 EventBus 类,用于存储订阅者字典。
public interface IEventBus{ void Publish<TEvent>(TEvent eventData) where TEvent : class; IDisposable Subscribe<TEvent>(Action<TEvent> handler) where TEvent : class;}
public class EventBus : IEventBus{ private readonly Dictionary<Type, List<Delegate>> _subscribers = new(); private readonly object _lock = new();
public void Publish<TEvent>(TEvent eventData) where TEvent : class { List<Delegate> handlers; lock (_lock) { if (!_subscribers.TryGetValue(typeof(TEvent), out var list)) return; handlers = new List<Delegate>(list); }
foreach (var handler in handlers) { if (handler is Action<TEvent> action) action(eventData); } }
public IDisposable Subscribe<TEvent>(Action<TEvent> handler) where TEvent : class { lock (_lock) { if (!_subscribers.ContainsKey(typeof(TEvent))) _subscribers[typeof(TEvent)] = new List<Delegate>(); _subscribers[typeof(TEvent)].Add(handler); }
return new Unsubscriber(() => { lock (_lock) { if (_subscribers.TryGetValue(typeof(TEvent), out var list)) list.Remove(handler); }