天天看點

開源一個特别簡單的事件總線元件:Weiz.EventBus

在C#中,我們可以在一個類中定義自己的事件,而其他的類可以訂閱該事件,當某些事情發生時,可以通知到該類。這對于桌面應用或者獨立的windows服務來說是非常有用的。但對于一個web應用來說是有點問題的,因為對象都是在web請求中建立的,而且這些對象生命周期都很短,因而注冊某些類的事件是很困難的。此外,注冊其他類的事件會使得類緊耦合。事件總線便可以用來解耦并重複利用應用中的邏輯。

一、說明

是以今天介紹一個簡單的事件總線,它是事件釋出訂閱模式的實作,讓我們能在領域驅動設計(DDD)中以事件的弱引用本質對我們的子產品和領域邊界很好的解耦設計。

目前,所有的源代碼已經送出到github 上,位址:

https://github.com/weizhong1988/Weiz.EventBus

程式目錄結構如下:

開源一個特别簡單的事件總線元件:Weiz.EventBus

二、事件總線帶來的好處和引入的問題

好處比較明顯,就是獨立出一個

釋出訂閱子產品

,調用者可以通過使用這個子產品,屏蔽一些線程切換問題,簡單地實作釋出訂閱功能。

壞處可能比較隐晦,但這些需要足夠引起我們的重視

  • 大量的濫用,将導緻邏輯的分散,出現問題後很難定位。
  • 沒辦法實作強類型,在編譯的時候就發現問題。
  • 代碼可讀性有些問題,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、運作驗證

接下來運作上面的示例程式,檢視事件訂閱的情況。

開源一個特别簡單的事件總線元件:Weiz.EventBus

我們看到人員注冊成功後,成功觸發了郵件消息事件、短信消息事件、紅包消息事件。 下單成功後,自動觸發紅包事件。

最後

以上,就把事件總線介紹完了,完整的代碼,請到github 上下載下傳,這個隻是EventBus 的簡單實作,各位可以根據自己的實際場景和需求,優化修改。

繼續閱讀