天天看點

DDD~領域事件與事件總線

回到目錄

談談它

終于有些眉目了,搜刮了很多牛人的資料,英文的,中文的,民國文的,終于小有成就了,同時也做了個DEMO,領域事件這東西好,但需要你明白它之後才會說好,而對于明白領域事件這件事來說,它的門檻有點高,居然花了我三天的時間才把它搞定,嗨!

占占給它的定義

領域事件:Domain Event,是針對某個業務來說的,或者說針對某個聚合的業務來說的,例如訂單生成這種業務,它可以同時對應一種事件,比如叫做OrderGeneratorEvent,而你的零散業務可能随時會變,加一些業務,減一些業務,而對于訂單生成這個事件來說,它是唯一不變的,而我們需要把這些由産生訂單而發生變化的事情拿出來,而拿出來的這些業務就叫做"領域事件".其中的領域指的就是訂單生成這個聚合;而事件指的就是那些零散業務的統稱.

它的主要幾個抽象

在面向對象的程式設計世界裡,做這種事情我們需要幾個抽象:

領域對象事件标示:(标示接口,接口的一種,用來限制一批對象)IEvent

領域對象的處理方法,行為:(需要讓那些零散的子產品重寫的方法,起個聽起來熟悉的名字,叫它handle吧)IEventHandler=>Handle

事件總線:事件處理核心類,承載了事件的釋出,訂閱與取消訂閱的邏輯,EventBus

某個領域對象:為了實作某個業務,而建立的實體類,它裡面有事件所需要的資料,它繼承了IEvent

某個領域對象的事件:它是一個事件處理類,它實作了IEventHandler,它所處理的事情需要在Handle裡去完成

我的Demo的實作

一 結果圖:

二 核心類:

IEvent接口,标示接口往往都是空的,呵呵

/// <summary>
    /// 事件實體基類
    /// </summary>
    public interface IEvent
    {
    }      

IEventHandler接口,隻有一個行為方法Handle

/// <summary>
    /// 事件處理接口
    /// </summary>
    /// <typeparam name="TEvent">繼承IEvent對象的事件源對象</typeparam>
    public interface IEventHandler<TEvent>
        where TEvent : IEvent
    {
        /// <summary>
        /// 處理程式
        /// </summary>
        /// <param name="evt"></param>
        void Handle(TEvent evt);

    }      

EventBus是實作事件的核心,在這版裡,它支援異步事件機制,使用Task實作,是以它需要運作在.net4.5平台之上

  /// <summary>
    /// 事件總線
    /// 釋出與訂閱處理邏輯
    /// 核心功能代碼
    /// </summary>
    public class EventBus
    {
        private EventBus() { }

        private static EventBus _eventBus = null;
        private readonly object sync = new object();
        /// <summary>
        /// 對于事件資料的存儲,目前采用記憶體字典
        /// </summary>
        private static Dictionary<Type, List<object>> eventHandlers = new Dictionary<Type, List<object>>();
        /// <summary>
        // checks if the two event handlers are equal. if the event handler is an action-delegated, just simply
        // compare the two with the object.Equals override (since it was overriden by comparing the two delegates. Otherwise,
        // the type of the event handler will be used because we don't need to register the same type of the event handler
        // more than once for each specific event.
        /// </summary>
        private readonly Func<object, object, bool> eventHandlerEquals = (o1, o2) =>
         {
             var o1Type = o1.GetType();
             var o2Type = o2.GetType();
             if (o1Type.IsGenericType &&
                 o1Type.GetGenericTypeDefinition() == typeof(ActionDelegatedEventHandler<>) &&
                 o2Type.IsGenericType &&
                 o2Type.GetGenericTypeDefinition() == typeof(ActionDelegatedEventHandler<>))
                 return o1.Equals(o2);
             return o1Type == o2Type;
         };
        /// <summary>
        /// 初始化空的事件總件
        /// </summary>
        public static EventBus Instance
        {
            get
            {
                return _eventBus ?? (_eventBus = new EventBus());
            }
        }
        /// <summary>
        /// 通過XML檔案初始化事件總線,訂閱信自在XML裡配置
        /// </summary>
        /// <returns></returns>
        public static EventBus InstanceForXml()
        {
            if (_eventBus == null)
            {
                XElement root = XElement.Load(System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "EventBus.xml"));
                foreach (var evt in root.Elements("Event"))
                {
                    List<object> handlers = new List<object>();

                    Type publishEventType = Type.GetType(evt.Element("PublishEvent").Value);
                    foreach (var subscritedEvt in evt.Elements("SubscribedEvents"))
                        foreach (var concreteEvt in subscritedEvt.Elements("SubscribedEvent"))
                            handlers.Add(Type.GetType(concreteEvt.Value));

                    eventHandlers[publishEventType] = handlers;
                }

                _eventBus = new EventBus();
            }
            return _eventBus;
        }

        #region 事件訂閱&取消訂閱,可以擴充
        /// <summary>
        /// 訂閱事件清單
        /// </summary>
        /// <param name="type"></param>
        /// <param name="subTypeList"></param>
        public void Subscribe<TEvent>(IEventHandler<TEvent> eventHandler)
            where TEvent : class, IEvent
        {
            lock (sync)
            {
                var eventType = typeof(TEvent);
                if (eventHandlers.ContainsKey(eventType))
                {
                    var handlers = eventHandlers[eventType];
                    if (handlers != null)
                    {
                        if (!handlers.Exists(deh => eventHandlerEquals(deh, eventHandler)))
                            handlers.Add(eventHandler);
                    }
                    else
                    {
                        handlers = new List<object>();
                        handlers.Add(eventHandler);
                    }
                }
                else
                    eventHandlers.Add(eventType, new List<object> { eventHandler });
            }
        }
        /// <summary>
        /// 訂閱事件實體
        /// </summary>
        /// <param name="type"></param>
        /// <param name="subTypeList"></param>
        public void Subscribe<TEvent>(Action<TEvent> eventHandlerFunc)
            where TEvent : class, IEvent
        {
            Subscribe<TEvent>(new ActionDelegatedEventHandler<TEvent>(eventHandlerFunc));
        }
        public void Subscribe<TEvent>(IEnumerable<IEventHandler<TEvent>> eventHandlers)
            where TEvent : class, IEvent
        {
            foreach (var eventHandler in eventHandlers)
                Subscribe<TEvent>(eventHandler);
        }
        /// <summary>
        /// 取消訂閱事件
        /// </summary>
        /// <param name="type"></param>
        /// <param name="subType"></param>
        public void Unsubscribe<TEvent>(IEventHandler<TEvent> eventHandler)
            where TEvent : class, IEvent
        {
            lock (sync)
            {
                var eventType = typeof(TEvent);
                if (eventHandlers.ContainsKey(eventType))
                {
                    var handlers = eventHandlers[eventType];
                    if (handlers != null
                        && handlers.Exists(deh => eventHandlerEquals(deh, eventHandler)))
                    {
                        var handlerToRemove = handlers.First(deh => eventHandlerEquals(deh, eventHandler));
                        handlers.Remove(handlerToRemove);
                    }
                }
            }
        }
        public void Unsubscribe<TEvent>(IEnumerable<IEventHandler<TEvent>> eventHandlers)
          where TEvent : class, IEvent
        {
            foreach (var eventHandler in eventHandlers)
                Unsubscribe<TEvent>(eventHandler);
        }
        public void Unsubscribe<TEvent>(Action<TEvent> eventHandlerFunc)
            where TEvent : class, IEvent
        {
            Unsubscribe<TEvent>(new ActionDelegatedEventHandler<TEvent>(eventHandlerFunc));
        }
        #endregion

        #region 事件釋出
        /// <summary>
        /// 釋出事件,支援異步事件
        /// </summary>
        /// <typeparam name="TEvent"></typeparam>
        /// <param name="evnt"></param>
        public void Publish<TEvent>(TEvent evnt)
           where TEvent : class, IEvent
        {
            if (evnt == null)
                throw new ArgumentNullException("evnt");
            var eventType = evnt.GetType();
            if (eventHandlers.ContainsKey(eventType)
                && eventHandlers[eventType] != null
                && eventHandlers[eventType].Count > 0)
            {
                var handlers = eventHandlers[eventType];
                foreach (var handler in handlers)
                {
                    var eventHandler = handler as IEventHandler<TEvent>;
                    if (eventHandler.GetType().IsDefined(typeof(HandlesAsynchronouslyAttribute), false))
                    {
                        Task.Factory.StartNew((o) => eventHandler.Handle((TEvent)o), evnt);
                    }
                    else
                    {
                        eventHandler.Handle(evnt);
                    }
                }
            }
        }

        public void Publish<TEvent>(TEvent evnt, Action<TEvent, bool, Exception> callback, TimeSpan? timeout = null)
           where TEvent : class, IEvent
        {
            if (evnt == null)
                throw new ArgumentNullException("evnt");
            var eventType = evnt.GetType();
            if (eventHandlers.ContainsKey(eventType) &&
                eventHandlers[eventType] != null &&
                eventHandlers[eventType].Count > 0)
            {
                var handlers = eventHandlers[eventType];
                List<Task> tasks = new List<Task>();
                try
                {
                    foreach (var handler in handlers)
                    {
                        var eventHandler = handler as IEventHandler<TEvent>;
                        if (eventHandler.GetType().IsDefined(typeof(HandlesAsynchronouslyAttribute), false))
                        {
                            tasks.Add(Task.Factory.StartNew((o) => eventHandler.Handle((TEvent)o), evnt));
                        }
                        else
                        {
                            eventHandler.Handle(evnt);
                        }
                    }
                    if (tasks.Count > 0)
                    {
                        if (timeout == null)
                            Task.WaitAll(tasks.ToArray());
                        else
                            Task.WaitAll(tasks.ToArray(), timeout.Value);
                    }
                    callback(evnt, true, null);
                }
                catch (Exception ex)
                {
                    callback(evnt, false, ex);
                }
            }
            else
                callback(evnt, false, null);
        }

        #endregion

    }      

一個具體的領域對象,它繼承IEvent

/// <summary>
    /// 添加訂單的事件
    /// </summary>
    public class OrderGeneratorEvent : IEvent
    {
        public int OrderID { get; set; }
    }      

一個為OrderGeneratorEvent工作的領域事件,它用來為客戶發郵件

   /// <summary>
    /// 發郵件功能
    /// </summary>
    public class OrderAddedEventHandler_SendEmail : IEventHandler<OrderGeneratorEvent>
    {
        public void Handle(OrderGeneratorEvent evt)
        {
            Console.WriteLine("Order_Number:{0},Send a Email.", evt.OrderID);
        }
    }      

下面看一個主程式:

static void Main(string[] args)
    {
          EventBus.Instance.Subscribe(new OrderAddedEventHandler_SendEmail());
            var entity = new OrderGeneratorEvent { OrderID = 1 };
            Console.WriteLine("生成一個訂單,單号為{0}", entity.OrderID);
            EventBus.Instance.Publish(entity);
            Console.ReadKey();
    }      

下面是運作結果:

嗨,終于了解這東西了,呵呵,在此感謝一下晴陽兄,它對DDD的貢獻非常大...

作者:倉儲大叔,張占嶺,

榮譽:微軟MVP

QQ:853066980

支付寶掃一掃,為大叔打賞!

DDD~領域事件與事件總線