领域驱动设计 pdf_什么是领域驱动设计?
什么是領域驅動設計?
你可能使用領域驅動設計(DDD)開發了一些項目。你可能很滿意, 使用領域模型來開發領域業務。并且得意地展示給你的同事看,他們會說“666”。
但有的時候你使用領域模型你總覺得哪兒有點不對勁。你會嘀咕你可能遺漏了什么。 emmmm...但真的是這樣嗎?你發覺自己在問類似下面的這些問題:
- 什么是領域模型?
- 領域模型是怎么更新到數據庫的呢?
- 領域模型是否要引入一種架構模式?例如CQRS
當我剛開始使用領域模式的時候,我也同樣被上面這些問題所困擾。 甚至當我寫文檔前幾天,我也并沒有扎實地掌握某些細節。 我經歷了一些“啊哈”的開竅時刻,我想把這些分享給你。 這篇文章會深入講解幫你明白上面問題的答案。
在看答案之前,我們需要先往后退一步。 這篇文章的目的不是給你一個要點清單,而是想幫你真正地領會領域模型。 其實我們并沒有太多需要學習的,事實上,我們會花很多時間試圖忘記某些已經習得的概念(unlearning)。
“忘記你已經學到的。” — Yoda這篇文章真的很長。它更像一本mini書,這也是我更喜歡的形式。
摘要
如果你不想閱讀整篇文章,可以快速瀏覽這份摘要。如果你打算閱讀整篇文章,你完全可以跳過這部分。
Question:什么是領域模型?
為解決場景下的問題而形成的一套模型,然后使用這套模型來解決業務問題。 根據重復勞動經驗我們會形成一套模式。領域模型也一樣會形成一套模式,他包括:實體、值對象、模塊、領域服務。
Question:領域模型是怎么更新到數據庫的呢?
使用資源庫(repository)將領域模型更新到數據庫。 在一個一對多的實體,例如:用戶組(Group)和用戶(User),用戶組內有N個用戶, 如果用戶非常多,一次加載Group肯定會造成性能損失,這種問題怎么設計呢? 如果不使用領域模型依靠經驗你會想到拆分,現在你使用了領域模型想的方案也應該是拆分。 我看到有些人把repository注入到領域模型內,這種做法是錯誤的。
Question:領域模型是否要引入一種架構模式?例如CQRS
首先我想說的是領域模型不需要引入架構模式。 領域模式是解決領域內的業務問題的,他不是解決架構問題,所以領域模型本身不需要引入架構。 當你使用領域模型的時候,領域層之上你可以使用架構,比如CQRS、MVC等等。
要不,我們開始正文。我想從傳統的項目開始講解一步步的過渡到領域模型。 我將講解三種組織代碼的結構,分別是:傳統模式、IDDD模式、我思考的模式。
說一下我們用到的技術框架:
- ORM:Spring Data JPA
- Database:h2-database
我們先假設一個需求用例,現在我們要開發一個身份認證模塊(identity)其中包括的功能有 獲得用戶信息、修改密碼、用戶認證。
使用傳統項目來開發整個需求
首先來看下我們的項目結構:
這個項目結構大家已經非常熟悉了,就是我們傳統的分層方式。 我們通常會把業務邏輯寫在service里面,如下:
整個功能我們已經開發完了,是不是看著非常簡單。 我們來看changePassword方法,我們通過repository根據用戶名獲得到用戶, 然后調用authenticate方法進行認證,認證通過后修改密碼(user.setPassword())。 是不是看上去沒有任何毛病,而且程序還運行的非常成功。嗯,確實是。 但是在這種編程模式里我們更多的是從數據庫的模式來開發的,因為User只是封裝了靜態數據。 然后在service中來完成修改密碼這個邏輯,這種操作更像是過程化編程。
我們應該從面向對象的角度來思考問題。 一提到對象你首先想到的是什么?繼承?封裝?多態?還有嗎? 我再添一條類是一組相關的屬性和行為的集合。
既然我提到了屬性和行為,那我們重新思考下修改密碼這個用例: 首先password是User類上的一個屬性,對于修改密碼我們應該是調用User對象上的changePassword方法, 然后由changePassword來完成修改password屬性,這就是封裝。
接下來我們使用領域模型再來完成上面用例的業務。
使用IDDD來開發整個需求
首先我們也是來看一下IDDD的項目結構:
當你看到這個項目結構的時候,你可能心生疑惑:“怎么沒有service, repository這樣的包呢?”
我來告訴你,IDDD推薦我們使用應用層、領域層和基礎設施層來做分層。 對于這種分包方式是《實現領域驅動設計》這本書比較推薦的。所以這個項目我們以這種方式來組織我們的代碼。
接下來我們來看看應用層服務和領域模型:
再來看UserService上的changePassword方法,我們還是通過authenticate獲得用戶, 然后又調用了用戶的changePassword來修改密碼。
但是你會發現我們并沒有把密碼加密這個交由User來完成,這是為什么呢?
因為加密不是User的職責。就像authenticate一樣,你自己不可能認證自己, 就像你不借助鏡子永遠不會看清你的臉蛋。就像你會問別人我今天漂不漂亮,而不會自欺欺人的告訴自己我很漂亮。
通過將changePassword交由User,你會發現你的業務很清晰了。 因為你對號入座將原本由用戶該做的事情又還給了用戶。
接下來我想說一個我認為的分層架構,以及如何組織代碼。這部分知識涉及到了UML、面向對象。
我直接上圖,然后在細細討論:
當你看到這個結構,你會發現怎么沒有層了呢?怎么都放在了一個包里。 聊到這我就應該給你說一說UML中的模塊和構造型。 我們都已經很熟悉模塊了,因為我們平常都是在用包來組織模塊。 這個我就不多講了,我想說的什么是構造型。構造型就是用來區分不同種類的類。 玩了那么多年的Spring,還記得那幾個常用的組件注解(@Component、@Controller、@Service、@Repository)嗎? 他們被放置在org.springframework.stereotype這個包下,就是為了區分你的不同種類的類。
所以我們現在為我們的模塊(identity)畫一個UML的類圖:
當你看到UML的類圖再和剛才的Java項目結構圖進行對比是不是有些清晰了呢? 這個時候你可以再配合一個用例和時序圖,來表達你的業務。
整個示例源碼
what-is-a-domain-model-example
結束
也大體說完了整個演變過程,這也是我一年了的技術總結吧。
為了搞清楚心中的一個疑惑:“為什么我們項目的代碼組織結構和國外開源框架的組織結構有那么大的不同呢。” 我花了一年的時間看完了:《領域驅動設計》、《實現領域驅動設計》、 《企業應用架構模式》、《軟件建模與設計》這幾本書,其實還有正在看沒有看完的。
當你想搞懂一個東西的時候,你應該把他搞到通透,然后再說你怎么看待這個問題。 有的時候我在看完DDD以后,我還是會問自己,這是我想要的嗎?出現這種疑惑還是需要攀登, 你應該繼續選擇研究這本書引用其他知識,知識的傳播可能是書籍也可能是論文。 當把這些迭代的思想看完以后,你還得回過頭來在看這個問題,再去揣摩。可能會有新的突破。 只有這樣一次次的突破,才能解決你心中的疑惑。
還有很多細節我可能沒有一一表達出來。 上述演變過程僅代表我個人思考,禁止轉載,如有誤人子弟之處,請您指出。
如有問題請加QQ群討論:
總結
以上是生活随笔為你收集整理的领域驱动设计 pdf_什么是领域驱动设计?的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: java 实体类 临时注解_JPA:Ja
- 下一篇: 投资性价比夏普比率是什么意思