應用程序框架實戰十三:DDD分層架構之我見

  前面介紹了應用程序框架的一個重要組成部分——公共操做類,並提供了一個數據類型轉換公共操做類做爲示例進行演示。下面準備介紹應用程序框架的另外一個重要組成部分,即體系架構支持。你不必定要使用DDD這樣的架構,使用單層架構和普通三層架構同樣能夠,不過你若是但願得到更進一步的複用性和封裝度,使用更加面嚮對象的技術是必經之程。程序員

  我在2010年之前還在使用古老的ASP.NET WebForm和原始的Ado.Net。以前我有個觀念:.NET技術發展太快,跟着微軟屁股後面跑太累,因此只使用它一些原始的東西,本身封裝一下也能知足工做上的需求。對於像Linq這樣的技術只是隨便看了下,特別是當時不少人告訴我Linq已死,千萬別學,我當時很喜歡這樣的言論,由於不學習新知識就有了充分的理由。編程

  到了2010年,我有一次上博客園,瀏覽了一些文章,發現充滿各類縮寫和名詞,什麼Dto、工做單元一類,我才知道新一代的.Net技術已經開始普及,我已經Out了。以後我開始學習EF和MVC,在剛開始接觸EF的時候,我從一些博客瞭解到,爲了發揮EF的威力,必須使用DDD進行設計。爲了掃清攔路虎,我購買了幾本DDD的書來學習,學習過程當中才發現面向對象和敏捷開發纔是關鍵,因而開始大量購書,一發不可收拾,四年時間買了接近兩百本後,終於把基礎補起來一點。設計模式

  DDD的核心思想是描述如何使用面向對象的方法對業務領域建模,怎樣得到更好的領域模型。雖然看了很多DDD的資料,但仍是感受它異常抽象,另外面向對象的思想也很難進步,可能和前些年的編程習慣有關,已經習慣於從數據的角度考慮問題,造成了思惟定勢。架構

  DDD雖然抽象,但它仍是提供了一些技術上的支持。大部分人都是從DDD分層架構入手來進行學習和實踐,固然,DDD並非分層架構,分層架構只是DDD的一個技術構造。下面簡單介紹一下我對DDD分層架構的理解,因爲我使用DDD的時間不長,我所描述的觀點都是我本身的一些開發經驗,不必定正確,歡迎各位高手批評指正,共同進步。框架

  DDD分層架構整體上和三層架構類似,不過對各層提出了更具體的職責和構造塊。我也常常與一些在使用DDD分層架構的朋友交流,我問他們DDD分層架構與普通三層架構有何區別,大部分人都感受差很少,除了一些名詞術語有所變化。若是你也是這個感受,那麼可能本文對你是有幫助的,由於我明顯感受出它們之間有所不一樣。分佈式

  DDD分層架構與傳統三層架構示意圖以下。單元測試

 

(領域驅動設計分層架構示意圖)學習

 

(傳統三層架構示意圖)測試

  DDD分層架構與傳統三層架構最重要的區別多是重心不一樣,即傳統三層架構的重心在業務邏輯層,而DDD分層架構的重心在領域層。spa

  面向對象設計的核心是基於業務概念建模,並映射到代碼中,這樣的好處是減輕程序員將業務概念轉換到技術的負擔,由於更容易理解。傳統三層架構雖然也把業務概念轉換到實體層的Model對象,但實體層只是一個輔助設施,這些Model只是用來裝數據的容器,做用並不顯著。DDD分層架構把領域層提到核心地位,這些Model成爲業務邏輯的一個主要放置場所。

  使用DDD分層架構的第一個好處就是業務邏輯高度內聚到領域層,換句話說,若是有邏輯問題,找領域層就對了。對於這一點,有些人認爲傳統三層架構也能夠,找業務邏輯層不是同樣嗎?這多是大多數對領域驅動設計分層架構認識沒法突破的關鍵。

  雖然你能夠按照分層架構的要求,把所有業務邏輯都寫到BLL層,但你沒法精肯定位你須要的業務邏輯究竟處於什麼位置,換句話說,你須要業務邏輯的一個惟一訪問點。因爲你沒法輕易找到業務邏輯的訪問點,因此產生冗餘代碼就再所不免,一段相同或類似的冗餘代碼會在多個地方產生,從而致使可維護性的下降。經過強制約束代碼和目錄規範以及提取公共方法能夠緩解部分問題,但要從根本上解決,你還得向面向對象求救。

  那麼,哪裏是業務邏輯最好的落腳點,最直觀,最容易被你們想到的惟一訪問點在哪呢?好比你要處理一個訂單,讓你到其它地方去找處理訂單的代碼,你天然找起來困難。那麼若是這段代碼處於訂單實體的內部,狀況就大不相同了,你能夠在最短的時間內找到它。在領域實體中內聚業務邏輯,能夠爲你建立一個業務邏輯的惟一訪問點。你們之後須要某個邏輯的時候,先看看實體中有沒有本身須要的,這樣就能顯著下降代碼冗餘,從而更好維護。

  因此,個人第一條DDD使用經驗就是,使用充血模型,將業務邏輯儘可能放到領域實體中。充血模型有不少爭論,不過你大可沒必要理會別人的說法,本身實踐才能出真知。用得不爽,你後面不用就是了,對你基本沒啥影響。目前我使用充血模型,感受它主要的問題是,若是採用分佈式架構,好比中間採用WCF遠程調用,須要經過一層專門的DTO來進行傳輸,並且須要增長一個遠程外觀的服務,會致使工做量上升。

  當把充血模型用起來之後,下一步是要把聚合用起來。聚合這個概念很好理解,就是包含關係。在UML中有兩種包含關係,第一種叫聚合,表示比較弱的包含關係,聚合內部的東西在外面能夠直接訪問。第二種叫組合,即組成聚合,是很強的包含關係,表示外部的對象由內部的多個子對象組成,內部的子對象在外面不能直接訪問,必須經過外部的對象間接引用。DDD雖然用了聚合這個詞,但它表示UML中的組成聚合,因此它把外部的對象稱爲根,即聚合根,要訪問內部對象,必須先訪問聚合根。

  概念上的理解,除了能吹吹牛之外,沒多大幫助。我在剛接觸DDD的時候,也能理解聚合的概念,提及來同樣口沫橫飛,但真正用起來過了差很少一年。除了我反應比較遲鈍之外,還有一個緣由是被以前以數據爲中心的思惟定勢所束縛。

  我也常常下載一些DDD的Demo來學習,可是這些例子大多都很是簡單,因此我主要仍是依靠看書和本身摸索。我剛開始的用法是一個表對應一個領域實體,每一個領域實體對應一個倉儲。我在使用的過程當中,隱隱發現哪裏不對,可是沒法找出具體的緣由。通過大半年,我也使用DDD開發了幾個簡單的項目,逐步積累了一些經驗,在一次看書的時候,我忽然領悟到個人DDD用法主要毛病是依賴關係混亂,而解決這些依賴關係的手段就是聚合。

  聚合的主要影響是顯著減小倉儲數量,以及集中管理高度依賴的相關實體。把高度相關的實體內聚到一個聚合中,能夠把這些依賴關係封裝到一個更小的空間,外部只與聚合根打交道,與聚合內部子對象的依賴關係就會明顯下降。一個聚合對應一個倉儲,而不是一個實體對象一個倉儲,能夠減小倉儲數量,從而進一步下降依賴關係。

  後面我從新閱讀了一些博客和書籍,發現別人其實都說清楚了,只是本身當時看過去沒有理解而已,這真是紙上得來終覺淺 絕知此事要躬行。

  個人第二條DDD使用經驗是,把高度相關的實體封裝到聚合中,爲每一個聚合根建立一個倉儲。

  觀察上面的DDD分層架構示意圖,會發現領域層只依賴於應用程序框架服務,倉儲採用了接口分離模式將實現和接口分離到不一樣的程序集,領域層中只包含倉儲的接口,這個設計讓領域層很是純淨,和外部的依賴關係降到最低。這對咱們意味着什麼?更低的依賴讓咱們能夠方便的對業務邏輯進行單元測試,特別是採用了TDD方式的話,這一點將顯得尤爲重要。咱們能夠在單元測試中使用模擬框架對倉儲以及外部依賴進行模擬測試,從而大幅度提高業務邏輯的穩定性和健壯性。

  另外,觀察傳統三層架構,業務邏輯層通常直接依賴數據訪問層,讓單元測試變得困難,從而轉向更粗粒度的集成測試。

  經過上面的分析,能夠看到採用DDD分層架構能夠得到比傳統三層架構更好的可複用性、可維護性、可測試性等。

  固然不可能把全部業務邏輯所有放入領域實體中,有些功能須要操做多個實體,或者須要使用某些設計模式,這時候須要使用領域服務。這裏的要點是儘可能把領域服務的操做委託給領域實體,由於這樣業務邏輯能夠更加集中。

  DDD分層架構還有一些構造塊,我會在後面的文章詳細介紹。若是沒有介紹到的,說明我還處於學習和摸索階段,尚未多少心得,等我有些經驗之後再告訴你們。

  如今來總結一下。

  使用DDD分層架構有哪些好處

  • 幫你更集中的管理業務邏輯。
  • 幫你下降各層間,以及各業務模塊間的依賴關係。
  • 幫你更方便的進行單元測試。

  個人DDD分層架構使用經驗

  • 使用充血模型,將業務邏輯儘可能放到領域實體中,領域實體爲業務邏輯提供一個惟一訪問點。
  • 不能放入領域實體的邏輯,儘可能放到領域服務,總之,業務邏輯應該高度內聚到領域層。
  • 把高度相關的實體封裝到聚合中,爲每一個聚合根建立一個倉儲。

  最後,提醒一下,咱們使用一些DDD分層架構構造塊,可能並不算真正用上了DDD。可是,咱們的目標是使用DDD嗎?不是,咱們的目標是把業務邏輯作得更穩定,更好維護。因此不用在乎本身使用的技術正不正宗,標不標準,只要比之前更好,就應該堅持下去。

  .Net應用程序框架交流QQ羣: 386092459,歡迎有興趣的朋友加入討論。

  謝謝你們的持續關注,個人博客地址:http://www.cnblogs.com/xiadao521/

相關文章
相關標籤/搜索