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

本文转自博客园张占岭(仓储大叔)的博客,原文链接:DDD~领域事件与事件总线,如需转载请自行联系原博主。

目录
相关文章
|
3月前
|
消息中间件 JavaScript 中间件
中间件事件总线事件定义
【6月更文挑战第20天】
30 2
中间件事件总线事件定义
|
4月前
|
JavaScript
在Vue中,如何使用事件总线来传递数据和触发事件?
在Vue中,如何使用事件总线来传递数据和触发事件?
71 0
页面第二次进入或者多次进入,事件总线触发事件多次,eventBus触发多次
页面第二次进入或者多次进入,事件总线触发事件多次,eventBus触发多次
|
10月前
|
JSON 数据格式
EventBridge事件领域
EventBridge事件领域
54 0
|
消息中间件 弹性计算 运维
阿里云事件生态再升级:使用 EventBridge 驱动全量云产品
阿里云 EventBridge 作为云上事件枢纽,早已集成了云上产品的各类事件,用户开通 EventBridge 后使用内置的云服务专用总线就可以监听这些事件,无需创建任何额外资源。
260 0
阿里云事件生态再升级:使用  EventBridge 驱动全量云产品
|
消息中间件 弹性计算 运维
重新定义分析 - EventBridge实时事件分析平台发布
为了解决事件领域中针对流式事件做分析的难题,EventBridge 近日发布了针对事件/消息领域的全新分析工具--EventBridge 实时事件分析平台。下面简要对 EventBridge 实时事件分析平台的内容进行介绍。
216 0
重新定义分析 - EventBridge实时事件分析平台发布
|
新零售 敏捷开发 Cloud Native
“全”事件触发:阿里云函数计算与事件总线产品完成全面深度集成
目前,函数计算已具备接入EventBridge所有事件源的触发能力,实现触达阿里云全系产品服务的“最后一公里”。
293 0
“全”事件触发:阿里云函数计算与事件总线产品完成全面深度集成
|
Kubernetes Cloud Native 网络协议
Knative 事件驱动实践:通过 EventBridge 触发事件
Knative是一款基于Kubernetes的 Serverless 框架。其目标是制定云原生、跨平台的 Serverless 容器编排标准。Knative通过整合容器构建(或者函数)、工作负载管理(动态扩缩)以及事件驱动这三者来实现的这一Serverless标准。那么如何给 Knative 提供生产级别的事件驱动能力?这里我们可以通过事件总线 EventBridge 来实现.事件总线EventB
244 0
Knative 事件驱动实践:通过 EventBridge 触发事件
|
JSON 监控 机器人
EventBridge 事件领域重点特性介绍(二)| 学习笔记
快速学习 EventBridge事件领域重点特性介绍。
172 0
EventBridge 事件领域重点特性介绍(二)| 学习笔记
|
消息中间件 弹性计算 运维
阿里云事件生态再升级:使用 EventBridge 驱动全量云产品
阿里云 EventBridge 作为云上事件枢纽,早已集成了云上产品的各类事件,用户开通 EventBridge 后使用内置的云服务专用总线就可以监听这些事件,无需创建任何额外资源。
阿里云事件生态再升级:使用 EventBridge 驱动全量云产品