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