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的贡献非常大...