在 C# 中, 我们可以在一个类中定义自己的事件, 而其他的类可以订阅该事件, 当某些事情发生时, 可以通知到该类这对于桌面应用或者独立的 windows 服务来说是非常有用的但对于一个 web 应用来说是有点问题的, 因为对象都是在 web 请求中创建的, 而且这些对象生命周期都很短, 因而注册某些类的事件是很困难的此外, 注册其他类的事件会使得类紧耦合事件总线便可以用来解耦并重复利用应用中的逻辑
事件总线带来的好处和引入的问题
好处比较明显, 就是独立出一个发布订阅模块, 调用者可以通过使用这个模块, 屏蔽一些线程切换问题, 简单地实现发布订阅功能
坏处可能比较隐晦, 但这些需要足够引起我们的重视
大量的滥用, 将导致逻辑的分散, 出现问题后很难定位
没办法实现强类型, 在编译的时候就发现问题
代码可读性有些问题, IDE 无法识别这些协议, 对 IDE 不友好
总得来说, 如果项目里面有大量的事件交互, 那么还是可以通过 EventBus 来实现, 否则还是推荐自己在模块内部实现观察者模式
示例代码
所以今天介绍一个简单的事件总线, 它是事件发布订阅模式的实现, 让我们能在领域驱动设计 (DDD) 中以事件的弱引用本质对我们的模块和领域边界很好的解耦设计
目前, 所有的源代码已经提交到 github 上, 地址: https://github.com/weizhong1988/Weiz.EventBus
程序目录结构如下:
事件总线
事件总线是被所有触发并处理事件的其他类共享的单例对象要使用事件总线, 首先应该获得它的一个引用下面有两种方法来处理:
订阅事件
触发事件之前, 应该先要定义该事件 EventBus 为我们提供了 Subscribe 方法来订阅事件:
- public void Subscribe<TEvent>(IEventHandler<TEvent> eventHandler) where TEvent : IEvent
- {
- // 同步锁
- lock (_syncObject)
- {
- // 获取领域模型的类型
- var eventType = typeof(TEvent);
- // 如果此领域类型在事件总线中已注册过
- if (_dicEventHandler.ContainsKey(eventType))
- {
- var handlers = _dicEventHandler[eventType];
- if (handlers != null)
- {
- handlers.Add(eventHandler);
- }
- else
- {
- handlers = new List<object>
- {
- eventHandler
- };
- }
- }
- else
- {
- _dicEventHandler.Add(eventType, new List<object> { eventHandler });
- }
- }
- }
所以的事件都集成自 IEvent, 该类包含了类处理事件需要的属性
- var sendEmailHandler = new UserAddedEventHandlerSendEmail();
- var sendMessageHandler = new UserAddedEventHandlerSendMessage();
- var sendRedbagsHandler = new UserAddedEventHandlerSendRedbags();
- Weiz.EventBus.Core.EventBus.Instance.Subscribe(sendEmailHandler);
- Weiz.EventBus.Core.EventBus.Instance.Subscribe(sendMessageHandler);
- //Weiz.EventBus.Core.EventBus.Instance.Subscribe<UserGeneratorEvent>(sendRedbagsHandler);
- Weiz.EventBus.Core.EventBus.Instance.Subscribe<OrderGeneratorEvent>(sendRedbagsHandler);
发布事件
对于事件源, 则可以通过 Publish 方法发布事件触发一个事件很简单, 如下所示:
- public void Publish<TEvent>(TEvent tEvent, Action<TEvent, bool, Exception> callback) where TEvent : IEvent
- {
- var eventType = typeof(TEvent);
- if (_dicEventHandler.ContainsKey(eventType) && _dicEventHandler[eventType] != null &&
- _dicEventHandler[eventType].Count> 0)
- {
- var handlers = _dicEventHandler[eventType];
- try
- {
- foreach (var handler in handlers)
- {
- var eventHandler = handler as IEventHandler<TEvent>;
- eventHandler.Handle(tEvent);
- callback(tEvent, true, null);
- }
- }
- catch (Exception ex)
- {
- callback(tEvent, false, ex);
- }
- }
- else
- {
- callback(tEvent, false, null);
- }
- }
下面是发布事件的调用:
- var orderGeneratorEvent = new OrderGeneratorEvent { OrderId = Guid.NewGuid() };
- System.Console.WriteLine("{0}下单成功", orderGeneratorEvent.OrderId);
- Weiz.EventBus.Core.EventBus.Instance.Publish(orderGeneratorEvent, CallBack);
定义处理事件
要处理一个事件, 应该要实现 IEventHandler 接口, 如下所示:
- /// <summary>
- /// send email
- /// </summary>
- public class UserAddedEventHandlerSendEmail : IEventHandler<UserGeneratorEvent>
- {
- public void Handle(UserGeneratorEvent tEvent)
- {
- System.Console.WriteLine(string.Format("{0}的邮件已发送", tEvent.UserId));
- }
- }
处理多事件
在一个单一的处理句柄中, 可以处理多个事件这时, 你应该为每个事件实现 IEventHandler 比如:
- /// <summary>
- /// red bags.
- /// </summary>
- public class UserAddedEventHandlerSendRedbags : IEventHandler<UserGeneratorEvent>,IEventHandler<OrderGeneratorEvent>
- {
- public void Handle(OrderGeneratorEvent tEvent)
- {
- System.Console.WriteLine(string.Format("{0}的下单红包已发送", tEvent.OrderId));
- }
- public void Handle(UserGeneratorEvent tEvent)
- {
- System.Console.WriteLine(string.Format("{0}的注册红包已发送", tEvent.UserId));
- }
- }
最后
以上, 就把事件总线介绍完了, 完整的代码, 请到 github 上下载, 这个只是 EventBus 的简单实现, 各位可以根据自己的实际场景和需求, 优化修改
来源: https://www.cnblogs.com/zhangweizhong/p/8544158.html