<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    posts - 89,  comments - 98,  trackbacks - 0

    在最近的圍繞domain object的討論中浮現(xiàn)出來了三種模型,(還有一些其他的旁枝,不一一分析了),經(jīng)過一番討論,各種問題逐漸清晰起來,在這里我試圖做一個總結(jié),便于大家了解和掌握。

    第一種模型:只有g(shù)etter/setter方法的純數(shù)據(jù)類,所有的業(yè)務(wù)邏輯完全由business object來完成(又稱TransactionScript),這種模型下的domain object被Martin Fowler稱之為“貧血的domain object”。下面用舉一個具體的代碼來說明,代碼來自Hibernate的caveatemptor,但經(jīng)過我的改寫:

    一個實(shí)體類叫做Item,指的是一個拍賣項(xiàng)目
    一個DAO接口類叫做ItemDao
    一個DAO接口實(shí)現(xiàn)類叫做ItemDaoHibernateImpl
    一個業(yè)務(wù)邏輯類叫做ItemManager(或者叫做ItemService)

    java代碼
    						public
    						class 
    						Item
    						implements
    						Serializable
    						{
    						
    private Long id = null ;
    private int version ;
    private String name ;
    private User seller ;
    private String description ;
    private MonetaryAmount initialPrice ;
    private MonetaryAmount reservePrice ;
    private Date startDate ;
    private Date endDate ;
    private Set categorizedItems = new HashSet ();
    private Collection bids = new ArrayList ();
    private Bid successfulBid ;
    private ItemState state ;
    private User approvedBy ;
    private Date approvalDatetime ;
    private Date created = new Date ();
    / / getter / setter方法省略不寫,避免篇幅太長
    }

    java代碼
    						public
    						interface
    						ItemDao
    						{
    						
    public Item getItemById ( Long id );
    public Collection findAll ();
    public void updateItem ( Item item );
    }

    ItemDao定義持久化操作的接口,用于隔離持久化代碼。

    java代碼
    						public
    						class 
    						ItemDaoHibernateImpl
    						implements
    						ItemDao
    						extends
    						HibernateDaoSupport
    						{
    						
    public Item getItemById ( Long id ) {
    return ( Item ) getHibernateTemplate (). load ( Item . class , id );
    }
    public Collection findAll () {
    return ( List ) getHibernateTemplate (). find (" from Item ");
    }
    public void updateItem ( Item item ) {
    getHibernateTemplate (). update ( item );
    }
    }

    ItemDaoHibernateImpl完成具體的持久化工作,請注意,數(shù)據(jù)庫資源的獲取和釋放是在ItemDaoHibernateImpl里面處理的,每個DAO方法調(diào)用之前打開Session,DAO方法調(diào)用之后,關(guān)閉Session。(Session放在ThreadLocal中,保證一次調(diào)用只打開關(guān)閉一次)

    java代碼
    publicclass ItemManager{
    privateItemDaoitemDao;
    publicvoidsetItemDao(ItemDaoitemDao){this.itemDao=itemDao;}
    publicBidloadItemById(Longid){
    itemDao.loadItemById(id);
    }
    publicCollectionlistAllItems(){
    returnitemDao.findAll();
    }
    publicBidplaceBid(Itemitem,Userbidder,MonetaryAmountbidAmount,
    BidcurrentMaxBid,BidcurrentMinBid)throwsBusinessException{
    if(currentMaxBid!=null&&currentMaxBid.getAmount().compareTo(bidAmount)>0){
    thrownewBusinessException("Bid too low.");
    }

    //Auctionisactive
    if(!state.equals(ItemState.ACTIVE))
    thrownewBusinessException("Auction is not active yet.");

    //Auctionstillvalid
    if(item.getEndDate().before(newDate()))
    thrownewBusinessException("Can't place new bid, auction already ended.");

    //CreatenewBid
    BidnewBid=newBid(bidAmount,item,bidder);

    //PlacebidforthisItem
    item.getBids().add(newBid);
    itemDao.update(item);// 調(diào)用DAO完成持久化操作
    returnnewBid;
    }
    }

    事務(wù)的管理是在ItemManger這一層完成的,ItemManager實(shí)現(xiàn)具體的業(yè)務(wù)邏輯。除了常見的和CRUD有關(guān)的簡單邏輯之外,這里還有一個placeBid的邏輯,即項(xiàng)目的競標(biāo)。

    以上是一個完整的第一種模型的示例代碼。在這個示例中,placeBid,loadItemById,findAll等等業(yè)務(wù)邏輯統(tǒng)統(tǒng)放在ItemManager中實(shí)現(xiàn),而Item只有g(shù)etter/setter方法。





    第二種模型,也就是Martin Fowler指的rich domain object是下面這樣子的:

    一個帶有業(yè)務(wù)邏輯的實(shí)體類,即domain object是Item
    一個DAO接口ItemDao
    一個DAO實(shí)現(xiàn)ItemDaoHibernateImpl
    一個業(yè)務(wù)邏輯對象ItemManager

    java代碼
    publicclass ItemimplementsSerializable{
    // 所有的屬性和getter/setter方法同上,省略
    publicBidplaceBid(Userbidder,MonetaryAmountbidAmount,
    BidcurrentMaxBid,BidcurrentMinBid)
    throwsBusinessException{

    //Checkhighestbid(canalsobeadifferentStrategy(pattern))
    if(currentMaxBid!=null&&currentMaxBid.getAmount().compareTo(bidAmount)>0){
    thrownewBusinessException("Bid too low.");
    }

    //Auctionisactive
    if(!state.equals(ItemState.ACTIVE))
    thrownewBusinessException("Auction is not active yet.");

    //Auctionstillvalid
    if(this.getEndDate().before(newDate()))
    thrownewBusinessException("Can't place new bid, auction already ended.");

    //CreatenewBid
    BidnewBid=newBid(bidAmount,this,bidder);

    //PlacebidforthisItem
    this.getBids.add(newBid);// 請注意這一句,透明的進(jìn)行了持久化,但是不能在這里調(diào)用ItemDao,Item不能對ItemDao產(chǎn)生依賴!

    returnnewBid;
    }
    }

    競標(biāo)這個業(yè)務(wù)邏輯被放入到Item中來。請注意this.getBids.add(newBid); 如果沒有Hibernate或者JDO這種O/R Mapping的支持,我們是無法實(shí)現(xiàn)這種透明的持久化行為的。但是請注意,Item里面不能去調(diào)用ItemDAO,對ItemDAO產(chǎn)生依賴!

    ItemDao和ItemDaoHibernateImpl的代碼同上,省略。

    java代碼
    publicclass ItemManager{
    privateItemDaoitemDao;
    publicvoidsetItemDao(ItemDaoitemDao){this.itemDao=itemDao;}
    publicBidloadItemById(Longid){
    itemDao.loadItemById(id);
    }
    publicCollectionlistAllItems(){
    returnitemDao.findAll();
    }
    publicBidplaceBid(Itemitem,Userbidder,MonetaryAmountbidAmount,
    BidcurrentMaxBid,BidcurrentMinBid)throwsBusinessException{
    item.placeBid(bidder,bidAmount,currentMaxBid,currentMinBid);
    itemDao.update(item);// 必須顯式的調(diào)用DAO,保持持久化
    }
    }

    在第二種模型中,placeBid業(yè)務(wù)邏輯是放在Item中實(shí)現(xiàn)的,而loadItemById和findAll業(yè)務(wù)邏輯是放在ItemManager中實(shí)現(xiàn)的。不過值得注意的是,即使placeBid業(yè)務(wù)邏輯放在Item中,你仍然需要在ItemManager中簡單的封裝一層,以保證對placeBid業(yè)務(wù)邏輯進(jìn)行事務(wù)的管理和持久化的觸發(fā)。

    這種模型是Martin Fowler所指的真正的domain model。在這種模型中,有三個業(yè)務(wù)邏輯方法:placeBid,loadItemById和findAll,現(xiàn)在的問題是哪個邏輯應(yīng)該放在Item中,哪個邏輯應(yīng)該放在ItemManager中。在我們這個例子中,placeBid放在Item中(但是ItemManager也需要對它進(jìn)行簡單的封裝),loadItemById和findAll是放在ItemManager中的。

    切分的原則是什么呢? Rod Johnson提出原則是“case by case”,可重用度高的,和domain object狀態(tài)密切關(guān)聯(lián)的放在Item中,可重用度低的,和domain object狀態(tài)沒有密切關(guān)聯(lián)的放在ItemManager中。

    我提出的原則是:看業(yè)務(wù)方法是否顯式的依賴持久化。

    Item的placeBid這個業(yè)務(wù)邏輯方法沒有顯式的對持久化ItemDao接口產(chǎn)生依賴,所以要放在Item中。請注意,如果脫離了Hibernate這個持久化框架,Item這個domain object是可以進(jìn)行單元測試的,他不依賴于Hibernate的持久化機(jī)制。它是一個獨(dú)立的,可移植的,完整的,自包含的域?qū)ο?/span>。

    而loadItemById和findAll這兩個業(yè)務(wù)邏輯方法是必須顯式的對持久化ItemDao接口產(chǎn)生依賴,否則這個業(yè)務(wù)邏輯就無法完成。如果你要把這兩個方法放在Item中,那么Item就無法脫離Hibernate框架,無法在Hibernate框架之外獨(dú)立存在。



    第三種模型印象中好像是firebody或者是Archie提出的(也有可能不是,記不清楚了),簡單的來說,這種模型就是把第二種模型的domain object和business object合二為一了。所以ItemManager就不需要了,在這種模型下面,只有三個類,他們分別是:

    Item:包含了實(shí)體類信息,也包含了所有的業(yè)務(wù)邏輯
    ItemDao:持久化DAO接口類
    ItemDaoHibernateImpl:DAO接口的實(shí)現(xiàn)類

    由于ItemDao和ItemDaoHibernateImpl和上面完全相同,就省略了。

    java代碼
    publicclass ItemimplementsSerializable{
    // 所有的屬性和getter/setter方法都省略
    privatestaticItemDaoitemDao;
    publicvoidsetItemDao(ItemDaoitemDao){this.itemDao=itemDao;}

    publicstaticItemloadItemById(Longid){
    return(Item)itemDao.loadItemById(id);
    }
    publicstaticCollectionfindAll(){
    return(List)itemDao.findAll();
    }

    publicBidplaceBid(Userbidder,MonetaryAmountbidAmount,
    BidcurrentMaxBid,BidcurrentMinBid)
    throwsBusinessException{

    //Checkhighestbid(canalsobeadifferentStrategy(pattern))
    if(currentMaxBid!=null&&currentMaxBid.getAmount().compareTo(bidAmount)>0){
    thrownewBusinessException("Bid too low.");
    }

    //Auctionisactive
    if(!state.equals(ItemState.ACTIVE))
    thrownewBusinessException("Auction is not active yet.");

    //Auctionstillvalid
    if(this.getEndDate().before(newDate()))
    thrownewBusinessException("Can't place new bid, auction already ended.");

    //CreatenewBid
    BidnewBid=newBid(bidAmount,this,bidder);

    //PlacebidforthisItem
    this.addBid(newBid);
    itemDao.update(this);// 調(diào)用DAO進(jìn)行顯式持久化
    returnnewBid;
    }
    }

    在這種模型中,所有的業(yè)務(wù)邏輯全部都在Item中,事務(wù)管理也在Item中實(shí)現(xiàn)。

    posted on 2006-10-19 09:19 水煮三國 閱讀(513) 評論(2)  編輯  收藏 所屬分類: J2EE 、Hibernate

    FeedBack:
    # re: 總結(jié)一下最近關(guān)于domain object以及相關(guān)的討論 [From:JAVAEYE]
    2006-10-19 09:20 | 水煮三國
    在上面三種模型之外,還有很多這三種模型的變種,例如partech的模型就是把第二種模型中的DAO和Manager三個類合并為一個類后形成的模型;例如frain....(id很長記不住)的模型就是把第三種模型的三個類完全合并為一個單類后形成的模型;例如Archie是把第三種模型的Item又分出來一些純數(shù)據(jù)類(可能是,不確定)形成的一個模型。

    但是不管怎么變,基本模型歸納起來就是上面的三種模型,下面分別簡單評價一下:

    第一種模型絕大多數(shù)人都反對,因此反對理由我也不多講了。但遺憾的是,我觀察到的實(shí)際情形是,很多使用Hibernate的公司最后都是這種模型,這里面有很大的原因是很多公司的技術(shù)水平?jīng)]有達(dá)到這種層次,所以導(dǎo)致了這種貧血模型的出現(xiàn)。從這一點(diǎn)來說,Martin Fowler的批評聲音不是太響了,而是太弱了,還需要再繼續(xù)吶喊。

    第二種模型就是Martin Fowler一直主張的模型,實(shí)際上也是我一直在實(shí)際項(xiàng)目中采用這種模型。我沒有看過Martin的POEAA,之所以能夠自己摸索到這種模型,也是因?yàn)閺?2年我已經(jīng)開始思考這個問題并且尋求解決方案了,但是當(dāng)時沒有看到Hibernate,那時候做的一個小型項(xiàng)目我已經(jīng)按照這種模型來做了,但是由于沒有O/R Mapping的支持,寫到后來又不得不全部改成貧血的domain object,項(xiàng)目做完以后再繼續(xù)找,隨后就發(fā)現(xiàn)了Hibernate。當(dāng)然,現(xiàn)在很多人一開始就是用Hibernate做項(xiàng)目,沒有經(jīng)歷過我經(jīng)歷的那個階段。

    不過我覺得這種模型仍然不夠完美,因?yàn)槟氵€是需要一個業(yè)務(wù)邏輯層來封裝所有的domain logic,這顯得非常羅嗦,并且業(yè)務(wù)邏輯對象的接口也不夠穩(wěn)定。如果不考慮業(yè)務(wù)邏輯對象的重用性的話(業(yè)務(wù)邏輯對象的可重用性也不可能好),很多人干脆就去掉了xxxManager這一層,在Web層的Action代碼直接調(diào)用xxxDao,同時容器事務(wù)管理配置到Action這一層上來。Hibernate的caveatemptor就是這樣架構(gòu)的一個典型應(yīng)用。

    第三種模型是我很反對的一種模型,這種模型下面,Domain Object和DAO形成了雙向依賴關(guān)系,無法脫離框架測試,并且業(yè)務(wù)邏輯層的服務(wù)也和持久層對象的狀態(tài)耦合到了一起,會造成程序的高度的復(fù)雜性,很差的靈活性和糟糕的可維護(hù)性。也許將來技術(shù)進(jìn)步導(dǎo)致的O/R Mapping管理下的domain object發(fā)展到足夠的動態(tài)持久透明化的話,這種模型才會成為一個理想的選擇。就像O/R Mapping的流行使得第二種模型成為了可能(O/R Mapping流行以前,我們只能用第一種模型,第二種模型那時候是不現(xiàn)實(shí)的)。
      回復(fù)  更多評論
      
    # re: 總結(jié)一下最近關(guān)于domain object以及相關(guān)的討論 [From:JAVAEYE]
    2006-10-19 09:21 | 水煮三國
    總結(jié)的不錯!我也來湊個熱鬧吧,發(fā)發(fā)自己的觀點(diǎn)。

    Robbin總結(jié)的三點(diǎn)模型,我1、2用過,所味的第3點(diǎn)還無福消受啊

    一、關(guān)于第一種模型我在一個實(shí)際項(xiàng)目中做過這樣的設(shè)計,給我的感覺不是很好,主要有以下幾點(diǎn):
    《1》要寫太多的貧血類,其實(shí)可以做一個工具來自動生成,也不錯。
    《2》業(yè)務(wù)邏輯感覺不能很好的得到體現(xiàn),這樣增加了BussImp類的復(fù)雜度, 且許多操作是不應(yīng)該由BussImp來承擔(dān), 但也有個好處那就是設(shè)計相對的容易些
    《3》這不是OO的正統(tǒng)設(shè)計,這是受Boost的影響
    二、至于第二種模型是我一直都在用的,這種模型對設(shè)計人員的要求相對的要高,為什么?那是因?yàn)閷?ItemClass 要比以前更難以把握,其實(shí)設(shè)計就是歸類,但就是這個歸類就不那么的簡單,且每個人都有自己的歸類方法,很難形成統(tǒng)一。
      回復(fù)  更多評論
      
    <2006年10月>
    24252627282930
    1234567
    891011121314
    15161718192021
    22232425262728
    2930311234

    常用鏈接

    留言簿(4)

    隨筆分類(85)

    隨筆檔案(89)

    文章分類(14)

    文章檔案(42)

    收藏夾(37)

    java

    oracle

    Sybase

    搜索

    •  

    積分與排名

    • 積分 - 210785
    • 排名 - 266

    最新評論

    閱讀排行榜

    評論排行榜

    主站蜘蛛池模板: 亚洲精品无码久久久久去q | 国产AV日韩A∨亚洲AV电影| 亚洲精品亚洲人成在线观看| 成人免费视频小说| 天天影院成人免费观看| 9i9精品国产免费久久| 国产精品亚洲片在线花蝴蝶| 亚洲黄色免费电影| 亚洲精品乱码久久久久久 | 视频免费1区二区三区| 中文字幕亚洲男人的天堂网络 | 亚欧国产一级在线免费| 久久精品亚洲日本波多野结衣| 亚洲国产成a人v在线| 久久精品国产亚洲AV麻豆王友容 | 猫咪免费观看人成网站在线| 77777午夜亚洲| 亚洲一区二区三区四区视频 | 久久精品视频免费播放| 黄色网址免费在线观看| 免费精品国自产拍在线播放| 亚洲爆乳AAA无码专区| 亚洲欧美中文日韩视频| 99精品全国免费观看视频..| 特级aaaaaaaaa毛片免费视频| 亚洲精品国产综合久久久久紧| 亚洲六月丁香六月婷婷色伊人| 亚洲欧洲日产专区| 亚洲国产精品日韩专区AV| 国产va在线观看免费| 久久精品免费网站网| 黄色网址免费在线观看| 中文字幕免费在线看线人动作大片 | 亚洲视频手机在线| 91在线精品亚洲一区二区| 亚洲视频在线观看| 精品无码一区二区三区亚洲桃色 | 三年在线观看免费观看完整版中文| 一级黄色免费网站| 成全视成人免费观看在线看 | 亚洲av色影在线|