一区二区久久-一区二区三区www-一区二区三区久久-一区二区三区久久精品-麻豆国产一区二区在线观看-麻豆国产视频

領(lǐng)域驅(qū)動設(shè)計實踐

  領(lǐng)域驅(qū)動設(shè)計的關(guān)注重心是領(lǐng)域,尤其在面對復(fù)雜的領(lǐng)域邏輯時,它總能夠幫助我們很好地分析領(lǐng)域。領(lǐng)域驅(qū)動設(shè)計的基礎(chǔ)是領(lǐng)域建模。Eric認(rèn)為需要和領(lǐng)域?qū)<伊己玫睾献鳎瑥慕徽勚邪l(fā)現(xiàn)通用語言,找到領(lǐng)域的關(guān)鍵詞。領(lǐng)域建模是迭代的過程,根據(jù)逐漸深入的領(lǐng)域知識來精化模型。不過,領(lǐng)域驅(qū)動設(shè)計并不排斥其他的分析技術(shù),例如分析模式,或者通過測試驅(qū)動開發(fā)來引導(dǎo)我們找到問題域的領(lǐng)域模型。

  領(lǐng)域建模并非領(lǐng)域驅(qū)動設(shè)計所獨(dú)有。在RUP中,領(lǐng)域建模就是一個非常重要的環(huán)節(jié)。它是一種用例驅(qū)動的開發(fā)方法,通過獲得的用例來幫助分析和設(shè)計人員尋找對象,以及對象之間的關(guān)系。根據(jù)我個人的經(jīng)驗,我喜歡采用兩種截然不同的方式來獲得模型。一種是用例驅(qū)動,一種則是測試驅(qū)動。在得到初步的領(lǐng)域模型中,我會嘗試?yán)妙I(lǐng)域驅(qū)動設(shè)計的思想為對象分類,找到實體、值對象、聚合以及服務(wù)對象,并通過分析對象的生命周期,為不同類型的對象建立資源庫和工廠對象。

  本文將以一個讀者耳熟能詳?shù)膱D書館管理系統(tǒng)作為我們要分析的領(lǐng)域,嘗試講解如何在項目開發(fā)中應(yīng)用領(lǐng)域驅(qū)動設(shè)計。我將選擇用例驅(qū)動的方式來獲得我最初的領(lǐng)域模型。簡單起見,我先給出分析領(lǐng)域的用例以及用例圖。

  借書:讀者攜帶要借書籍到借書處。圖書館工作人員首先掃描讀者的借書卡,獲得讀者信息,然后掃描書籍的條形碼。如果借閱多本,則掃描多本書籍。掃描時,需要判斷當(dāng)前讀者的類型,獲得讀者可借書籍?dāng)?shù)。如果借閱書籍超出,則提示。如果掃描失敗,允許工作人員手工輸入編號。借閱的期限為1個月。

  還書:讀者攜帶要還書籍到還書處。圖書館工作人員掃描書籍的條形碼,進(jìn)行還書操作。如果借閱的書籍超期,則提示,并計算出應(yīng)收罰款的數(shù)額。如果掃描失敗,允許工作人員手工輸入編號。

  我采用了摘要方式來描述用例。我喜歡這樣一種簡潔的方式,它實際上等同于XP中的用戶故事。在需求并不復(fù)雜的時候,或者在對文檔要求并不嚴(yán)格的時候,都可以采用這種方式來編寫用例。

  以下是表達(dá)上述兩個用例的用例圖展現(xiàn):

clip_image002

  可以首先利用名詞/動詞法找到模型中的領(lǐng)域?qū)ο蟆_@種方法雖然極度地簡單與低級,然后在建立領(lǐng)域模型之初,是非常有效的手段。通過對用例的分析,大致可以獲得如下對象:Reader,Administrator,Book,Library Card以及Scanner。也許還有我們未曾發(fā)現(xiàn)的領(lǐng)域?qū)ο螅@可以通過深入領(lǐng)域或與客戶交談來進(jìn)一步獲得。我們可以嘗試著先獲得一個最簡單的領(lǐng)域模型,如下所示。

clip_image004

  我們發(fā)現(xiàn)Administrator對象是一個孤立的對象,它與其他領(lǐng)域?qū)ο鬀]有產(chǎn)生任何關(guān)系。至少在借書、還書用例中,我們并不需要管理這個對象,可以考慮刪除它。模型中的Scanner對象非常特殊,表面上它會對Book與LibraryCard進(jìn)行操作,然而對于Scanner而言,它并不關(guān)心操作的是什么對象,而只需要掃描條形碼,返回一個字符串。這是一種行為的體現(xiàn)。在整個系統(tǒng)中,Scanner對象可以只擁有一個,沒有屬性和狀態(tài),僅提供掃描功能,或者說是服務(wù),因此可以考慮將其定義為服務(wù)對象。

  Reader與Book之間的關(guān)系非常直接,可是在引入LibraryCard之后,這個關(guān)系就顯得有些尷尬了。仔細(xì)閱讀用例,我們發(fā)現(xiàn)識別讀者的信息,是通過借書卡來獲取的。無論是借書還是還書,都可以通過借書卡來獲得讀者當(dāng)前借閱的書。此時,讀者與書之間就不存在任何關(guān)系了,它已經(jīng)進(jìn)行了轉(zhuǎn)嫁。既然借書卡已經(jīng)實現(xiàn)了對借書關(guān)系的管理,我們還有必要保留Reader對象嗎?閱讀用例,我們知道在掃描借書卡時,會獲得讀者的信息。雖然我們可以在借書卡中保留這些信息,但根據(jù)單一職責(zé)原則(SRP),將其專門封裝為一個對象仍有必要。

  目前,借書卡僅僅維護(hù)了讀者當(dāng)前借閱的書籍,那么,還需要維護(hù)借閱和返還的歷史記錄嗎?從用例的描述來看,并沒有這一功能。我們感到疑惑,因為保留歷史記錄是大多數(shù)系統(tǒng)所必備的。此時,客戶的答案就顯得格外重要。“哦,是的,我們需要查看歷史記錄!”這是客戶給我們的肯定答復(fù)。顯然,查看歷史記錄屬于另一個用例,它甚至可能屬于另外一個上下文(Context),例如關(guān)于“查詢”的上下文。然而,這一信息的來源卻來自于借閱與返回用例,我們應(yīng)該將其識別出來。如果其他用例需要用到,我認(rèn)為這個對象是需要共享的。細(xì)化后的領(lǐng)域模型如下:

clip_image006

  通過對掃描行為的分析,我認(rèn)為Scanner提供的掃描行為與領(lǐng)域無關(guān),而是一種基礎(chǔ)設(shè)施,因此我將其定義為基礎(chǔ)設(shè)施層的服務(wù)。模型增加了FineCalculator對象,用以完成對超期讀者的罰款金額計算。顯然,它是一個服務(wù)對象。注意,BorrowingHistory與Book是一對一的關(guān)系,因為我們需要為每一本書建立一條借閱歷史記錄。

  現(xiàn)在,我們需要識別領(lǐng)域模型中的實體和值對象,以及可能的聚合。我們需要一個唯一的標(biāo)識來區(qū)別讀者,且這一標(biāo)識具有連續(xù)性,因此Reader是一個實體對象。同樣,Book對象也是一個實體對象,因為我們需要一個唯一標(biāo)識來完成對書籍的跟蹤。注意,在這個模型中的Book實體,其實例代表的是具體的某一本書,而不是指同一種書。因為圖書館可能就同一種書購買多本,而讀者借閱的是真實的書本,而不僅僅是書的屬性。此時,Book的標(biāo)識ID就顯得尤為重要,甚至不能用書籍的ISBN來標(biāo)識。

  從表面上看,BorrowingHistory同樣屬于實體對象,它的每一條記錄都是唯一的,即使存在兩條歷史記錄,具有相同的讀者ID與書籍ID,我們?nèi)詫⑵湟暈椴煌挠涗洠驗樗鼈兊慕栝啎r間并不相同。不過,對于系統(tǒng)的調(diào)用者而言,通常不會去關(guān)注所有的借閱記錄,而是查詢某位讀者的借閱記錄,因此,我們可以將其作為與Reader放在一起的聚合。然而,隨著對需求的深入分析,我們發(fā)現(xiàn)定義這樣的聚合存在問題,因為我們可能還需要查詢某本書的借閱記錄(例如,希望知道哪本書最受歡迎,跟蹤每本書的借閱情況等)。由于Reader和Book應(yīng)該分屬于不同的聚合,BorrowingHistory就存在無法劃定聚合的問題。既然如此,我們應(yīng)該將其分離出來,作為一個單獨(dú)的聚合根。

  讓人感覺疑惑不解的是LibraryCard對象。一方面,它的ID來源于Reader,且存在一對一的關(guān)系,因此它可以作為Reader聚合的一部分。根據(jù)模型圖來看,它實際上又記錄了讀者與書之間的關(guān)系。仔細(xì)分析,LibraryCard所維護(hù)的這樣一種讀者與書的關(guān)系,事實上正是BorrowingHistory的一種體現(xiàn),區(qū)別僅在于一個記錄了當(dāng)前的借書信息,一個還包括過去的借書信息。BorrowingHistory可以進(jìn)行信息的持久化,LibraryCard則完全可以在內(nèi)存中維持一個當(dāng)前借閱信息的集合。因此,可以將LibraryCard定義在Reader聚合中。這樣既可以減少對象之間的關(guān)聯(lián),又能保證對象之間的一致性。

  我們還需要深入分析Reader對象和Book對象的標(biāo)識ID,因為這兩者的標(biāo)識ID都是通過基礎(chǔ)設(shè)施的Scanner服務(wù)獲得的。Scanner并沒有能力知道二者之間的區(qū)別。而在借閱書籍時,根據(jù)需求規(guī)定的流程,必須是先掃描借書卡,獲得讀者信息,然后再掃描書。此外,當(dāng)掃描出現(xiàn)錯誤時,系統(tǒng)需要支持操作人員手工輸入,因此對手工輸入的內(nèi)容也需要進(jìn)行ID的驗證。我們需要有專門驗證ID的對象。

  我們還要考慮許多業(yè)務(wù)規(guī)則,例如是否允許讀者借書的規(guī)則,是否超期的規(guī)則,計算罰款額度的規(guī)則。如果這些規(guī)則極為簡單,且不具有變化的可能,可以放在領(lǐng)域?qū)ο笾小H欢坏┮?guī)則變得復(fù)雜,就會嚴(yán)重干擾相關(guān)領(lǐng)域?qū)ο蟮穆氊?zé)。根據(jù)職責(zé)分離的原則,我們可以提供專門的規(guī)則對象,即領(lǐng)域驅(qū)動設(shè)計中規(guī)格模式的應(yīng)用。如果可能變化,我們甚至可以引入策略模式,對這些規(guī)則進(jìn)行抽象。經(jīng)過分析后得到的領(lǐng)域模型如下所示:

clip_image008

  Reader實體對象和LibraryCard實體對象處于同一個聚合中,其中Reader為聚合根。BorrowingSpecification和ReturningSepecification均為值對象,并放在Reader聚合中。FineCalculator是一個服務(wù)對象,它會調(diào)用FineRule值對象獲得罰款規(guī)則,通過計算后返回Money值對象值。由于聚合的原因,原來FineCalculator與LibraryCard之間的關(guān)系已經(jīng)修改為計算Reader的罰款。

  BorrowingHistory和Book均為實體對象,而IdentityValidator則為服務(wù)對象,負(fù)責(zé)驗證掃描碼。

  接下來需要為領(lǐng)域?qū)ο筮x擇資源庫(Repository)。在領(lǐng)域模型中,只有Reader、BorrowingHistory和Book三個實體為聚合根對象,因此只需要為這三個對象建立資源庫對象即可。

clip_image010

  由于需求較為簡單,建立的領(lǐng)域模型已經(jīng)比較完善,我們可以著手編碼,對這些模型進(jìn)行驗證。本文沒有考慮限定上下文的情況,我希望未來的文章能夠以真實的案例對此進(jìn)行表述。整體而言,根據(jù)這個案例,我們已經(jīng)能夠初步領(lǐng)略領(lǐng)域驅(qū)動設(shè)計的基本步驟。

it知識庫領(lǐng)域驅(qū)動設(shè)計實踐,轉(zhuǎn)載需保留來源!

鄭重聲明:本文版權(quán)歸原作者所有,轉(zhuǎn)載文章僅為傳播更多信息之目的,如作者信息標(biāo)記有誤,請第一時間聯(lián)系我們修改或刪除,多謝。

主站蜘蛛池模板: 亚洲美女人黄网成人女 | 国产精品自在自线免费观看 | 色婷婷综合久久久久中文一区二区 | 一区二区三区免费视频网站 | 日本一区二区三区高清在线观看 | 久久亚洲欧美日本精品品 | 欧美激情视频在线免费观看 | 99视频精品全部 在线 | 亚在线 | 国产精品美女在线 | 四房激情网| 黄网在线观看网址入口 | 中文字幕一区中文亚洲 | 欧美在线91 | 韩国一级成a人片在线观看 韩国一级毛片 | 亚洲第一免费视频 | 亚洲a影院| 欧美一级性视频 | 国产一级不卡毛片 | 久久综合久久久久 | 久久福利一区二区 | 黄色小视频免费在线观看 | 国产午夜在线视频 | 欧美另类videosbestsex久久 | 国产精品久久久久久永久牛牛 | 五月开心激情 | 欧美日韩亚洲一区二区精品 | 中日韩美中文字幕 | 97国产成人精品免费视频 | 加勒比热 | 国产第一第二第三第四第五 | 国产精品麻豆视频 | 天天色天天综合 | 视频一区国产精品 | 国产综合亚洲欧美日韩一区二区 | 午夜久久久精品 | tube44欧美高清 | 亚洲第一网站免费视频 | 亚洲视频国产 | 亚洲色在线视频 | 一本色道久久88加勒比—综合 |