论坛首页 Java企业应用论坛

总结一下最近关于domain object以及相关的讨论

浏览 206410 次
该帖已经被评为精华帖
作者 正文
   发表时间:2006-10-19  
沿着每篇帖子的思路,我还是比较同意robbin的观点,而且看的过程中,好几处我有了一些想法,突然发现下面的帖子robbin正好表达了几乎类似的观点,这不由让我激动不已。

robbin 写道
redlly 写道
如一个工资单包括基本工资、奖金、个人所得税三个字段。而最后的实际所得应该=基本工资+奖金-税。这个总收入属性是数据库表中没有的,而是在实际业务中产生的,是业务逻辑的需要,那么这个属性应不应该包含在domain object中?


这个总收入属性应该包含在domain object里面,但是domain object的这个总收入属性不必映射数据库。


对于这个总收入,我觉得不需要以属性的形式包含在domain object里面,更好的方式应该是domain object只提供一个获取总收入的方法,如下代码所示:
public class Wage {
  private float baseWage;
  private float prize;
  private float tax;
  
  // 以上属性的 getter/setter方法

  public float getFactIncome(){
    return baseWage + prize - tax;
  }
}


而且,我觉得这个方法最好的体现了domain logic,虽然它是这么的简单
0 请登录后投票
   发表时间:2006-10-19  
frankensteinlin 写道
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; 
    } 
}


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,保持持久化 
    } 
}


对于楼主的domain object 方案二(正如上面所写)提出几个问题:
首先这个placeBid太简单了 我先擅自加点需求(加入这些需求只是说明技术问题,合理与否希望大家不要追究):
1)当 item 是列表A中的产品 如果拥有者是nato成员国呢么只允许卖给NATO成员国,如果是军用品只能卖给不再黑名单的国家
2)当 item 的买方协议的类型和卖方协议的类型都是不相互冲突。
这样的话该如何处理?

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."); 
            /////////////////////////////////////////////////////////////////////
            if(item.isBelongListA()) {//是列表A中的产品这个列表何时从数据库取出??
                if (item.getOwner().getCountry().isNato()){  // owner 的country信息何时从列表中取出? 
                	// country是否在在nato列表中nato国家的列表何时从数据库中取得?
                   ............................	
                }

                if (item.isForArmy){
                   bidder.getCountry().isInblackList()   //何时从数据库中取得。。。。
                }
            }
            	
            	
            	
            /////////////////////////////////////////////////////////////////////
            // Create new Bid 
            Bid newBid = new Bid(bidAmount, this, bidder); 
    
            // Place bid for this Item 
            this.getBids.add(newBid);  // 请注意这一句,透明的进行了持久化,但是不能在这里调用ItemDao,Item不能对ItemDao产生依赖! 
    
            return newBid; 
    } 
}


上面的的需求和代码不一定正确但是意思就是想说明placeBid的时候还是需要很多对象的帮助才能完成任务,
这些对象的的属性哪里来?

    放在 ItemManager setXXXDao 然后全部取出来准备好 最后调用?
public class ItemManager { 
    private ItemDao itemDao; 
    public void setItemDao(ItemDao itemDao) { this.itemDao = itemDao;} 
    .....xxxDao
     public void setXXXDao(XXXDao XXXDao) { this.xxxDao = xxxDao;} 
   .....................
    public Bid placeBid(Item item, User bidder, MonetaryAmount bidAmount, 
                            Bid currentMaxBid, Bid currentMinBid) throws BusinessException { 
        。。。。。。。。。。。。。。。。。。。。。
        //把item全部装配好?                    	
        item.placeBid(bidder, bidAmount, currentMaxBid, currentMinBid); 
        itemDao.update(item);    // 必须显式的调用DAO,保持持久化 
    } 
}

   或者:
   	 public Item loadItemById(Long id) { 
        itemDao.loadItemById(id); // 把item的所有属性全部都取出来??
    } 
    
 

  
  要么就利用hibernate这样的orm工具能够非显式的从数据库调用bidder.getCountry()<lazy的话自动从数据库取>
  不过这样的话dao估计就没什么用了,直接用hibernate的session 得了 ,这样manager也没什么用了?
   
不知道楼主是否能给我在这点上解惑?


frankensteinlin 写道
实践的结构第二种方案似乎只能在业务很简单的情况下使用,就我前面列举的很多业务规则的例子,基本上可使用第二种方案是个灾难。(如果我没理解错的话)



对于这个问题,我觉得应该把竞标逻辑placeBid,分为两部分来分析和处理

一部分如判断出价是否大于当前最大出价、当前拍卖项目是否已经结束,等等,这部分是和本拍卖项目密切相关的,所以属于本domain logic;

而另一部分,如以上列举的{
1)当 item 是列表A中的产品 如果拥有者是nato成员国呢么只允许卖给NATO成员国,如果是军用品只能卖给不再黑名单的国家
2)当 item 的买方协议的类型和卖方协议的类型都是不相互冲突。
}这部分更多地属于拍卖规则,属于Business logic,所以不应该有拍卖项目item来维护。item中的domain logic 是稳定的,不易变化的,而这些拍卖规则是不稳定的,可能会经常调整的,我们不希望这些不稳定的因素渗入到稳定的domain中。

这样分解之后,由业务层进行拍卖规则的判断,通过判断之后,进入domain层处理,所以第二种模型丝毫不会产生难以支撑的问题

(个人见解,欢迎批评)
0 请登录后投票
   发表时间:2006-11-02  
看完了所有的帖子,一个感觉,没几个人读懂了poeaa的,同一个概念每个人理解的都不一样,真正理解了poeaa的人很少!
0 请登录后投票
   发表时间:2006-11-03  
MS偶这种初级人员只看不回
昨天也有朋友和我说起这个模型那个模型的
既然看到这里我也应该有发言的权利
第二种方式可能是得到更多认同的方案而第一种可能是现阶段应用最广的

Oh my god....一只小强跑到我的本本里了!!

我自己也是在使用第一种方案(落后时代很久了~)
不过我觉得第二种方案(不好意思我说不出那是什么模型,很久没学习了)“内嵌”的方法应该是只和自身相关的curd等,其它数据访问应该的放到dao(然后由manager包装)里来完成,事务是必须划分至manager的

对于zhuam说到的
引用
至于第二种模型是我一直都在用的,这种模型对设计人员的要求相对的要高,为什么?那是因为对 ItemClass 要比以前更难以把握,其实设计就是归类,但就是这个归类就不那么的简单,且每个人都有自己的归类方法,很难形成统一。
这里的“归类”应该就是指什么方法应该在item里而什么方法在manager层,我觉得只要是显式地与其它对象相关的内容都应该是manager层来处理



不好意思,新人民工,还没有上升到理论的高度~~
0 请登录后投票
   发表时间:2006-11-03  
sinosupe 写道
看完了所有的帖子,一个感觉,没几个人读懂了poeaa的,同一个概念每个人理解的都不一样,真正理解了poeaa的人很少!

强烈同意,
0 请登录后投票
   发表时间:2006-11-06  
   你的第二种方式离开了Hibernate,JDO这些框架就不行了,为什么还要觉得这种方式好呢,如果我用iBatis,又该如果选型呢?我觉得好的范式或法则,不应该太过依赖于具体的实现,否则就必须提出它的使用前提,毕竟很多应用是不适合用Hibernate的。
0 请登录后投票
   发表时间:2006-12-14  
如果使用 hibernate来实现第二种方式,
是不是以为者要大量的用级联持久化(cascade)?
0 请登录后投票
   发表时间:2006-12-14  
其实domain model中应该放什么样的逻辑在without ejb和pro spring中有很明显的阐述的,而且这两本书的观点显然是一致的,不过显然这个帖子里有很多人也描述了同样的观点,我也非常赞成这种观点,就是域模型之间的逻辑操作应该放在域模型之中,之前没有看这两本书的时候我也是这么做的,比如说购物车是一个域模型那结算购物车中商品的总价就应该放在购物车中进行,因为这时购物车中已经有商品对象,和其对应的个数,没有必要通过service了。 也就是说域模型之间的逻辑操作应该放在域模型中,其他业务操作应该在service中,这种域模型就是robbin所说的第二种模型吧。 我一时记不起来是在那两本书的哪一章哪一页了,有空我贴出来,大家去翻翻看
0 请登录后投票
   发表时间:2006-12-14  
一直有个问题不明白,就是有条件查询要怎么写.比如要查created在xxxx和yyyy之间的,在servie层和dao层都加相应的方法吗?
0 请登录后投票
   发表时间:2007-01-10  
请问采用第二种模式,是否必须使用vo了呢?
0 请登录后投票
论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics