常言笑的家

          Spring, Hibernate, Struts, Ajax, RoR

          實(shí)戰(zhàn)DDD(Domain-Driven Design領(lǐng)域驅(qū)動設(shè)計)

                  2004年著名建模專家Eric Evans發(fā)表了他最具影響力的著名書籍:Domain-Driven Design –Tackling Complexity in the Heart of Software(中文譯名:領(lǐng)域驅(qū)動設(shè)計 2006年3月清華出版社譯本,或稱 Domain Driven-Design architecture [Evans DDD])。

            Martin Fowler作序說;“希望本書是一本非常有影響力的書籍,....... Eric最值得我尊敬的一個方面是他敢于討論還未取得成功的事情”,其實(shí),時值今年2006年,DDD開發(fā)框架已經(jīng)層出不窮(如RoR、RIFE、Jdonwork等),我們項(xiàng)目軟件包結(jié)構(gòu)都變成了這樣:xxx.model;xxx.service,DDD思想已經(jīng)遍地開花,不能再說不成功了。

            DDD是告訴我們?nèi)绾巫龊脴I(yè)務(wù)層!并以領(lǐng)域驅(qū)動設(shè)計思想來選擇和合適的框架,本文以基于Jdonwork開發(fā)的JiveJdon3.0說明DDD方法的實(shí)戰(zhàn)應(yīng)用。

            首先必須認(rèn)識到:領(lǐng)域建模是一種藝術(shù)的技術(shù),不是數(shù)學(xué)的技術(shù),它是用來解決復(fù)雜軟件快速應(yīng)付變化的解決之道(快速適應(yīng)需求變化的軟件復(fù)用)。

            我們知道軟件的產(chǎn)生過程是:分析、設(shè)計、編程、測試、部署。過去,分析領(lǐng)域和軟件設(shè)計是分裂的,分析人員從領(lǐng)域中收集基本概念;而設(shè)計必須指明一組能北項(xiàng)目中適應(yīng)編程工具構(gòu)造的組件,這些組件必須能夠在目標(biāo)環(huán)境中有效執(zhí)行,并能夠正確解決應(yīng)用程序出現(xiàn)的問題。 模型驅(qū)動設(shè)計(Model-Driven Design)拋棄了分裂分析模型與設(shè)計的做法,使用單一的模型來滿足這兩方面的要求。這就是領(lǐng)域模型。

            單一的領(lǐng)域模型同時滿足分析原型和軟件設(shè)計,如果一個模型實(shí)現(xiàn)時不實(shí)用,重新尋找新模型。如果模型沒有忠實(shí)表達(dá)領(lǐng)域關(guān)鍵概念時,也必須重新尋找新的模型。 建模和設(shè)計成為單個迭代循環(huán)。將領(lǐng)域模型和設(shè)計緊密聯(lián)系。因此,建模專家必須懂設(shè)計,會編程。

          分層架構(gòu)

            最初層次只分為三層:表現(xiàn)層、業(yè)務(wù)層和持久層;DDD其實(shí)告訴我們?nèi)绾巫寣?shí)現(xiàn)業(yè)務(wù)層!

            一位道友曾經(jīng)請教層次的職責(zé),對服務(wù)Service提出疑問。根據(jù)Eric的理論,業(yè)務(wù)層將細(xì)分為兩個層次:應(yīng)用層和領(lǐng)域?qū)印K鼈兊亩x是:應(yīng)用層:定義軟件可以完成的工作,并且指揮具有豐富含義的領(lǐng)域?qū)ο髞斫鉀Q問題,保持精練;不包括業(yè)務(wù)規(guī)則或知識,無業(yè)務(wù)情況的狀態(tài); 領(lǐng)域?qū)樱贺?fù)責(zé)表示業(yè)務(wù)概念、業(yè)務(wù)狀態(tài)的信息和業(yè)務(wù)規(guī)則,是業(yè)務(wù)軟件核心。

            層次之間必須清晰分離,每個層都是內(nèi)聚的,并且只依賴它的下層,為了實(shí)現(xiàn)各層的最大解耦,Ioc模式和Ioc容器是目前最好的選擇,Jdonwork使用基于PicoContainer的Ioc容器實(shí)現(xiàn)了各層的松耦合;

            Eric特別指出:那種將業(yè)務(wù)邏輯交由業(yè)務(wù)界面處理的快速UI方式是旁門左道。希望象C/S結(jié)構(gòu)那樣可視化拖拖圖形就完成的軟件開發(fā)是一種錯誤的方向,開發(fā)時快速,難于維護(hù)和擴(kuò)展,雖然使用J2EE技術(shù),其實(shí)是一種偽多層技術(shù)。可惜,有很多國人在瘋狂開發(fā)這類工具,大有不撞南墻不低頭之勢,并且瘋狂誤導(dǎo)很多非專業(yè)人士,可悲可嘆!如果對這段言論持不同意見,建議你購買"領(lǐng)域驅(qū)動設(shè)計"這本譯書,見P53頁。

          領(lǐng)域模型種類

            傳統(tǒng)模型分為兩種:實(shí)體(Entity)和值對象( Object),現(xiàn)在服務(wù)(Service)成為第三種模型元素。

            實(shí)體(Entity)定義:通過一系列連續(xù)性(continuity)和標(biāo)識(identity ID)來定義;個人認(rèn)為它和分析領(lǐng)域的四色原型中的PPT原型非常類似,可以看成是PPT原型延續(xù)。

            實(shí)體必須擁有自己的唯一ID,主鍵,如果沒有一個ID標(biāo)識,為每個實(shí)例加上一個具有唯一性ID,可能是內(nèi)部使用。 如JiveJdon3.0中jdonwork.xml中模型增刪改查CRUD配置定義:

          <model key="forumId" class="com.jdon.jivejdon.model.Forum">
              ..     
          </model>

            其中,forumId是模型com.jdon.jivejdon.model.Forum的主鍵,唯一ID,每個模型必須有一個專家。

            值對象( Object):如果一個對象代表了領(lǐng)域的某種描述性特征,且沒有概念性的標(biāo)識。個人認(rèn)為它是四色原型中Deion原型延續(xù)。如果我們只關(guān)心模型中一個元素的屬性,那么把這個元素劃為值對象。值對象是不可變的,不要給它任何標(biāo)識,避免實(shí)體的維護(hù)性,降低設(shè)計復(fù)雜性。我們不關(guān)心值對象是哪個實(shí)例。

            在JiveJdon3.0中,F(xiàn)orumState是一個值對象,它表示論壇當(dāng)前最新帖子、論壇的主題數(shù)量和帖子數(shù)量,它的根對象是Forum,是被內(nèi)聚嵌入到Forum這個實(shí)體模型中的,代碼如下:

           1package com.jdon.jivejdon.model;
           2
           3
           4
           5
           6/**
           7* Forum State Object
           8* this is a embeded class in Forum. 
           9@author <a href="mailto:banqiao@jdon.com">banq</a>
          10*
          11*/

          12public class ForumState 
          13
          14  private int threadCount = 0//主題數(shù)量 
          15
          16  
          17  private int messageCount = 0;//帖子數(shù)量
          18
          19
          20  private ForumMessage lastPost; //最新帖子 
          21
          22
          23  public int getMessageCount() {
          24    return messageCount;
          25  }
            
          26
          27  
          28}
           
          29
          30

            同樣ForumThreadState是也是一種值對象,根據(jù)Eric的值對象設(shè)計,F(xiàn)orumThreadState和ForumState是可以合并成一個對象的,值對象中沒有ID等唯一標(biāo)識。

            Eric認(rèn)為:服務(wù)Service是描述領(lǐng)域概念最自然的方式,是四色原型的MI原型的延續(xù), 優(yōu)秀服務(wù)3個特征:
            1.與領(lǐng)域概念相關(guān)的操作行為、但不是實(shí)體和值對象中固有的部分。
            2.接口根據(jù)領(lǐng)域模型中其他元素定義
            3.操作是無狀態(tài)的。

            在JiveJdon3中,com.jdon.jivejdon.service.ForumService和Forum實(shí)體模型及其值對象ForumState共同完成領(lǐng)域模型,其中ForumService屬于應(yīng)用服務(wù)層;而后兩者屬于領(lǐng)域?qū)樱黄渌?wù)ForumMessageService、AccountService和UploadService等都是此類性質(zhì)。

          領(lǐng)域?qū)ο蟮纳芷赟cope

            Spring 1.x剛出來時確實(shí)忽悠了大家一把,因?yàn)樗麤]有領(lǐng)域?qū)ο蟮纳芷谥С郑钡絊pring 2.0才將如new Bean scope,當(dāng)初那些瘋狂捧Spring 1.x 臭腳的所謂高手是不是還是基于數(shù)據(jù)庫驅(qū)動的思維,根本沒有真正OO模式思維,當(dāng)今天JBoss Seam、Scopes等框架開始重視對象生命周期支持后,曾經(jīng)發(fā)生在Jdon社區(qū)爭戰(zhàn)硝煙已經(jīng)過去,成為歷史。

            Eric認(rèn)為:每個對象獨(dú)有器生命周期,一個對象在創(chuàng)建以后,可能要經(jīng)歷各種不同的狀態(tài),并最終消亡。 對象生命周期由長短:臨時對象;常駐內(nèi)存;有的與其他對象存在復(fù)雜的依賴關(guān)系;狀態(tài)變化時必須滿足一些不變量的約束條件。 如何管理這些對象提出挑戰(zhàn)!處理不好會偏離MDD的方向。

            在生命周期中維護(hù)對象的完整性。避免模型由于管理生命周期的復(fù)雜性而陷入困境。有 三個模式來處理:聚合(Aggregate):定義清晰的所有權(quán)和邊界使模型更加緊湊,避免出現(xiàn)盤根錯節(jié)的對象關(guān)系網(wǎng);工廠(Factory)和組合(Respository)。

            當(dāng)一個對象生命周期之始,使用工廠和組合提供了訪問和控制模型對象的方法,完善了MDD。 建立聚合的模型,并且把工廠和組合加入設(shè)計中來,可以使我們系統(tǒng)地對模型對象進(jìn)行管理。 聚合圈出一個范偉,在這個范圍中,對象無論在哪個生命周期,保持不變性。

            在JiveJdon3.0中,值對象ForumState是被聚合在實(shí)體模型Forum中,F(xiàn)orum作為ForumState的一個根,由于它們數(shù)據(jù)必須保持一致性,不變量(invariant)是指無論何時發(fā)生數(shù)據(jù)變化必須滿足一致性規(guī)則,由于根控制了訪問,就無法繞過它修改內(nèi)部元素,例如,如果沒有Forum實(shí)體對象這個根,就無法去修改對象狀態(tài)ForumState,F(xiàn)orumState獲得是通過Forum的getter方法獲得的。

            ForumState和Forum的分離有可以使修改論壇狀態(tài)數(shù)據(jù)(當(dāng)發(fā)一個新帖時,必須更新當(dāng)前論壇的最新帖子為該新帖),不會影響到Forum其他元素,特別是使用事務(wù)鎖定時,不必鎖住整個對象,見"領(lǐng)域驅(qū)動設(shè)計"書籍P92。

            另外,F(xiàn)orumThread和ForumMessage的關(guān)聯(lián)關(guān)系必設(shè)定成單向的,而不是雙向的,因?yàn)轭I(lǐng)域建模中,關(guān)聯(lián)越簡單越好。

            在JiveJdon3.0中,你可能注意到有一個com.jdon.jivejdon.service.factory.ForumBuilder,所有實(shí)體模型對象的獲得都是從這個工廠創(chuàng)建出來的,我曾經(jīng)徘徊過:這個工廠類是否應(yīng)該屬于持久層,因?yàn)镴iveJdon3.0持久層沒有使用Hibernate這樣O/R Mapping框架,而是直接使用SQL,但是從持久層輸出的都是對象,這是必須堅持的一個設(shè)計原則(好像是MF的一個什么元數(shù)據(jù)模式) 。

            但是,Eric明確告訴我們,領(lǐng)域模型的工廠屬于應(yīng)用層,頁就是還是應(yīng)該處于業(yè)務(wù)層的,這樣好處很多,業(yè)務(wù)層設(shè)計根本無需從Hibernate等持久層框架獲得,而是從自己的工廠獲得。

            組合(Respository)又被翻譯成倉儲,我認(rèn)為組合合適,主要用來返回一批對象,查詢組合常用來返回批量查詢結(jié)果,Jdonwork兩個快速開發(fā)支持:批量查詢其實(shí)應(yīng)該是Respository的實(shí)現(xiàn),實(shí)際也是過去Master-details的一種查詢實(shí)現(xiàn)。

            以com.jdon.jivejdon.presentation.action.ThreadListAction為例子,其功能是查詢論壇Forum下所有主題ForumThread,并分頁顯示,實(shí)現(xiàn)效果按這里,我們在customizeListForm方法中將根Model Forum設(shè)置進(jìn)入,在threadList.jsp中,我們使用struts的標(biāo)簽庫logic:iterator來遍歷組合對象threadListForm中的ForumThread集合。

          失血模型

            MF(Martin Fowler)曾經(jīng)提出有名的貧血模型或失血模型,讓我們好生迷惑和彷徨,他認(rèn)為實(shí)體模型對象中只有弱行為setter和getter方法,沒有真正行為,好像缺少血液的人,不和諧了,不少高手又被忽悠了,大談貧血模型。

            其實(shí),Eric已經(jīng)認(rèn)為,在DDD中,領(lǐng)域中一些概念不能作為模型中的對象來處理的,如果將這些功能概念強(qiáng)行加給實(shí)體對象和值對象,破壞模型中對象的定義,人為添加沒有意義的對象。服務(wù)是描述領(lǐng)域概念最自然的方式。

            為了在這些大師之間取得一個平衡,有人將Model的持久化操作(CRUD行為)整入到領(lǐng)域模型中,這是不是違背當(dāng)初Dao模式初衷,Dao模式其實(shí)是橋模式和適配器模式組合(見SUN的J2EE核心模式)。

            無論如何,我們的DDD項(xiàng)目中都是以失血模型存在著,所以,Eric呼喚:建模專家必須懂得實(shí)現(xiàn),懂得軟件技術(shù),MF可能會聽進(jìn)去的。

          本站提供DDD領(lǐng)域建模培訓(xùn)

          相關(guān)文章

          狀態(tài)對象:數(shù)據(jù)庫的替代者

          數(shù)據(jù)庫時代的終結(jié)

          快速適應(yīng)需求變化的軟件復(fù)用

          Java項(xiàng)目開發(fā)中常見根本性認(rèn)識誤區(qū)

          領(lǐng)域模型驅(qū)動設(shè)計(DDD)之模型提煉

          Ruby On Rails 與Jdon work架構(gòu)比較

          Organizing Domain Logic

          Java EE/J2EE面向?qū)ο缶幊讨?/a>

          posted on 2006-12-16 22:22 常言笑 閱讀(313) 評論(0)  編輯  收藏 所屬分類: 技術(shù)總結(jié)

          My Links

          Blog Stats

          常用鏈接

          留言簿(5)

          隨筆分類

          隨筆檔案

          搜索

          積分與排名

          最新評論

          閱讀排行榜

          評論排行榜

          主站蜘蛛池模板: 阜宁县| 堆龙德庆县| 九寨沟县| 固安县| 无棣县| 吴桥县| 望谟县| 新安县| 祁连县| 福州市| 吉安县| 江津市| 凤城市| 龙岩市| 南阳市| 乐业县| 汝城县| 秦皇岛市| 肃宁县| 永靖县| 昌吉市| 水富县| 淄博市| 西贡区| 遵义县| 宁国市| 峨眉山市| 沛县| 什邡市| 怀宁县| 类乌齐县| 永修县| 遵义市| 麦盖提县| 南靖县| 广丰县| 黄梅县| 台山市| 米泉市| 房产| 织金县|