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的貢獻非常大...
浙公網安備 33010602011771號