C#總結(六)EventBus事件總線的使用-自己實現事件總線


在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 的簡單實現,各位可以根據自己的實際場景和需求,優化修改。

 


免責聲明!

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



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