我愛oo,我愛java

          交流blog QQ:421057986 oofrank@donews

          DAO-持久層-領(lǐng)域?qū)ο?貧血模型

          原文


          關(guān)于"貧血模型"的討論幾乎沒有停止過,在openfans.org的開發(fā)過程中,我們也討論了很久,我覺的有很多東西應(yīng)該記下來:
          明確一下意思先:
          DAO:數(shù)據(jù)操作對象,會操作數(shù)據(jù)庫
          持久層:能提供對象持久化服務(wù)的一系列組件或服務(wù)
          領(lǐng)域?qū)ο?描述領(lǐng)域模型的對象,是通過業(yè)務(wù)分析進(jìn)行系統(tǒng)建模的產(chǎn)物
          貧 血模型:就是domain object只有屬性的getter/setter方法的純數(shù)據(jù)類,所有的業(yè)務(wù)邏輯完全由一個所謂的Manager來完成(又稱 TransactionScript),這種模型下的domain object被Martin Fowler稱之為“貧血的domain object”
          常見的類基本結(jié)構(gòu)如下:
          一個業(yè)務(wù)數(shù)據(jù)類叫做Item,
          一個DAO接口類叫做ItemDao
          一個DAO接口實現(xiàn)類叫做ItemDaoHibernateImpl
          一個業(yè)務(wù)邏輯類叫做ItemManager(或者叫做ItemService).

          觀察上面的幾個類很容易發(fā)現(xiàn)問題:
          1:Item和ItemManager實際是操作與數(shù)據(jù)的關(guān)系,實際完成的就是經(jīng)典OO中的一個對象的能力;
          2:當(dāng)有許多Item時 類組變得很龐大,產(chǎn)生很多 xxxDao xxxImpl xxxManager 其中包含大量重復(fù)代碼;
          按<<重構(gòu)>>的觀點,上述代碼存在以下臭味:
          1:重復(fù)的代碼?? xxxDao xxxImpl xxxManager(通常)
          2:霰彈式修改,一個變化影響多個類,類之間不夠高內(nèi)聚 item變化-->Dao,Impl,Manager均要變動
          3:依戀情結(jié),兩個類之間互相作用過多 item<->Manager
          4:平行繼承體系,當(dāng)增加一個新類時總是要增加另一個類
          5:夸夸其談未來性,在沒有任何暗示的情況下考慮擴(kuò)展? Dao,實際HibernateImpl可能n年內(nèi)是唯一的Dao實現(xiàn)
          6:純稚的數(shù)據(jù)類,只有數(shù)據(jù)的類? item

          我覺的 貧血模型 是系統(tǒng)分析設(shè)計方向性錯誤的產(chǎn)物:
          1:沒有進(jìn)行領(lǐng)域建模---以數(shù)據(jù)表結(jié)構(gòu)為中心,而不是業(yè)務(wù)模型為中心的思考方式,使設(shè)計人員選擇Item為考慮問題的出發(fā)點
          2:將DAO與持久層混淆---我們需要的一種持久化服務(wù),DAO緊緊是提供數(shù)據(jù)操作能力而已,Hibernate是一種高級的服務(wù)(他已經(jīng)包含了DAO,而不是相反),已經(jīng)完成了所有的持久層服務(wù).
          3:過于強(qiáng)調(diào)低偶合---將一些本來一些提供單一職責(zé)的內(nèi)容分散在多個單元中使 客戶端 依賴更多的接口,而忘記了高內(nèi)聚原則.
          4:Spring的能力限制---由于Spring現(xiàn)階段不支持對于領(lǐng)域模型的服務(wù)注入,使設(shè)計人員將操作和數(shù)據(jù)分開,并將領(lǐng)域變?yōu)镈ataOnly的.
          ? (Spring2.0將在很大程度上解決這個問題)
          ?
          我認(rèn)為良好的解決方案:
          ? 首先領(lǐng)域建模,建立領(lǐng)域模型-->合并前面所說的Item和ItemManager成為 domainItem;對于數(shù)據(jù)庫服務(wù),
          ? 1:如果考慮領(lǐng)域?qū)影瑪?shù)據(jù)操作能力,則建立DAO并選擇其它好的DAO方案比如IBATIS或Hibernate之類的組件;
          ? 2:如果考慮將數(shù)據(jù)庫(或其他存儲界質(zhì))存儲考慮在領(lǐng)域之外成為持久層,
          ? ??? a:則或者對持久層框架同時建模,同時選擇合適的組件為持久層服務(wù)提供存儲服務(wù)(包括DAO--亦可選擇IBATIS/Hibernate組件),
          ? ??? b:或者直接使用Hibernate/JDO等框架實現(xiàn)持久化服務(wù),領(lǐng)域?qū)又苯邮褂贸志脤臃?wù),對領(lǐng)域?qū)ο筮M(jìn)行持久化和反持久化(從持久層獲取以持久化的對象).
          ?
          其他:
          ? 實際上,作為一種解決方案,所謂"貧血模型"的具體使用,并不會有太大的問題,尤其是使用一些代碼生成工具或已經(jīng)做好相應(yīng)的基本框架時,很多軟件的核心價 值都在于對客戶提供的服務(wù),而其內(nèi)部則成為黑盒,我們只要合理的解決業(yè)務(wù)問題,就是"王道"了,對于代碼的臭味,可以慢慢重構(gòu)--這也需要成本呀.?
          ?
          再其他:
          有人說,我們的業(yè)務(wù)就是CRUD,領(lǐng)域模型只有數(shù)據(jù)類就足夠了.我覺的這是搞錯了方向------只有CRUD時,只有處理CRUD的那些類才有必要進(jìn)行建模(他們才是領(lǐng)域模型),而所謂的User\Item等數(shù)據(jù)類則完全沒有必要進(jìn)行建模,更不要談領(lǐng)域了.

          貧血之外:
          實際上,軟件\OO方法的外延大的很,更多問題與數(shù)據(jù)庫存儲無關(guān)(但也有貧血問題),所以建模才是根本,OO方法的原則才是我們必須掌握的.

          posted on 2006-04-10 22:21 兼聽則明 閱讀(6552) 評論(4)  編輯  收藏 所屬分類: oo

          評論

          # re: DAO-持久層-領(lǐng)域?qū)ο?貧血模型 2006-04-11 01:30 mixlee

          典型的濫用接口  回復(fù)  更多評論   

          # re: DAO-持久層-領(lǐng)域?qū)ο?貧血模型 2007-10-20 13:02 鄧英妥

          不敢茍同樓主的觀點  回復(fù)  更多評論   

          # re: DAO-持久層-領(lǐng)域?qū)ο?貧血模型 2008-10-20 17:40 mojie

          合并前面所說的Item和ItemManager成為 domainItem,我認(rèn)為貧血可以使,層次更清晰 ,便于模型維護(hù)  回復(fù)  更多評論   

          # re: DAO-持久層-領(lǐng)域?qū)ο?貧血模型[未登錄] 2015-04-15 20:10 喔喔

          同樣不敢溝通樓主觀點  回復(fù)  更多評論   


          只有注冊用戶登錄后才能發(fā)表評論。


          網(wǎng)站導(dǎo)航:
           
          主站蜘蛛池模板: 临安市| 蒙城县| 陆良县| 方城县| 开封市| 石嘴山市| 铁力市| 鲁山县| 舞钢市| 许昌县| 湘阴县| 梁山县| 信阳市| 黄石市| 鄂伦春自治旗| 启东市| 恭城| 东至县| 蒲城县| 罗源县| 望谟县| 安义县| 吴川市| 温州市| 岳阳市| 盐津县| 霍林郭勒市| 沂南县| 介休市| 灵宝市| 兰州市| 教育| 巴彦淖尔市| 彭泽县| 长寿区| 仁化县| 太康县| 通许县| 广德县| 丹东市| 清苑县|