一、前言 結合我們本次系列的第一篇博文中提到的上下文映射圖(傳送門:如何一步一步用DDD設計一個電商網站(一)—— 先理解核心概念),得知我們這個電商網站的核心域就是銷售子域。因為電子商務是以信息網路技術為手段,以商品交換為中心的商務活動,一個好的核心域設計可以大大提升企業的競爭力和對市場變化的相應 ...
一、前言
結合我們本次系列的第一篇博文中提到的上下文映射圖(傳送門:如何一步一步用DDD設計一個電商網站(一)—— 先理解核心概念),得知我們這個電商網站的核心域就是銷售子域。因為電子商務是以信息網路技術為手段,以商品交換為中心的商務活動,一個好的核心域設計可以大大提升企業的競爭力和對市場變化的相應速度。
那麼我們開始設計領域對象。對於設計領域對象的基本概念不瞭解的可以先閱讀我的該系列第二篇文章(傳送門:如何一步一步用DDD設計一個電商網站(二)—— 項目架構)。
二、定義幾個基類
我相信我們大部分人會以如下的方式去存放我們定義的基類,見圖1。
【圖1】
這是一種比較常規的技術分層思維方式產生的結果,在某些項目文件中或多或少有那麼幾個"Base"、"Core"、"Common"等的文件夾存放著一些通用的類,它們起著對當前項目中類的抽象、實現通用性支撐性功能的作用。然而在DDD中這些都應屬於基礎設施層的事情,這樣能夠保證其他層專註於自身的職責,不會把本應內聚的東西泄露到這些類中。如我們當前的領域層就專註於領域建模,裡面的概念全部與通用語言相關。說乾就乾,搬到基礎設施層去,再取個能表達出一致概念的名字的模塊存放,如圖2。
【圖2】
三、核心域(銷售子域)中有什麼
“銷售”用通俗的話講就是“把商品賣給用戶”,這幾個字中就已經凸顯出幾個概念:“商品”,“用戶”,“賣”。以下就是”商品“和”用戶“的代碼實現:
【圖3】
【圖4】
我相信有許多人會以圖3和圖4的方式定義我們的商品和用戶,乍一看的確符合對商品、用戶概念的獨立的理解。但在DDD中有不同的限界上下文,每個限界上下文專註處理自身的業務,多個限界上下文之間是以協作的方式工作。保證多個限界上下文之間的良好協作關係的方式是提高自治性。提高自治性的方式又有很多,技術方面如領域事件、消息隊列、事件源等,這裡暫時不展開描述。從代碼層面來看,建模的時候只獲取對當前上下文業務處理剛剛好大小的數據,也可以提高當前項目的自治性。
根據我們劃分的上下文映射圖,用戶和商品是屬於另外的上下文的,那麼在這裡我們都應該建模為值對象,因為我們是無法直接修改這些對象的內部屬性的。另外,在上面2個圖中,獲取其他上下文中的資源時,我們作為客戶方基本上是不會原封不動的消費服務方提供的數據的。比如這裡面的Product.PermitNo(批文號),在大部分行業里,它與銷售商品沒什麼關係。再如User.BlockedBalance(凍結餘額),在銷售的過程中,只需要知道用戶有多少可用餘額就好了。這個思路總結一下就是,從業務角度我們不求大而全,只求剛好滿足當前業務即可,但是當業務發生變化的時候我們的領域模型也要及時反映出調整後的通用語言概念。得到修改後的模型:
【圖5】
【圖6】
對了,不管是值對象還是實體和聚合,習慣在構造函數中的做好守衛驗證,有利於表達出什麼樣的領域對象是合法的。
四、更好的存活於分散式背景下
在某些背景下一個限界上下文是作為獨立的服務對外提供API進行訪問的,特別在電商行業,分散式系統的構建是個普遍情況,方式也多元化,各種RPC框架、Restful等技術選型,SOA、微服務等實現理念層出不窮。如何最大化的降低技術變更和業務變化導致的上下文劃分調整的影響,也是我們要考慮的重要問題。
對於我們.Net開發人員來說,在分散式場景下用的最多的方式無非是WebAPI和WCF了。這種方式也就是在第一篇文章中所提到的發佈語言和開放主機服務,那麼對於客戶端來說需要做好防腐層(第一篇文章中有提到)的工作,好避免外部上下文的概念侵入到自身的領域概念中。一個普遍的防腐層實現時序圖,其中真正負責防腐層工作的是XXXAdapter和XXXTranslator,如下(摘自[Vaughn Vernon]《實現領域驅動設計》):
【圖7】
我們這裡實現的相關類如下圖所示定義:
【圖8】
其中1存放著訪問遠程資源的介面定義,2是其實現方式。這樣設計的好處是,對於領域層的建模隱藏了數據獲取的實現細節。並且當我們實際開發的時候可能由於需要配合服務方還未準備好,但是這絲毫不影響我們的開發工作,我們可以定義個Mock類來實現這裡的IRemoteServices中的介面,就可以順利地進行開發工作。
其中ProductAdapter、UserAdapter分別負責請求商品上下文和用戶上下文並取得原始結果,ProductTranslator、UserTranslator則是通過解析原始結果,轉換為我方上下文中需要的領域模型概念。以下則是核心部分的實現:
【圖9】
【圖10】
五、結語 本來打算想把整個“把商品賣給用戶”過程講完,但是發現這樣篇幅太長,所以這次就先到這裡,先把其中的2個主體整個設計過程給弄明白了,接下去再講“賣”這個行為該如何設計。謝謝各位看官:) 本文的源碼地址:https://github.com/ZacharyFan/DDDDemo,註意其中的Restful請求地址和Json解析類為假實現,僅為了用於支持本文的表述。
作者:Zachary_Fan
出處:http://www.cnblogs.com/Zachary-Fan/p/6036729.html