什么是事件总线

1 前置阅读

在阅读本文章之前,你可以先阅读:

  • 什么是观察者模式

2 定义

事件总线是实现基于事件驱动模式的方式之一,事件发送者将事件消息发送到一个事件总线上,事件订阅者向事件总线订阅和接收事件,然后再处理接收到的事件。当然,订阅者不仅可以接收和消费事件,它们本身也可以创建事件,并将它们发送到事件总线上。

事件总线是对发布-订阅模式的一种实现。它是一种集中式事件处理机制,允许不同的组件之间进行彼此通信而又不需要相互依赖,达到一种解耦的目的。

3 需求

  • 维护一个事件源与事件处理的映射字典。
  • 提供统一的订阅、取消订阅和发布接口。

3 实现

首先,定义事件源、事件处理、事件总线接口。

namespace Example.EventBus
{
    /// <summary>
    /// 事件源
    /// </summary>
    public class IEvent
    {
    }
}
namespace Example.EventBus
{
    /// <summary>
    /// 事件处理
    /// </summary>
    /// <typeparam name="TEvent">事件源</typeparam>
    public interface IEventHandler<TEvent> where TEvent : IEvent
    {
        void Handle(TEvent @event);
    }
}
namespace Example.EventBus
{
    /// <summary>
    /// 事件总线
    /// </summary>
    public interface IEventBus
    {
        void Publish<TEvent>(TEvent @event) where TEvent : IEvent;

        void Subscribe<TEvent>(IEventHandler<TEvent> eventHandler) where TEvent : IEvent;

        void Unsubscribe<TEvent>(IEventHandler<TEvent> eventHandler) where TEvent : IEvent;
    }
}

然后,实现具体事件总线类。

  1. 事件源与事件处理的映射字典。
private static Dictionary<string, List<object>> eventHandlers = new Dictionary<string, List<object>>();
  1. 实现订阅,往字典表中添加事件处理实例
public void Subscribe<TEvent>(IEventHandler<TEvent> eventHandler) where TEvent : IEvent
{
    var eventTypeName = typeof(TEvent).FullName;
    if (eventAndEventHandlers.ContainsKey(eventTypeName))
    {
        var handlers = eventAndEventHandlers[eventTypeName];
        handlers.Add(eventHandler);
    }
    else
    {
        eventAndEventHandlers.Add(eventTypeName, new List<object> { eventHandler });
    }
}
  1. 实现取消订阅,从字典表中删除事件处理实例
public void Unsubscribe<TEvent>(IEventHandler<TEvent> eventHandler) where TEvent : IEvent
{
    var eventTypeName = typeof(TEvent).FullName;
    if (eventAndEventHandlers.ContainsKey(eventTypeName))
    {
        var handlers = eventAndEventHandlers[eventTypeName];
        if (handlers != null && handlers.Exists(s => s.GetType()==eventHandler.GetType()))
        {
            var handlerToRemove = handlers.First(s => s.GetType() == eventHandler.GetType());
            handlers.Remove(handlerToRemove);
        }
    }
}
  1. 实现发布,通过事件源找到对应的事件处理类,并执行它
public void Publish<TEvent>(TEvent @event) where TEvent : IEvent
{
    var eventTypeName = typeof(TEvent).FullName;
    if (eventAndEventHandlers.ContainsKey(eventTypeName))
    {
        var handlers = eventAndEventHandlers[eventTypeName];
        try
        {
            foreach (var handler in handlers)
            {
                MethodInfo meth = handler.GetType().GetMethod("Handle");
                meth.Invoke(handler, new Object[] { @event });
            }
        }
        catch (Exception ex)
        {
            throw ex;
        }
    }
}

最后,创建客户端类,具体事件源类,具体事件处理类。

using Example.EventBus;
using System;

namespace Eaxmple.EventBus.Sample.ConsoleApp01
{
    /// <summary>
    /// 具体事件源类
    /// </summary>
    public class SendedEvent : IEvent
    {
        public string Name { get; private set; }
        public SendedEvent(string name)
        {
            Name = name;
        }
    }

    /// <summary>
    /// 具体事件处理类顾客A
    /// </summary>
    public class CustomerASendedEventHandler : IEventHandler<SendedEvent>
    {
        public void Handle(SendedEvent @event)
        {
            Console.WriteLine($"顾客A收到{@event.Name}通知!");
        }
    }

    /// <summary>
    /// 具体事件处理类顾客B
    /// </summary>
    public class CustomerBSendedEventHandler : IEventHandler<SendedEvent>
    {
        public void Handle(SendedEvent @event)
        {
            Console.WriteLine($"顾客B收到{@event.Name}通知!");
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            var eventBus = new SampleEventBus();

            var sendedEvent = new SendedEvent("优惠");

            var customerASendedEventHandler = new CustomerASendedEventHandler();
            eventBus.Subscribe<SendedEvent>(customerASendedEventHandler);
            var customerBSendedEventHandler = new CustomerBSendedEventHandler();
            eventBus.Subscribe<SendedEvent>(customerBSendedEventHandler);
            Console.WriteLine($"商店发了{sendedEvent.Name}通知!");
            eventBus.Publish<SendedEvent>(sendedEvent);

            Console.WriteLine();

            eventBus.Unsubscribe<SendedEvent>(customerBSendedEventHandler);
            Console.WriteLine($"商店发了{sendedEvent.Name}通知!");
            eventBus.Publish<SendedEvent>(sendedEvent);

            Console.ReadKey();
        }
    }
}

让我们来看看输出结果:

商店发布优惠通知!
顾客A收到优惠通知。
顾客B收到优惠通知。

商店发布优惠通知!
顾客A收到优惠通知。
posted @ 2021-01-10 11:03  南荣相如  阅读(2139)  评论(0编辑  收藏  举报