1. 程式人生 > >領域驅動設計學習筆記(一 事件匯流排)

領域驅動設計學習筆記(一 事件匯流排)

  • 何為領域驅動設計?

2004年著名建模專家Eric Evans發表了他最具影響力的書籍:《Domain-Driven Design: Tackling Complexity in the Heart of Software》(中文譯名:領域驅動設計:軟體核心複雜性應對之道),書中提出了領域驅動設計(簡稱 DDD)的概念。

  領域驅動設計事實上是針對OOAD的一個擴充套件和延伸,DDD基於面向物件分析與設計技術,對技術架構進行了分層規劃,同時對每個類進行了策略和型別的劃分。

  領域模型是領域驅動的核心。採用DDD的設計思想,業務邏輯不再集中在幾個大型的類上,而是由大量相對小的領域物件(類)組成,這些類具備自己的狀態和行為,每個類是相對完整的獨立體,並與現實領域的業務物件對映。領域模型就是由這樣許多的細粒度的類組成。基於領域驅動的設計,保證了系統的可維護性、擴充套件性和複用性,在處理複雜業務邏輯方面有著先天的優勢。

摘自:http://kb.cnblogs.com/page/112298/

  • 領域模型的種類?
  1. 失血模型:模型僅僅包含資料的定義和getter/setter方法,業務邏輯和應用邏輯都放到服務層中。這種類在Java中叫POJO,在.NET中叫POCO。
  2. 貧血模型:貧血模型中包含了一些業務邏輯,但不包含依賴持久層的業務邏輯。這部分依賴於持久層的業務邏輯將會放到服務層中。可以看出,貧血模型中的領域物件是不依賴於持久層的。
  3. 充血模型:充血模型中包含了所有的業務邏輯,包括依賴於持久層的業務邏輯。所以,使用充血模型的領域層是依賴於持久層,簡單表示就是 UI層->服務層->領域層<->持久層。
  4. 脹血模型:
    脹血模型就是把和業務邏輯不想關的其他應用邏輯(如授權、事務等)都放到領域模型中。我感覺脹血模型反而是另外一種的失血模型,因為服務層消失了,領域層幹了服務層的事,到頭來還是什麼都沒變。
  • 領域事件和事件匯流排

  • 總管物件(事件匯流排)   EventBus

主要職責是管理領域模型的所有事件,通過Dictionary<Type,List<object>> _dicEventHandler=new Dictionary<Type, List<object>>();主要包括

  • Subscribe訂閱相關的領域物件事件
  • Publish 觸發所有在事件總線上的領域物件事件控制代碼
複製程式碼
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace MyDDD
{
    /// <summary>
    /// 事件匯流排
    /// </summary>
    public class EventBus
    {
        /// <summary>
        /// 事件匯流排物件
        /// </summary>
        private static EventBus _eventBus=null;

        /// <summary>
        /// 領域模型事件控制代碼字典,用於儲存領域模型的控制代碼
        /// </summary>
        private static  Dictionary<Type,List<object>> _dicEventHandler=new Dictionary<Type, List<object>>();

        /// <summary>
        /// 附加領域模型處理控制代碼時,鎖住
        /// </summary>
        private readonly object _syncObject = new object();

        /// <summary>
        /// 單例事件匯流排
        /// </summary>
        public static EventBus Instance
        {
            get
            {
                return _eventBus ?? (_eventBus=new EventBus());
            }
        }

        private readonly Func<object, object, bool> _eventHandlerEquals = (o1, o2) =>
        {
            return true;
        };

        #region 訂閱事件

        public void Subscribe<TEvent>(IEventHandler<TEvent> eventHandler) where TEvent : IEvent
        {
            //同步鎖
            lock (_syncObject)
            {
                //獲取領域模型的型別
                var eventType = typeof (TEvent);
                //如果此領域型別在事件匯流排中已註冊過
                if (_dicEventHandler.ContainsKey(eventType))
                {
                    var handlers = _dicEventHandler[eventType];
                    if (handlers != null)
                    {
                        handlers.Add(eventHandler);
                    }
                    else
                    {
                        handlers=new List<object>
                        {
                            eventHandler
                        };
                    }
                }
                else
                {
                    _dicEventHandler.Add(eventType, new List<object> { eventHandler });
                }
            }
        }

        #endregion

        #region 宣佈事件

        public void Publish<TEvent>(TEvent tEvent, Action<TEvent, bool, Exception> callback)  where TEvent:IEvent
        {
            var eventType = typeof (TEvent);
            if (_dicEventHandler.ContainsKey(eventType) && _dicEventHandler[eventType] != null &&
                _dicEventHandler[eventType].Count > 0)
            {
                var handlers = _dicEventHandler[eventType];
                try
                {
                    foreach (var handler in handlers)
                    {
                        var eventHandler = handler as IEventHandler<TEvent>;
                        eventHandler.Handle(tEvent);
                        callback(tEvent, true, null);
                    }
                }
                catch (Exception ex)
                {
                    callback(tEvent, false, ex);
                }
            }
            else
            {
                callback(tEvent, false,null);
            }
        }

        #endregion

    }
}
複製程式碼
  • 領域物件

領域物件通過實現IEvent介面,標記此領域物件可以往事件匯流排中訂閱與自己相關的領域物件事件。

使用者註冊領域物件

複製程式碼
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace MyDDD
{
    /// <summary>
    /// 領域模型物件
    /// </summary>
    public class UserGenerator:IEvent
    {
        /// <summary>
        /// 使用者Id
        /// </summary>
        public Guid UserId { get; set; }
    }
}
複製程式碼
  • 領域物件事件控制代碼

領域物件事件控制代碼是領域物件發生變化時,通知EventBus觸發所有的事件控制代碼

        public void Publish<TEvent>(TEvent tEvent, Action<TEvent, bool, Exception> callback)  where TEvent:IEvent
        使用者註冊傳送Email的事件控制代碼
複製程式碼
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace MyDDD
{
    /// <summary>
    /// 
    /// </summary>
    public class UserAddedEventHandlerSendEmail : IEventHandler<UserGenerator>
    {

        public void Handle(UserGenerator tEvent)
        {
            Console.WriteLine(string.Format("{0}的郵件已傳送", tEvent.UserId));
        }
    }
}
複製程式碼
 

例子說明:當用戶註冊完成後,通知EventBus,由EventBus觸發相應操作,傳送Email或者其他操作。
        這樣的好處使用者註冊是主業務,其他屬於拓展,增加或減少需求,只需要往EventBus上訂閱或取消事件即可。
複製程式碼
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace MyDDD
{
    class Program
    {
        static void Main(string[] args)
        {
            EventBus.Instance.Subscribe(new UserAddedEventHandlerSendEmail());
            var userGenerator = new UserGenerator{UserId = Guid.NewGuid()};
            Console.WriteLine("{0}註冊成功",userGenerator.UserId);
            EventBus.Instance.Publish(userGenerator, CallBack);
            Console.ReadKey();
        }

        public static void CallBack(UserGenerator userGenerator, bool result, Exception ex)
        {
        }
    }
}
複製程式碼

http://www.cnblogs.com/cainiaoguoshi/p/4696965.html