zoukankan      html  css  js  c++  java
  • 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的贡献非常大...

    回到目录

  • 相关阅读:
    107. Binary Tree Level Order Traversal II
    103. Binary Tree Zigzag Level Order Traversal
    102. Binary Tree Level Order Traversal
    690. Employee Importance
    1723. Find Minimum Time to Finish All Jobs
    LeetCode 329 矩阵中最长增长路径
    7.2 物理内存管理
    LeetCode 面试题 特定深度节点链表
    LeetCode 100 相同的树
    npm安装包命令详解,dependencies与devDependencies实际区别
  • 原文地址:https://www.cnblogs.com/lori/p/3476703.html
Copyright © 2011-2022 走看看