第二种模型,也就是Martin Fowler指的rich domain object是下面这样子的:一个带有业务逻辑的实体类,即domain object是Item 
一个DAO接口ItemDao 
一个DAO实现ItemDaoHibernateImpl 
一个业务逻辑对象ItemManager
java 代码
public class Item implements Serializable {   
    //  所有的属性和getter/setter方法同上,省略   
    public Bid placeBid(User bidder, MonetaryAmount bidAmount,   
                        Bid currentMaxBid, Bid currentMinBid)   
        throws BusinessException {   
       
        // Check highest bid (can also be a different Strategy (pattern))   
        if (currentMaxBid != null && currentMaxBid.getAmount().compareTo(bidAmount) > 0) {   
            throw new BusinessException("Bid too low.");   
        }   
       
        // Auction is active   
        if ( !state.equals(ItemState.ACTIVE) )   
            throw new BusinessException("Auction is not active yet.");   
       
        // Auction still valid   
        if ( this.getEndDate().before( new Date() ) )   
            throw new BusinessException("Can't place new bid, auction already ended.");   
       
        // Create new Bid   
        Bid newBid = new Bid(bidAmount, this, bidder);   
       
        // Place bid for this Item   
        this.getBids.add(newBid);  // 请注意这一句,透明的进行了持久化,但是不能在这里调用ItemDao,Item不能对ItemDao产生依赖!   
       
        return newBid;   
    }   
}  
竞标这个业务逻辑被放入到Item中来。请注意this.getBids.add(newBid); 如果没有Hibernate或者JDO这种O/R Mapping的支持,我们是无法实现这种透明的持久化行为的。但是请注意,Item里面不能去调用ItemDAO,对ItemDAO产生依赖!ItemDao和ItemDaoHibernateImpl的代码同上,省略。
java 代码
public class ItemManager {    
    private ItemDao itemDao;    
    public void setItemDao(ItemDao itemDao) { this.itemDao = itemDao;}    
    public Bid loadItemById(Long id) {    
        itemDao.loadItemById(id);    
    }    
    public Collection listAllItems() {    
        return  itemDao.findAll();    
    }    
    public Bid placeBid(Item item, User bidder, MonetaryAmount bidAmount,    
                            Bid currentMaxBid, Bid currentMinBid) throws BusinessException {    
        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框架之外独立存在。

解决方案 »

  1.   

    第三种模型印象中好像是firebody或者是Archie提出的(也有可能不是,记不清楚了),简单的来说,这种模型就是把第二种模型的domain object和business object合二为一了。所以ItemManager就不需要了,在这种模型下面,只有三个类,他们分别是:Item:包含了实体类信息,也包含了所有的业务逻辑 
    ItemDao:持久化DAO接口类 
    ItemDaoHibernateImpl:DAO接口的实现类由于ItemDao和ItemDaoHibernateImpl和上面完全相同,就省略了。
    java 代码
    public class Item implements Serializable {   
        //  所有的属性和getter/setter方法都省略   
       private static ItemDao itemDao;   
        public void setItemDao(ItemDao itemDao) {this.itemDao = itemDao;}   
           
        public static Item loadItemById(Long id) {   
            return (Item) itemDao.loadItemById(id);   
        }   
        public static Collection findAll() {   
            return (List) itemDao.findAll();   
        }   
      
        public Bid placeBid(User bidder, MonetaryAmount bidAmount,   
                        Bid currentMaxBid, Bid currentMinBid)   
        throws BusinessException {   
           
            // Check highest bid (can also be a different Strategy (pattern))   
            if (currentMaxBid != null && currentMaxBid.getAmount().compareTo(bidAmount) > 0) {   
                throw new BusinessException("Bid too low.");   
            }   
               
            // Auction is active   
            if ( !state.equals(ItemState.ACTIVE) )   
                throw new BusinessException("Auction is not active yet.");   
               
            // Auction still valid   
            if ( this.getEndDate().before( new Date() ) )   
                throw new BusinessException("Can't place new bid, auction already ended.");   
               
            // Create new Bid   
            Bid newBid = new Bid(bidAmount, this, bidder);   
               
            // Place bid for this Item   
            this.addBid(newBid);   
            itemDao.update(this);      //  调用DAO进行显式持久化   
            return newBid;   
        }   
    }  
    在这种模型中,所有的业务逻辑全部都在Item中,事务管理也在Item中实现。
                                       
                         转于:http://www.javaeye.com/topic/11712