Repository已經不是什麼新鮮概念了。DDD模型自2004年提出,發展至今已經16年了。可是很多企業卻沒法實施,其緣由也很簡單:DDD是基於需求的,而不少並不理解需求;DDD是容易實現的,而不少設計者並不會編程。這種狀況就有一些兩頭不討好,而若是有辦法結合統一的話,則會很是好用。前端
學習Repository的過程當中,最早要進行的是思想的轉變。在過往的編程過程當中,你們每每將目光聚焦在CRUD中,致使每一個程序員首先想的是我如何使用SQL實現我所要的目標。而在DDD過程當中,實踐者應當將目光聚焦中功能上,首先將需求分解爲若干個功能,而後再將功能進行組合。程序員
舉例而言,某系統擁有組織機構和用戶功能。組織機構樹的每一個部門下屬若干個職位,每一個職位都有用戶擔任,每一個用戶能夠出任多個部門的多個職位。這時,系統設計師告訴你這裏要有如下功能:編程
部門管理(部門的CRUD,部門下職位的CRUD,職位與部門的CRUD)設計模式
用戶管理(用戶的CRUD)api
講到這裏,很容易看出,這裏其實有四張表,也就是部門,職位,用戶和用戶職位關聯表。表關係也容易理出,部門與職位1對多,職位與用戶多對多。函數
若是你使用的是DAO思想(或者說分層思想),那麼需求分析作到這一步也就結束了。你能夠直接經過上述內容整理出你須要實現的接口,即每張表的CRUD。而後在前端實現一個界面,每一個界面調用相關的接口程序也就寫完了。好比,其中一個接口多是這樣的:學習
[Route(「~/api/SetPosition」)]ui
public void SetPosition(Guid userId, Guid positionId);設計
那麼,如今問題來了。需求發生了一個變動,來了一個全新的需求,客戶說我如今需求每一個部門的更改必須經過流程進行。即當部門信息發生變動時,必須層層審覈,最後才經過後,才能在更新數據。這個審覈過程甚至包含了一部分關鍵職位的人員變化。接口
這時,那個坑人的系統設計師又站出來了,給了你一系列功能變化表:
部門修改申請(部門修改申請CRUD,部門申請審覈,部門申請同步到部門表,部門申請同步到職位表)
看上去,這個設計很美好「自頂向下逐步細化」分解的也很是舒服。可是,你仔細研究一下就發現這裏有兩個巨大的坑:
一、新建部門修改申請。在部門修改申請時,試問是否要將之前的部門數據複製到這張申請表中?若是你不復制,那了不起了,所有門全部手動數據所有要用戶自行輸入此表,那恐怕最終用戶會和你鬧的不可開交——這什麼垃圾軟件?!而若是你打算實現他,那我告訴你,這張可怕的部門表裏,字段很少,100個(呵呵)。
二、若是你說功能1實際上是必須實現的新功能,和設計關係不大。那麼你再觀察,將部門申請同步到部門這個功能。他絕對能夠細分爲「修改部門」和「修改職位」兩個子功能,而這兩個子功能實際上是以前的接口就實現的。那麼,你是否爲以前的接口留下了複用性?仔細看看以前接口的實現代碼,你就會悲劇的發現,70%的可能性那個接口是沒法複用的,由於查詢代碼其實不太同樣。
那這只是我隨手說的一個需求變動,若是有更多的需求變化呢?那麼雖然代碼仍是可以複用一部分,設計空間釋放也不會太麻煩。可是,仔細評判你的代碼和設計,就會發現原來優雅而簡潔的可複用設計的複用性愈來愈低,原來整齊而易讀的代碼的可讀性愈來愈差。這就是人間悲劇。
而這時,Repository的思想從天而降,他也許可以爲你可憐的代碼帶來一些讓你驚喜的變動。若是使用DDD的思想設計上述內容,首先你須要肯定領域。顯而易見的,這裏的領域能夠這樣劃分:
用戶領域:添加用戶,刪除用戶,修改用戶,修改用戶的職位,移除用戶的職位
部門領域:添加部門,刪除部門,修改部門,查詢部門下的職位,查詢部門下的用戶
職位領域:添加職位,修改職位,刪除職位,查詢職位下的用戶,將用戶添加到職位中,將用戶從職位中移除
注:這裏,若是是我寫代碼,我極可能會把「部門領域」和「職位領域」合併。這個並沒有不可,由於二者其實沒有那麼明顯的邊界。
在這個設計中,能夠看到其實有些功能是重複的,好比說「修改用戶的職位」和「將用戶添加到職位中」。可是,在領域設計中,我卻將其認爲是兩個不一樣的功能,由於他們的主體不同。對前者而言,我先查出用戶,函數的參數是「用戶ID」和「職位名稱」,這裏使用出字符串的職位名稱,即意味着對於用戶領域來講,他不須要認識「職位」這個類。對於後者而言,我先查出職位,函數參數是「職位」和「一個或者多個用戶ID」。這意味着,對於職位領域來講,他也不須要認識用戶這個類。
這裏能夠看到,領域之間,耦合度很低。其實達到了最小知識原則所要求的內容。可是,實現過程當中,可能會有這樣的疑問,將職位添加到用戶過程當中,難道你不須要判斷用戶是否存在嗎?固然,判斷仍是要判斷的,可是我徹底能夠不認識用戶這個類。經過將「用戶職位關係表」中的「用戶ID」字段與用戶表中的「ID」字段作出外鍵關係,徹底可讓數據幫我保證數據有效性。我只須要作一個簡單的異常處理便可。
另外,耦合度低不等於不能耦合,在這裏查詢一次用戶表,我認爲也沒有突破什麼界限,因此徹底沒有問題。
在設計完領域後,須要再設計邊界,也就是說由哪些類將這些功能所有暴露給外界。這時能夠這麼設計:
部門類:添加職位,修改職位,刪除職位,查詢職位下的用戶,將用戶添加到職位中,將用戶從職位中移除
用戶類:查詢我所在的部門和職位
用戶服務類:用戶的CRUD
部門服務類:部門的CRUD
這裏,實際是將部門看成了職位的聚合。這只是我隨手寫的設計,沒有實踐過也不知道有沒有什麼問題。但我想大體應當是正確的。這時,我就將全部功能都經過這幾個類暴露在外界。在考慮這些內容的狀況下,再來上述需求時,問題就明確了,他須要新建一個領域:部門修改申請。
部門修改申請:經過部門新建修改申請,經過舊的修改申請新建修改申請,審覈修改申請,將修改申請同步到部門中,將修改申請同步到職位中。
如今再來看以前的兩個大坑。問題1實際上是規避不了。由於這個就是新功能,規避的惟一辦法就是加錢,錢到位了功能也就到位了。而問題2確實就簡單了,由於你能夠直接調用暴露在「修改職位功能」將申請表中的用戶給到對應職位,也能夠經過調用「修改部門功能」直接將部門信息反向同步,而不須要考慮代碼是否優雅,由於這裏就是調用一個函數,並不存在優雅與否的問題。
再到之後,若是再有新功能,哪怕你仍是須要釋放設計空間。但你在重構的時候,已經整理過的功能就不須要整理第二遍。你只須要交被釋放出的設計空間所有放回領域中,重構的工做量大大減小。而這,就是我所看重的DDD的核心優點。
針對到實現層面,以前那些亂七八糟的領域功能,其實就是Repository,他的出現天然而又簡單。你所須要的只是簡單的變化一下本身的思想,多寫幾十行代碼,僅此而已。
最後,稍稍總結一下。完成以上內容的核心和關鍵其實並非你對DDD瞭解多少。而真正有效的是你對需求瞭解多少,你認爲需求有多少內容可能發生變化。對需求把握纔是軟件設計的核心。任何設計思想,設計模式都基於對需求的理解。我我的對軟件思想的重要理解:
不基於需求任何想法都空談,不理解需求任何代碼都是胡說,不把握變化任何設計都是假想。
與君共勉。