设计系列-事件总线(EventBus)

一、前言

  事件是基于委托的发布-订阅机制(基于windows消息处理机制)通过定义事件,订阅事件、发布事件并且关联业务逻辑,实现系统业务的解耦。发布-订阅机制提供了一种天然的业务解耦方式,所以在系统中使用事件定义业务状态、业务场景,让关联的业务订阅事件,当事件产生时事件订阅者执行业务,这样发布者不必知道订阅者具体的细节、订阅者也不必了解发布者。但是简单的事件无法满足实际生产的使用,因为生产中的业务是复杂的,多样的,所以就要设计一种框架来统一管理事件设计成事件总线。

二、设计

  

 

  事件总线进行抽象成如下接口关系图,IEventBus作为事件总线进行协调管理事件的发布订阅,作为事件中心承担的职责除了事件的发布和订阅之外,还包括对事件存储、容错、路由、异步、重试等。

事件总线类说明
IEvent 事件载体的接口,所有事件继承该接口,定义一个事件,并且赋予事件相应的业务逻辑,比如这个事件要产生的业务操作
IEventHandler 事件处理接口,每一个事件都必须关联相应的事件操作
IEventSubscriber 发布订阅机制的订阅事件接口,主要功能订阅事件关联事件处理器
IEventPublisher 发布订阅机制的发布事件接口,主要功能对产生的事件进行发布
IEventBus 事件总线接口,通过聚合事件的发布和订阅接口,在内部抽象成一个总线的方式统一管理事件,并且引入事件消息存储结构

 三、代码

  依据上述的事件总线接口关系图,在代码上定义各接口类,然后定义接口的关系创建一个初步的事件总线,通过事件总线接口来实现具体事件总线框架。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace TQF.EventBus.EventFramwork
{

    /// <summary>
    /// 事件消息接口,定义一个事件,事件载体
    /// </summary>
    public interface IEvent
    {
        /// <summary>
        /// 事件Id
        /// </summary>
        Guid EventId { get; }

        /// <summary>
        /// 事件时间
        /// </summary>
        DateTime EventDate { get; }
    }
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace TQF.EventBus.EventFramwork
{
    /// <summary>
    /// 事件处理接口,定义一个事件对应的处理逻辑
    /// </summary>
    public interface IEventHandler
    {
        /// <summary>
        /// 定义事件异步的处理器
        /// </summary>
        /// <param name="event">使用@区分关键字</param>
        /// <param name="cancellationToken">任务取消令牌,取消任务</param>
        /// <returns></returns>
        Task<bool> HandlerAsync(IEvent @event, CancellationToken cancellationToken = default);
        bool CanHandle(IEvent @event);
    }

    /// <summary>
    /// 泛型事件处理器
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public interface IEventHandler<in T> : IEventHandler where T : IEvent
    {
        Task<bool> HandleAsync(T @event, CancellationToken cancellationToken = default);
    }
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace TQF.EventBus.EventFramwork
{
    /// <summary>
    /// 事件发布器,发布消息
    /// </summary>
    public interface IEventPublisher:IDisposable
    {
        /// <summary>
        /// 事件发布器,发布事件
        /// </summary>
        /// <typeparam name="TEvent"></typeparam>
        /// <param name="event">事件</param>
        /// <param name="cancellationToken">任务取消令牌,取消任务</param>
        /// <returns></returns>
        Task PublishAsync<TEvent>(TEvent @event, CancellationToken cancellationToken = default)
        where TEvent : IEvent;
    }
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace TQF.EventBus.EventFramwork
{
    /// <summary>
    /// 事件订阅器订阅消息
    /// </summary>
    public interface IEventSubscriber:IDisposable
    {
        void Subscriber();
    }
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace TQF.EventBus.EventFramwork
{
    /// <summary>
    /// 事件总线接口,定义事件通讯渠道,消息订阅功能,消息派发功能(消息的路由,过滤,选择)等。
    /// 通过事件总线管理两者
    /// </summary>
    public interface IEventBus:IEventPublisher,IEventSubscriber
    {
    }
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace TQF.EventBus.EventFramwork
{
    /// <summary>
    /// 定义事件传递的参数
    /// </summary>
    public class EventProcessedEventArgs:EventArgs
    {
        public IEvent Event { get; }

        public EventProcessedEventArgs(IEvent @event)
        {
            this.Event = @event;
        }
    }
}

四、总结

  1、事件总线的目的是对业务的解耦,通过设计合理的架构来达到这个目标,既然是合理的框架,就涉及到存储、容错、路由、异步、重试等问题,所以上述提供是一个事件总线雏形。

  2、对于模式和架构,一个模式,一个架构其构成的最小单位可以理解为对象,通过对对象的划分、割裂,单独成个体,通过关系连接这些个体,建立起一个模型->模式->架构。

posted @ 2021-11-30 17:08  tuqunfu  阅读(1218)  评论(0编辑  收藏  举报