开源一个特别简单的事件总线组件:Weiz.EventBus

简介: 在C#中,我们可以在一个类中定义自己的事件,而其他的类可以订阅该事件,当某些事情发生时,可以通知到该类。这对于桌面应用或者独立的windows服务来说是非常有用的。但对于一个web应用来说是有点问题的,因为对象都是在web请求中创建的,而且这些对象生命周期都很短,因而注册某些类的事件是很困难的。此外,注册其他类的事件会使得类紧耦合。事件总线便可以用来解耦并重复利用应用中的逻辑。

在C#中,我们可以在一个类中定义自己的事件,而其他的类可以订阅该事件,当某些事情发生时,可以通知到该类。这对于桌面应用或者独立的windows服务来说是非常有用的。但对于一个web应用来说是有点问题的,因为对象都是在web请求中创建的,而且这些对象生命周期都很短,因而注册某些类的事件是很困难的。此外,注册其他类的事件会使得类紧耦合。事件总线便可以用来解耦并重复利用应用中的逻辑。

 

一、说明

所以今天介绍一个简单的事件总线,它是事件发布订阅模式的实现,让我们能在领域驱动设计(DDD)中以事件的弱引用本质对我们的模块和领域边界很好的解耦设计。

目前,所有的源代码已经提交到github 上,地址:https://github.com/weizhong1988/Weiz.EventBus

程序目录结构如下:

image.png


二、事件总线带来的好处和引入的问题

好处比较明显,就是独立出一个发布订阅模块,调用者可以通过使用这个模块,屏蔽一些线程切换问题,简单地实现发布订阅功能。

坏处可能比较隐晦,但这些需要足够引起我们的重视

  • 大量的滥用,将导致逻辑的分散,出现问题后很难定位。
  • 没办法实现强类型,在编译的时候就发现问题。
  • 代码可读性有些问题,IDE无法识别这些协议,对IDE不友好。

总得来说,如果项目里面有大量的事件交互,那么还是可以通过EventBus来实现,否则还是推荐自己在模块内部实现观察者模式。


三、Weiz.EventBus介绍

Weiz.EventBus事件总线是被所有触发并处理事件的其他类共享的单例对象。要使用事件总线,首先应该获得它的一个引用。下面有两种方法来处理:

1、订阅事件

触发事件之前,应该先要定义该事件。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);



2、发布事件

对于事件源,则可以通过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);

发布订单下单成功通知消息。


四、定义处理事件

1、定义处理事件

要处理一个事件,应该要实现IEventHandler接口,如下所示:

/// <summary>
    /// send email
    /// </summary>
    public class UserAddedEventHandlerSendEmail : IEventHandler<UserGeneratorEvent>
    {
        public void Handle(UserGeneratorEvent tEvent)
        {
            System.Console.WriteLine(string.Format("{0}的邮件已发送", tEvent.UserId));
        }
    }

这里定义了一个用户注册成功后,发送邮件通知事件。


2、处理多事件

在一个单一的处理句柄中,可以处理多个事件。这时,你应该为每个事件实现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));
        }
    }

这里定义了多个时间,包括下单发送红包事件和人员注册发送红包事件。


3、运行验证

接下来运行上面的示例程序,查看事件订阅的情况。

image.png

我们看到人员注册成功后,成功触发了邮件消息事件、短信消息事件、红包消息事件。  下单成功后,自动触发红包事件。  


最后


以上,就把事件总线介绍完了,完整的代码,请到github 上下载,这个只是EventBus 的简单实现,各位可以根据自己的实际场景和需求,优化修改。

 

相关文章
|
4月前
|
资源调度 JavaScript 前端开发
Vue3+TypeScript前端项目新纪元:揭秘高效事件总线Mitt,轻松驾驭组件间通信的艺术!
【8月更文挑战第3天】Vue3结合TypeScript强化了类型安全与组件化开发。面对大型应用中复杂的组件通信挑战,可通过引入轻量级事件发射器Mitt实现事件总线模式。Mitt易于集成,通过简单几步即可完成安装与配置:安装Mitt、创建事件总线实例、并在组件中使用`emit`与`on`方法发送及监听事件。此外,利用TypeScript的强大类型系统确保事件处理器正确无误。这种方式有助于保持代码整洁、解耦组件,同时提高应用的可维护性和扩展性。不过,在大规模项目中需谨慎使用,以防事件流过于复杂难以管理。
125 1
|
4月前
Vue3使用Mitt中央事件总线实现组件之间通讯(发布订阅库)
Vue3使用Mitt中央事件总线实现组件间的发布订阅通信,替代了Vue2中已移除的EventBus。
488 0
|
7月前
|
JavaScript 前端开发 API
从入门到项目实战 - VUE组件跨通信:vue2 与 vue3 中实现全局事件总线
从入门到项目实战 - VUE组件跨通信:vue2 与 vue3 中实现全局事件总线
427 0
|
JavaScript
Vue全局事件总线(任意组件间通信)
Vue全局事件总线(任意组件间通信)
|
JavaScript
【Vue组件间通信】 全局事件总线、订阅与发布
本章学习全局事件总线、订阅与发布。
157 0
【Vue组件间通信】 全局事件总线、订阅与发布
|
JavaScript
「后端小伙伴来学前端了」Vue中利用全局事件总线实现组件之间通信
「后端小伙伴来学前端了」Vue中利用全局事件总线实现组件之间通信
182 0
「后端小伙伴来学前端了」Vue中利用全局事件总线实现组件之间通信
|
JavaScript 前端开发
Vue事件车,非父子组件通讯$bus,$event,中央事件总线
Vue事件车,非父子组件通讯$bus,$event,中央事件总线
203 0
|
JavaScript
vue - 组件间通信 之 中央事件总线bus
中央事件总线 - 就是一个名字可以叫做bus的vue空实例,里边没有任何内容; var bus = new Vue(); 人如其名,她就像一个公交车一样,来回输送人,将a站点的A输送到b站点,再将b站点的B输送到a站点; 这里a,b站点就像父、子组件,也像兄、弟组件,或者像两个没有任何亲戚关系的任何组件; 而A,B就像是各个组件内部要传输的数据或者要执行的命令信息,靠bus来通信。
1995 0
|
2月前
|
JavaScript 调度
Vue事件总线(EventBus)使用指南:详细解析与实战应用
Vue事件总线(EventBus)使用指南:详细解析与实战应用
89 1
|
4月前
|
JavaScript
Vue学习之--------全局事件总线(2022/8/22)
这篇文章介绍了Vue中全局事件总线(GlobalEventBus)的概念和使用方法,它允许不同组件之间进行通信。文章通过图解和代码实例详细解释了如何安装全局事件总线、在组件中接收和提供数据,以及如何在组件销毁前解绑事件,以避免潜在的内存泄漏问题。
Vue学习之--------全局事件总线(2022/8/22)