轉(zhuǎn)帖|其它|編輯:郝浩|2010-11-10 11:33:44.000|閱讀 585 次
概述:在上一篇文章中,我們討論了組織業(yè)務(wù)邏輯的模式:Transaction Script和Active Record,Domain Model。在本篇中開始講述Anemic Model。
# 界面/圖表報表/文檔/IDE等千款熱門軟控件火熱銷售中 >>
前言: 在上一篇文章中,我們討論了組織業(yè)務(wù)邏輯的模式:Transaction Script和Active Record,Domain Model。在本篇中開始講述Anemic Model。
本篇議題如下:
Transaction Scrip(前篇)
Active Record前篇)
Domain Model(中篇)
Anemic Model(后篇)
DDD(后篇)
Anemic Domain Model:
這種模式和之前講述的Domain Model有很多的相似的地方。在之前的Domain Model中,每個業(yè)務(wù)類都包含了自己的業(yè)務(wù)邏輯和數(shù)據(jù),以及對象之前的關(guān)系;但是在Anemic Domain Model,每個業(yè)務(wù)類僅僅只是包含了一些保存業(yè)務(wù)數(shù)據(jù)的屬性,把相應(yīng)的業(yè)務(wù)規(guī)則從原本的業(yè)務(wù)類中移到了另外的一個專門的業(yè)務(wù)規(guī)則類(Specification Pattern,我們后面的章節(jié)講述),同時把相應(yīng)的業(yè)務(wù)方法移到了service類中。之前在Domain Model中,service類包含了一些粗顆粒度的業(yè)務(wù)方法,現(xiàn)在service類中也包含了原本在業(yè)務(wù)類中的細(xì)粒度的業(yè)務(wù)方法。
我們再來看看在這種組織方式下,我們之前的代碼如何寫:
大家看到上面的代碼,里面已經(jīng)沒有了業(yè)務(wù)邏輯的方法和一些規(guī)則,這些東西都被移到了另外的一個類中:
大家在看看service類,現(xiàn)在service類中方法就很多了:
到這里為止,四種組織業(yè)務(wù)邏輯的模式就講述完了,每一種都有自己的用途,無所謂“一定用,或者一定不用”。到底是用哪種,都是根據(jù)項目和經(jīng)驗而定。
DDD:
下面我們就來進(jìn)入DDD,這里只是講述了一下DDD中的一些基本概念,至于具體的講述DDD:
1. 后面的章節(jié)會陸續(xù)的介紹
2. 閱讀《領(lǐng)域驅(qū)動設(shè)計.軟件核心復(fù)雜性應(yīng)對之道》,如果朋友們有需要,留下自己的Email,我會發(fā)送給大家。
分層架構(gòu)
當(dāng)我們創(chuàng)建一個軟件應(yīng)用時,這個應(yīng)用的很大一部分是不能直接跟領(lǐng)域關(guān)聯(lián)的,但它們是基礎(chǔ)設(shè)施的一部分或者是為軟件服務(wù)的。最好能讓應(yīng)用中的領(lǐng)域部分盡可能少地和其他的部分摻雜在一起,因為一個典型的應(yīng)用包含了很多和數(shù)據(jù)庫訪問,文件或網(wǎng)絡(luò)訪問以及用戶界面等相關(guān)的代碼。
在一個面向?qū)ο蟮某绦蛑校脩艚缑妗?shù)據(jù)庫以及其他支持性代碼經(jīng)常被直接寫到業(yè)務(wù)對象中。附加的業(yè)務(wù)邏輯被嵌入到UI 組件和數(shù)據(jù)庫腳本的行為中。之所以這樣做的某些原因是這樣可以很容易地讓事情快速工作起來。
但是,當(dāng)領(lǐng)域相關(guān)的代碼被混入到其他層時,要閱讀和思考它也變得極其困難。表面看上去是對UI 的修改,卻變成了對業(yè)務(wù)邏輯的修改。對業(yè)務(wù)規(guī)則的變更可能需要謹(jǐn)慎跟蹤用戶界面層代碼、數(shù)據(jù)庫代碼以及其他程序元素。實現(xiàn)粘連在了一起,模型驅(qū)動對象于是變得不再可行。也很難使用自動化測試。對于每個活動中涉及到的技術(shù)和邏輯,程序必須保持簡單,否則就會變得很難理解。因此,將一個復(fù)雜的程序切分成層。開發(fā)每一個層中內(nèi)聚的設(shè)計,讓每個層僅依賴于它底下的那層。遵照標(biāo)準(zhǔn)的架構(gòu)模式以提供層的低耦合。將領(lǐng)域模型相關(guān)的代碼集中到一個層中,把它從用戶界面、應(yīng)用和基礎(chǔ)設(shè)施代碼中分隔開來。釋放領(lǐng)域?qū)ο蟮娘@示自己、保存自己、管理應(yīng)用任務(wù)等職責(zé),讓它專注于展現(xiàn)領(lǐng)域模型。這會讓一個模型進(jìn)一步富含知識,更清晰地捕獲基礎(chǔ)的業(yè)務(wù)知識,讓它們正常工作。
一個通用領(lǐng)域驅(qū)動設(shè)計的架構(gòu)性解決方案包含4 個概念層:
將應(yīng)用劃分成分離的層并建立層間的交換規(guī)則很重要。如果代碼沒有被清晰隔離到某層中,它會迅即混亂,因為它變得非常難以管理變更。在某處對代碼的一個簡單修改會對其他地方的代碼造成不可估量的結(jié)果。領(lǐng)域?qū)討?yīng)該關(guān)注核心的領(lǐng)域問題。它應(yīng)該不涉及基礎(chǔ)設(shè)施類的活動。用戶界面既不跟業(yè)務(wù)邏輯緊密捆綁也不包含通常屬于基礎(chǔ)設(shè)施層的任務(wù)。在很多情況下應(yīng)用層是必要的。它會成為業(yè)務(wù)邏輯之上的管理者,用來監(jiān)督和協(xié)調(diào)應(yīng)用的整個活動。
例如,對一個典型的交互型應(yīng)用,領(lǐng)域和基礎(chǔ)設(shè)施層看上去會這樣:用戶希望預(yù)定一個飛行路線,要求用一個應(yīng)用層中的應(yīng)用服務(wù)來完成。應(yīng)用依次從基礎(chǔ)設(shè)施中取得相關(guān)的領(lǐng)域?qū)ο螅{(diào)用它們的相關(guān)方法,比如檢查與另一個已經(jīng)被預(yù)定的飛行線路的安全邊界。當(dāng)領(lǐng)域?qū)ο髨?zhí)行完所有的檢查并修改了它們的狀態(tài)決定后,應(yīng)用服務(wù)將對象持久化到基礎(chǔ)設(shè)施中。
實體
有一類對象看上去好像擁有標(biāo)識符,它的標(biāo)識符在歷經(jīng)軟件的各種狀態(tài)后仍能保持一致。對這些對象來講這已經(jīng)不再是它們關(guān)心的屬性,這意味著能夠跨越系統(tǒng)的生命周期甚至能超越軟件系統(tǒng)的一系列的延續(xù)性和標(biāo)識符。我們把這樣的對象稱為實體。
OOP 語言會把對象的實例放于內(nèi)存,它們對每個對象會保持一個對像引用或者是記錄一個對象地址。在給定的某個時刻,這種引用對每一個對象而言是唯一的,但是很難保證在不確定的某個時間段它也是如此。實際上恰恰相反。對象經(jīng)常被移出或者移回內(nèi)存,它被序列化后在網(wǎng)絡(luò)上傳輸,然后在另一端被重新建立,或者它們都被消除。在程序的運(yùn)行環(huán)境中,那個看起來像標(biāo)識符的引用關(guān)系其實并不是我們在談?wù)摰臉?biāo)識符。
如果有一個存放了天氣信息(如溫度)的類,很容易產(chǎn)生同一個類的不同實例,這兩個實例都包含了同樣的值,這兩個對象是完全相當(dāng)?shù)模梢杂闷渲幸粋€跟另一個交換,但它們擁有不同的引用,它們不是實體。如果我們要用軟件程序?qū)崿F(xiàn)一個“人”的概念,我們可能會創(chuàng)建一個Person 類,這個類會帶有一系列的屬性,如:名稱,出生日期,出生地等。這些屬性中有哪個可以作為Person 的標(biāo)識符嗎?名字不可以作為標(biāo)識符,因為可能有很多人擁有同一個名字。如果我們只考慮兩個人的名字的話,我們不能使用同一個名字來區(qū)分他們兩個。我們也不能使用出生日期作為標(biāo)識符,因為會有很多人出在同一天出生。同樣也不能用出生地作為標(biāo)識符。一個對象必須與其他的對象區(qū)分開來,即使是它們擁有著相同的屬性。錯誤的標(biāo)識符可能會導(dǎo)致數(shù)據(jù)混亂。
考慮一下一個銀行會計系統(tǒng)。每一個賬戶擁有它自己的數(shù)字碼。每一個賬戶可以用它的數(shù)字碼來精確標(biāo)識。這個數(shù)字碼在系統(tǒng)的生命周期中會保持不變,并保證延續(xù)性。賬戶碼可以作為一個對象存在于內(nèi)存中,也可以被在內(nèi)存中銷毀,發(fā)送到數(shù)據(jù)庫中。當(dāng)這個賬戶被關(guān)閉時,它還可以被歸檔,只要還有人對它感興趣,它就依然在某處存在。不論它的表現(xiàn)形式如何,數(shù)字碼會保持一致。因此,在軟件中實現(xiàn)實體意味著創(chuàng)建標(biāo)識符。對一個人而言,其標(biāo)識符可能是屬性的組合:名稱,出生日期,出生地,父母名稱、當(dāng)前地址。在美國,社會保險號也會用來創(chuàng)建標(biāo)識符。對一個銀行賬戶來說,賬號看上去已經(jīng)足可以作為標(biāo)識符了。通常標(biāo)識符或是對象的一個屬性(或?qū)傩缘慕M合),一個專門為保存和表現(xiàn)標(biāo)識符而創(chuàng)建的屬性,也或是一種行為。對兩個擁有不同標(biāo)識符的對象來說,能用系統(tǒng)輕易地把它們區(qū)分開來,或者兩個使用了相同標(biāo)識符對象能被系統(tǒng)看成是相同的,這些都是非常重要的。如果不能滿足這個條件,整個系統(tǒng)可能是有問題的。
有很多不同的方式來為每一個對象創(chuàng)建一個唯一的標(biāo)識符:可能由一個模型來自動產(chǎn)生ID,在軟件中內(nèi)部使用,不會讓它對用戶可見;它可能是數(shù)據(jù)庫表的一個主鍵,會被保證在數(shù)據(jù)庫中是唯一的。只要對象從數(shù)據(jù)庫中被檢索,它的ID 就會被檢索出并在內(nèi)存中被重建;ID 也可能由用戶創(chuàng)建,例如每個機(jī)場會有一個關(guān)聯(lián)的代碼。每個機(jī)場擁有一個唯一的字符串ID,這個字符串是在世界范圍內(nèi)通用的,被世界上的每一個旅行代理使用以標(biāo)識它們的旅行計劃中涉及的機(jī)場。另一種解決方案是使用對象的屬性來創(chuàng)建標(biāo)識符,當(dāng)這個屬性不足以代表標(biāo)識符時,另一個屬性就會被加入以幫助確定每一個對象。
當(dāng)一個對象可以用其標(biāo)識符而不是它的屬性來區(qū)分時,可以將它作為模型中的主要定義。保證類定義簡潔并關(guān)注生命周期的延續(xù)性和可標(biāo)識性。對每個對象定義一個有意義的區(qū)分,而不管它的形式或者歷史。警惕要求使用屬性匹配對象的需求。定義一個可以保證對每一個對象產(chǎn)生一個唯一的結(jié)果的操作,這個過程可能需要某個符號以保證唯一性。這意味著標(biāo)識可以來自外部,或者它可以是由系統(tǒng)產(chǎn)生、使用任意的標(biāo)識符,但它必須符合模型中的身份差別。模型必須定義哪些被看作同一事物。
實體是領(lǐng)域模型中非常重要的對象,并且它們應(yīng)該在建模過程開始時就被考慮。決定一個對象是否需要成為一個實體也很重要,這會在下一個模型中被討論。
本站文章除注明轉(zhuǎn)載外,均為本站原創(chuàng)或翻譯。歡迎任何形式的轉(zhuǎn)載,但請務(wù)必注明出處、不得修改原文相關(guān)鏈接,如果存在內(nèi)容上的異議請郵件反饋至chenjj@fc6vip.cn
文章轉(zhuǎn)載自:博客轉(zhuǎn)載