ABP之事件總線(4)


在上一篇的隨筆中,我們已經初步完成了EventBus,但是EventBus中還有諸多的問題存在,那么到底有什么問題呢,接下來我們需要看一看ABP中的源碼是如何定義EventBus的。

1.第一個點

 

在ABP中提供了對Action類型的支持,而我們的自己定義的類中只是針對繼承了IEventHandler的接口的類

2.第二個點

在ABP中使用了線程安全的ConcurrentDictionary來存放映射關系,因為EventBus作為一個單例存在,這是必須要考慮的。ConcurrentDictionary雖然保證了字典的線程安全,但是並不能保證List的線程安全,可能存在同一時間同時插入相同的Handler,所以在上面的方法中使用了加鎖的方式。

3.第三個點

 

 從上面的源碼中,我們可以看出EventBus使用了反射和容器(CastleWindsor)注入的方式觸發,其實要實現完全解耦,實現靈活可配置,反射是一項必不可少的技術,但是凡事都都是講究一個度,我們知道反射的缺點就是性能消耗比較大,隨着反射技術的發展,反射的速度已經提升了許多,但是相對於直接調用,那還是存在一定的差距。但是只要講究合理度,損耗一部分性能實現良好的系統,這是明智的。在上一篇隨筆中,我們的所有的類型包括EventData和Eventhandler全部是使用的是反射的方式實現的,可想而知,這是消耗性能最大的,而在ABP中采用了加入的容器的方式,這將改善性能問題。其實還是那句話,容器這種接觸耦合的方式還是離不開反射技術在里面。在Castle Windsor的源碼中,它同樣是維護了一個字典,只是將部分類通過反射的方式得到,來優化完全使用反射獲取對象的方式。

4.第四個點

加入了異步的方式觸發事件,通過重新開啟一個線程的方式,提高執行的速度。

 首先來完善第一個問題,其實在事件總線最開始的時候我們已經嘗試定義了一個統一的Handler只不過那個Handler定義的有點過頭了。。。。,這個我們可以參照一下ABP的源碼中ActionEventHandler中的定義

  internal class ActionEventHandler<TEventData> :IEventHandler<TEventData> where TEventData:EventData
    {
        /// <summary>
        /// Action委托具有一個TEventData類型的參數
        /// </summary>
        public Action<TEventData> Action { get; private set; }
        /// <summary>
        /// 因為就是為了統一創建Handler所以處理邏輯是通過構造函數傳入而不是直接在Handle()方法中寫死
        /// </summary>
        /// <param name="handler"></param>
        public ActionEventHandler(Action<TEventData> handler)
        {
            Action = handler;
        }
        public void Handle(TEventData evetData)
        {
            Action(evetData);
        }
    }

 我們在上一篇定義的Mouse類中,將我們的ActionHandler觸發,簡單的測試一下

 

 public void Come()
        {
            new ActionEventHandler<MouseEventData>((data)=>Console.WriteLine(data.Name)).Handle(new MouseEventData() {  Name="小黃"});
            //MouseEventHandler(new MouseEventData() { Name=this.Name});
            //EventBus.Default.Trigger(new MouseEventData() { Name=this.Name});
        }

 

第二個問題:解決並發性的問題此時需要用到鎖,所以只需要在可能產生並發的代碼中加入鎖即可

  //盡量保證鎖中的代碼少
  public static object  lockObj=new object();
  public void Register(Type dataType, Type handlerType)
        {
            lock (lockObj)
            {
                if (mapDic.Keys.Contains(dataType))
                {
                    if (!mapDic[dataType].Contains(handlerType))
                    {
                        mapDic[dataType].Add(handlerType);
                    }
                }
                else
                {
                    mapDic[dataType] = new List<Type>() { handlerType };
                }
            }
        }
 public void Unregister(Type eventType, Type handler)
        {
            lock (lockObj)
            {
                if (mapDic.Keys.Contains(eventType))
                {
                    if (mapDic[eventType].Contains(handler))
                    {
                        mapDic[eventType].Remove(handler);
                    }
                }
            }
        }

 

第四個問題:加入異步的處理方法,其實就是單獨開啟一個線程執行需要同步執行的代碼而已

 public Task TriggerAsync<TEventData>(TEventData eventData) where TEventData : IEventData
        {
            return Task.Run(() => Trigger(eventData));
        }
//調用一下
  static void Main(string[] args)
        {
          
            EventBus.Default.Register(typeof(MouseEventData), typeof(CatchEventHandler));
            Mouse m = new Mouse("老鼠1號");
            EventBus.Default.TriggerAsync(new MouseEventData() { Name = "xiaohuang" });
            m.Come();
            Console.Read();
        }

 第三個問題,涉及到容器,這一部分內容較多,將在接下來的隨筆中學習


免責聲明!

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



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