DDD~領域事件與(yu)事件總線
談談它
終于(yu)有些眉目(mu)了(le)(le),搜刮了(le)(le)很多牛人的(de)資料(liao),英文的(de),中文的(de),民國文的(de),終于(yu)小有成就了(le)(le),同時(shi)也做了(le)(le)個(ge)DEMO,領(ling)域事件(jian)這東西好(hao),但需要你(ni)明(ming)白(bai)它(ta)(ta)(ta)之后才(cai)會說好(hao),而對(dui)于(yu)明(ming)白(bai)領(ling)域事件(jian)這件(jian)事來說,它(ta)(ta)(ta)的(de)門檻有點高,居然花了(le)(le)我三天(tian)的(de)時(shi)間才(cai)把它(ta)(ta)(ta)搞定,嗨!
占占給它的定義
領域事件(jian):Domain Event,是針(zhen)對(dui)某(mou)個(ge)業務(wu)來說的(de)(de)(de)(de),或者說針(zhen)對(dui)某(mou)個(ge)聚合的(de)(de)(de)(de)業務(wu)來說的(de)(de)(de)(de),例如訂單生成這(zhe)種(zhong)業務(wu),它可(ke)以同時(shi)對(dui)應(ying)一(yi)(yi)種(zhong)事件(jian),比如叫做(zuo)(zuo)OrderGeneratorEvent,而(er)(er)你的(de)(de)(de)(de)零散業務(wu)可(ke)能隨時(shi)會變(bian),加一(yi)(yi)些(xie)業務(wu),減(jian)一(yi)(yi)些(xie)業務(wu),而(er)(er)對(dui)于訂單生成這(zhe)個(ge)事件(jian)來說,它是唯一(yi)(yi)不變(bian)的(de)(de)(de)(de),而(er)(er)我們(men)需要(yao)把這(zhe)些(xie)由(you)產生訂單而(er)(er)發生變(bian)化的(de)(de)(de)(de)事情拿出(chu)來,而(er)(er)拿出(chu)來的(de)(de)(de)(de)這(zhe)些(xie)業務(wu)就叫做(zuo)(zuo)"領域事件(jian)".其中的(de)(de)(de)(de)領域指的(de)(de)(de)(de)就是訂單生成這(zhe)個(ge)聚合;而(er)(er)事件(jian)指的(de)(de)(de)(de)就是那些(xie)零散業務(wu)的(de)(de)(de)(de)統稱.
它的主要幾個抽象
在面(mian)向對象的編程世(shi)界(jie)里,做這種事情我們需(xu)要幾個抽象:
領(ling)域(yu)對(dui)象事件標示:(標示接口,接口的(de)一種,用來(lai)約束一批對(dui)象)IEvent
領域對象的處(chu)理方(fang)法,行為:(需要讓那(nei)些零散的模塊重寫的方(fang)法,起個(ge)聽起來(lai)熟悉的名字(zi),叫它handle吧)IEventHandler=>Handle
事件(jian)總線(xian):事件(jian)處理核(he)心類,承載了事件(jian)的(de)發(fa)布,訂(ding)閱與取(qu)消訂(ding)閱的(de)邏輯,EventBus
某個(ge)領域對象:為了實現某個(ge)業務(wu),而創建的實體(ti)類,它(ta)里面有(you)事件所需(xu)要的數(shu)據,它(ta)繼承了IEvent
某個領(ling)域對象的(de)事件:它(ta)是一個事件處(chu)理類,它(ta)實現了IEventHandler,它(ta)所處(chu)理的(de)事情(qing)需要在Handle里去完成
我的Demo的實現
一 結果圖:
二 核心類:
IEvent接(jie)(jie)口,標示接(jie)(jie)口往(wang)往(wang)都是空的,呵呵
/// <summary> /// 事件實體基類 /// </summary> public interface IEvent { }
IEventHandler接口,只有一個行為方法Handle
/// <summary> /// 事件處理(li)接口 /// </summary> /// <typeparam name="TEvent">繼承IEvent對象的事件(jian)源對象</typeparam> public interface IEventHandler<TEvent> where TEvent : IEvent { /// <summary> /// 處理程序 /// </summary> /// <param name="evt"></param> void Handle(TEvent evt); }
EventBus是(shi)實現(xian)(xian)事件的核心,在這版里(li),它(ta)支持異(yi)步事件機制,使用Task實現(xian)(xian),所以它(ta)需要(yao)運行在.net4.5平臺之上
/// <summary> /// 事件總(zong)線 /// 發布與訂閱處(chu)理邏輯 /// 核(he)心(xin)功能代碼 /// </summary> public class EventBus { private EventBus() { } private static EventBus _eventBus = null; private readonly object sync = new object(); /// <summary> /// 對于(yu)事件數據的存儲,目前采用內(nei)存字典 /// </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> /// 初始化空的事件(jian)總件(jian) /// </summary> public static EventBus Instance { get { return _eventBus ?? (_eventBus = new EventBus()); } } /// <summary> /// 通過XML文件初始化事件總線,訂閱(yue)信自在XML里(li)配(pei)置 /// </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> /// 訂閱(yue)事件列(lie)表 /// </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> /// 訂閱事(shi)件實體(ti) /// </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> /// 取(qu)消訂閱事件(jian) /// </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 }
一個具(ju)體的領域對象(xiang),它繼承IEvent
/// <summary> /// 添加訂單(dan)的事(shi)件 /// </summary> public class OrderGeneratorEvent : IEvent { public int OrderID { get; set; } }
一個為OrderGeneratorEvent工作的領域(yu)事件,它用來為客(ke)戶發郵件
/// <summary> /// 發(fa)郵(you)件功(gong)能(neng) /// </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(); }
下面是運行結果:
嗨,終于(yu)理解(jie)這(zhe)東西了,呵呵,在此感謝一下晴陽兄(xiong),它(ta)對DDD的(de)貢(gong)獻非(fei)常(chang)大...