研究領域驅動設計(後面簡稱DDD)有半年之多,初識DDD是由於瞭解何爲充血模式,何爲貧血模式,進而順蔓摸瓜觸及DDD,初次瞭解有種相見恨晚的感受,爲何到如今才瞭解到有DDD這麼個東西,以後,一個伴隨我成長的疑惑,在我成長過程當中不斷致力於去解決,終於在DDD幫助下雲撥霧散。 個人疑惑,第一點就是對於咱們採用了不知道多久的開發模式,即Controller->Service->Dao,Service層扮演者上帝類,全部的邏輯都往裏塞,這種模式形成Service層的無限膨脹真的是對的嗎,很顯然答案是不對的,但事實上不少人對此仍是無動於衷,可是究竟要如何改進?之前在大學的時候,本身一直在給本身找外包項目作,曾經對本身放下豪言壯語,多複雜的系統,只要一次性過不要求對其進行維護以及加和改需求,我都能作出來,由於這種開發模式,確實是將CURD表現淋漓盡致,一個資深工程師的代碼實現結果,一個菜鳥也一樣作到(這裏說的是結果,不是過程,然而實際是過程也可能同樣,這就很難受了)。第二點,其實也是延續着第一點而來,隨着經驗的豐富,開始領悟到面向對象和軟件工程,那麼問題來了,在這種傳統的開發模式下,面向對象究竟體如今哪裏,咱們學到的設計模式,究竟在哪裏展開實踐,而實際上咱們每每是掛羊頭賣狗肉,羊頭是面向對象,狗肉是面向過程。html
下面我將一點點的引導你們進入DDD的思惟模式中,將咱們習慣的開發方式面向過程開發與DDD所倡導的面向模型開發進行對比,逐步進入面向對象。注意,本篇僅僅告訴你們何爲DDD,以及DDD的好處和缺點,具體如何實踐將在後面展開探討。DDD提出了一個所謂的領域建模,其實本質是面向對象開發原則中的類的單一職責,咱們的第一個問題是如何處置承擔過多的職責的Service上帝類。一個字很好解決,就是拆,筆者曾經嘗試按着類的單一職責的指導,將一個依賴注入過多其餘類的一個Service類,可能有十幾二十個,讀者你能夠檢查一下本身的項目,這就是壞代碼,這帶來的好處其實只有功能點封裝,並不能解決不讓Service類臃腫的問題,他仍是會慢慢臃腫起來的,而本質還是面向過程開發,還有一個問題是,就算是這種作法解決Service類臃腫的問題,他沒法解決一個很關鍵的東西,即這裏面的代碼,沒有體現出業務性。什麼叫作沒有體現出業務性?好比說激活用戶,咱們通常會怎麼開發?程序員
public class UserService{
public void updateAvailableById(long id,boolean available){
userDao.updateAvailableById(id,available);
}
}
複製代碼
這是很典型的面向過程開發的代碼,在咱們的項目中到處可見,喪失了面向對象中對象的概念,而現現在咱們在開發的時候,反而被由於使用了數據庫而束縛了咱們的思惟,咱們在接收到需求的第一時刻,在分析設計階段,每每是以數據表爲核心進行分析設計, 也就是根據需求首先獲得數據表名和字段,而後培訓程序員學會SQL語句如何操做這些數據表,那麼程序員爲實現數據表的先後順序操做,必然會將代碼寫成過程式的風格,以數據表爲核心進行分析設計,代碼很難避免不演變成過程式的代碼,由於咱們的重點放在了操做某張表,以及相關的某個字段。 這裏就是所謂的貧血模型了,UserDao是關於用戶表的SQL語句的集合,在項目中的表現就是寫了一堆SQL語句,UserService則是做爲Transaction Script的入口以及夾雜着其餘雜七雜八的Service類。而這一整個過程當中,user對象都沒出現過。 而領域驅動倡導的作法以下。spring
@Data
public class User{
private Long id;
private Boolean available;
public void activate(){
this.setAvailable(true);
}
}
//領域驅動服務
@Service
public class UserOperationService{
@Autowired
private UserRepository userRepository;
public void activate(User user){
user.activate();
userRepository.save(user);
}
}
複製代碼
首先第一點是類富含行爲(即充血模式),這纔是真正倡導的面向對象開發,業務系統所關注的點是業務功能而不是想着這個功能咱們應該如何建表,如何寫SQL語句,一直以來咱們的思惟都由於使用了數據庫而被綁架了,一上來就開始建表寫代碼,代碼寫的很是冗餘,徹底是過程式的思考方式,最後致使系統很是難以維護。業務功能只須要明白是激活功能,而不是把user表中available設爲true,數據庫只是基礎設施,咱們不該該關注以及知會對應的SQL語句是怎麼樣的,因此DDD強調的是Repository而不是DAO,Repository翻譯爲倉庫資源,所需即所得,不用去關注其背後,而DAO咱們不得不去關心SQL語句如何寫。能夠前往閱讀這篇文章進入更深刻的思考對象和數據庫的自然阻抗,若是看完以後還不是很明白的話能夠在留言區留下疑惑。數據庫
咱們不該將原屬於領域模型的行爲方法等劃放在服務中實現,對象不但有屬性還有行爲將數據和行爲封裝在一塊兒,並與現實世界的業務對象相映射。迴歸到咱們最初剛學習面向對象教咱們的那樣,萬物皆是類,而不是隻有一個上帝類,咱們須要多建立有合適邏輯的類,各種具有明確的職責劃分,使得邏輯分散到合適對象中。這樣的對象就是「充血模型」,而這個過程咱們也稱之爲領域建模,這纔是面向對象的真諦啊!設計模式
說到這裏,你們可能對以上的示例存在着一點疑惑,1.「怎麼這麼簡單的功能,用DDD的方式下卻整的這麼複雜?」,2.「你說的不就是要使用ORM框架hibernate嗎」。3.「可是一切說到底不都是須要對數據的增刪查改嗎」bash
第一點,DDD爲何稱之爲複雜軟件的設計之道?由於系統夠複雜,才能全面展示DDD的功效,業務邏輯站在至高點使得任何業務邏輯的修改擴展都能作到兵來將擋水來土掩,極大的下降了剛接觸該系統的同事上手入門的門檻,以及更好的避免存在隱藏BUG(你總會由於不當心改了一行代碼,而致使出現了業務異常)。簡單的系統功能,只有簡單的增刪查改,全部的業務邏輯實際只有簡單的增長和查詢,根本沒法提煉出來領域模型,若直接運用DDD的所有理論,實則浪費時間,殺雞用牛刀。可是沒有亙古不變的代碼,重構是一直伴隨着整個系統的演變,所以建議是即使是簡單系統,最好一開始就搭好DDD的樣子,後面我會繼續出幾篇文章,總結我對於DDD理論的實踐。架構
對於第二點,建議你們前往閱讀此篇文章 領域驅動設計(DDD)的實踐經驗分享之ORM的思考,仍是那句話,若是看完還不是很明白的話,請到留言區進行留言。其實目的就是爲了不進行數據建模, 數據模型,數據庫技術綁架了面向對象開發的思路,無形中致使開發人員率先輸出表設計,而忽略本來的模型設計,進行造成思惟習慣,「你這樣表很差設計啊」。而Hibernate實際上是根據DDD中的JPA理論指導下設計,就是爲了讓開發人員更加專一於業務邏輯實現,進行領域建模。框架
還有一個問題是一直以來不少人都錯誤的使用了像hibernate這種全ORM框架,建議你們前往閱讀此片文章如何對 JPA 或者 MyBatis 進行技術選型學習
第三點,初步認識DDD並想展開實踐的,確實會存在這個疑惑,DDD難在一點的是,他須要你思惟的轉變,你須要開始不去關注數據庫,不去關心SQL語句, 從數據建模轉向領域建模,而這個過程又會將你面向對象過車功能的思惟短板暴露出來,很抱歉,長期以來你並無用面向對象的思惟來開發。 Alistair Cockburn 提出了六邊形架構,旨在解決了傳統的分層架構所帶來的問題。倡導的是屏蔽技術細節,強調業務邏輯,最終目的是實現業務邏輯可重用,組織爲一個可重用的自封閉的業務模型,即拷貝不走樣。仔細想一想在貧血模式下,最大的不足就是業務邏輯不能重用,業務邏輯沒有組織爲一個可重用的自封閉的業務模型。 this
初步認識領域驅動設計的第一篇文章就講到這裏,後續會繼續分享領域驅動設計的概念和實踐。走過路過不要錯過,您的點贊是給予我寫做的最大動力。