<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的討論中浮現出來了三種模型,(還有一些其他的旁枝,不一一分析了),經過一番討論,各種問題逐漸清晰起來,在這里我試圖做一個總結,便于大家了解和掌握。

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

    一個實體類叫做Item,指的是一個拍賣項目
    一個DAO接口類叫做ItemDao
    一個DAO接口實現類叫做ItemDaoHibernateImpl
    一個業務邏輯類叫做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完成具體的持久化工作,請注意,數據庫資源的獲取和釋放是在ItemDaoHibernateImpl里面處理的,每個DAO方法調用之前打開Session,DAO方法調用之后,關閉Session。(Session放在ThreadLocal中,保證一次調用只打開關閉一次)

    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);// 調用DAO完成持久化操作
    returnnewBid;
    }
    }

    事務的管理是在ItemManger這一層完成的,ItemManager實現具體的業務邏輯。除了常見的和CRUD有關的簡單邏輯之外,這里還有一個placeBid的邏輯,即項目的競標。

    以上是一個完整的第一種模型的示例代碼。在這個示例中,placeBid,loadItemById,findAll等等業務邏輯統統放在ItemManager中實現,而Item只有getter/setter方法。





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

    一個帶有業務邏輯的實體類,即domain object是Item
    一個DAO接口ItemDao
    一個DAO實現ItemDaoHibernateImpl
    一個業務邏輯對象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);// 請注意這一句,透明的進行了持久化,但是不能在這里調用ItemDao,Item不能對ItemDao產生依賴!

    returnnewBid;
    }
    }

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

    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);// 必須顯式的調用DAO,保持持久化
    }
    }

    在第二種模型中,placeBid業務邏輯是放在Item中實現的,而loadItemById和findAll業務邏輯是放在ItemManager中實現的。不過值得注意的是,即使placeBid業務邏輯放在Item中,你仍然需要在ItemManager中簡單的封裝一層,以保證對placeBid業務邏輯進行事務的管理和持久化的觸發。

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

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

    我提出的原則是:看業務方法是否顯式的依賴持久化。

    Item的placeBid這個業務邏輯方法沒有顯式的對持久化ItemDao接口產生依賴,所以要放在Item中。請注意,如果脫離了Hibernate這個持久化框架,Item這個domain object是可以進行單元測試的,他不依賴于Hibernate的持久化機制。它是一個獨立的,可移植的,完整的,自包含的域對象

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



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

    Item:包含了實體類信息,也包含了所有的業務邏輯
    ItemDao:持久化DAO接口類
    ItemDaoHibernateImpl:DAO接口的實現類

    由于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);// 調用DAO進行顯式持久化
    returnnewBid;
    }
    }

    在這種模型中,所有的業務邏輯全部都在Item中,事務管理也在Item中實現。

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

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

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

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

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

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

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

    Robbin總結的三點模型,我1、2用過,所味的第3點還無福消受啊

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

    常用鏈接

    留言簿(4)

    隨筆分類(85)

    隨筆檔案(89)

    文章分類(14)

    文章檔案(42)

    收藏夾(37)

    java

    oracle

    Sybase

    搜索

    •  

    積分與排名

    • 積分 - 210731
    • 排名 - 266

    最新評論

    閱讀排行榜

    評論排行榜

    主站蜘蛛池模板: 三年在线观看免费观看完整版中文| 在线看片免费人成视频播| 亚洲第一成年免费网站| 免费人人潮人人爽一区二区| 国产精品99久久免费观看| 免费观看男人免费桶女人视频| 亚洲AV成人精品日韩一区18p| 666精品国产精品亚洲 | 免费一级毛片在级播放| 亚洲AV无码久久| 亚洲av无码兔费综合| 91久久精品国产免费直播| 最新国产AV无码专区亚洲| 日本亚洲色大成网站www久久| 国产激情免费视频在线观看| 亚洲AV日韩AV永久无码下载| 色噜噜狠狠色综合免费视频 | 亚洲国产成人AV在线播放| 午夜免费福利网站| 色噜噜狠狠色综合免费视频| 久久久久久亚洲精品不卡| 亚洲AV永久无码天堂影院| 国产高清免费观看| 亚洲AV无码一区二区三区在线| 精品成人免费自拍视频| 亚洲片一区二区三区| 亚洲欧美第一成人网站7777| 99爱视频99爱在线观看免费| 久久久久久久尹人综合网亚洲| 曰批免费视频播放在线看片二| 久久久久亚洲精品男人的天堂| 免费观看成人久久网免费观看| 亚洲精品国产福利在线观看| 午夜精品一区二区三区免费视频| 亚洲一区精品无码| 五月婷婷免费视频| 亚洲人成色77777在线观看大| 久久这里只精品国产免费10| 亚洲天然素人无码专区| 好吊妞788免费视频播放| 国产成人精品亚洲2020|