什么是事件總線


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收到優惠通知。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM