浏览 2999 次
锁定老帖子 主题:let's placeBid
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
|
|
---|---|
作者 | 正文 |
发表时间:2008-05-12
这个Domain可以简化为这样: public class Item { private Set<Bid> bids = new HashSet<Bid>(); } public class Bid { private User bidder; private int amount; } 现在我们要添加一个行为叫placeBid。于是我们可以写出如下的贫血代码: Bid currentMaxBid = itemDAO.getMaxBid(itemId); Item item = itemDAO.findById(itemId, true); if (currentMaxBid != null && bidAmount <= currentMaxBid.getAmount()) { throw new BizException("Bid too low."); } Bid newBid = new Bid(this, bidder, bidAmount); item.getBids().add(bid); itemDao.save(item); 这样的代码有什么问题吗?我觉得在没有更多的需求,系统规模不大的情况下,无法拿出有力的证据证明这样做的缺陷。那么我们再来看看如何用经典的Hibernate做法来做领域模型(参见robbin的第二种模型): public class Item { public Bid placeBid(User bidder, int bidAmount, Bid currentMaxBid) { if (currentMaxBid != null && bidAmount <= currentMaxBid.getAmount()) { throw new BizException("Bid too low."); } Bid newBid = new Bid(this, bidder, bidAmount); bids.add(newBid); return newBid; } } 在那篇老帖子(我知道,n年前了)中,七彩狼提出了一个问题,就是: 引用 第三类DomainLogic,也就是需要依赖到复杂查询的Logic 那需要这样的逻辑的是什么?远在天边,近在眼前。currentMaxBid哪来的?不还是从DAO中取出来的嘛。我Item包含了自己的bids,它居然没有办法知道maxBid是什么,还需要从外边用参数传进来。这是不合理的,但是却是不得已的。Hibernate的经典解决方案制约我们必须把这样的查询逻辑放在Domain的使用者那一边中调用DAO来完成。如果改用(http://www.iteye.com/topic/191261)我说的RichSet,就可以轻松解决: public class Item { private RichSet<Bid> bids = new DefaultRichSet<Bid>(); public Bid placeBid(User bidder, int bidAmount) { Bid currentMaxBid = bids.max("amount"); if (currentMaxBid != null && bidAmount <= currentMaxBid.getAmount()) { throw new BizException("Bid too low."); } Bid newBid = new Bid(this, bidder, bidAmount); bids.add(newBid); return newBid; } } max在缺省情况下的实现是遍历列表。在Hibernate增强之后就变成了SQL查询。类似于bids.add在缺省情况是列表操作,Hibernate存储的时候变成了SQL的INSERT。 我的观点是,所谓的大批量操作不属于Domain Logic是由于Hibernate造成的限制。实际情况中,Domain中应该有一个叫Repository的对象。它封装了一个List。 public class ItemRepository { private RichList<Item> items public ItemRepository(RichList<Item> items) { this.items = items; } } 作为领域对象的ItemRepository,它是不关心items是从哪里来的。它就认为这个items是domain中的所有的item。于是,addItem的item没名字不重复的校验就可以自然的放在ItemRepository上。 public class ItemRepository { public void addItem(String name) { if (items.find("name").eq(name).size() > 0) { throw new BizException("name duplicated"); } Item item = new Item(name); items.add(item); return item; } } 在Domain中,所有的Item列表,都应该经过ItemRepository包装。从而保证Item的名字唯一性。 声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
|
|
返回顶楼 | |
发表时间:2008-05-17
这样一个好贴怎么没有顶起来!
Repository存在是必要的! domain model本身是有状态的,由于生命周期的关系,一些model的生命周期依附于另一些model. 据此,我们把Domain Model分级:一级对象,二级对象甚至三级对象,其中三级对象依附于二级对象,二级对象依附于一级对象. 二级和三级对象可以利用RichSet访问并处理一些逻辑,但一级对象就必须通过Repository来控制! |
|
返回顶楼 | |
发表时间:2008-05-19
yimlin 写道 这样一个好贴怎么没有顶起来!
Repository存在是必要的!domain model本身是有状态的,由于生命周期的关系,一些model的生命周期依附于另一些model. 据此,我们把Domain Model分级:一级对象,二级对象甚至三级对象,其中三级对象依附于二级对象,二级对象依附于一级对象. 二级和三级对象可以利用RichSet访问并处理一些逻辑,但一级对象就必须通过Repository来控制! Repository同DAO有区别么? 看了半天也没看出RichSet有多少实质的好处。查找对象往往是会跨越多个对象关系的,这种东东实在看不出有多少实用价值。 要找到最近的bid需要那么费劲么? public class Item { private Bid currentMaxBid; private Set<Bid> bids = new HashSet<Bid>(); } |
|
返回顶楼 | |