该帖已经被评为精华帖
|
|
---|---|
作者 | 正文 |
发表时间:2007-04-03
Robin提到"
第二种模型的第二类变种就是干脆取消ItemManager,保留原来的Item,ItemDao,ItemDaoHibernateImpl这3个类。在这种情况下把事务控制前推至Web层的Action去控制,具体来说,就是直接对Action的execute()方法进行容器事务声明。" 我认为这样做非常不妥!! 当你的系统是一个分布式的应用及你的系统需要两种显示界面时,比如需要即支持form又需要支持web!! 这样做致导太多的重复代码,serivce方法应该是与case对应的。 还要记住一点,web层应该是一个很薄的层,你这样做就使得web层有具体的业务逻辑了!!! |
|
返回顶楼 | |
发表时间:2007-04-06
robbin 写道 第二种模型,也就是Martin Fowler指的rich domain object是下面这样子的:
一个带有业务逻辑的实体类,即domain object是Item 一个DAO接口ItemDao 一个DAO实现ItemDaoHibernateImpl 一个业务逻辑对象ItemManager 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的代码同上,省略。 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框架之外独立存在。 这样的model可以解决这个问题么? 假设我有一个订单表A,里面分别有三个货物发往三个不同的地方,我用另外一张表B记录这三个货物的状态。 A表里有一订单a,其B表对应的记录是ab1,ab2,ab2,当此三条记录任意一个变化的时候,检测其他记录的状态,并按照相应的逻辑改变a的状态。 不知道该如何写。 |
|
返回顶楼 | |
发表时间:2007-05-31
bonny 写道 robbin 写道 第二种模型,也就是Martin Fowler指的rich domain object是下面这样子的:
一个带有业务逻辑的实体类,即domain object是Item 一个DAO接口ItemDao 一个DAO实现ItemDaoHibernateImpl 一个业务逻辑对象ItemManager 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的代码同上,省略。 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框架之外独立存在。 这样的model可以解决这个问题么? 假设我有一个订单表A,里面分别有三个货物发往三个不同的地方,我用另外一张表B记录这三个货物的状态。 A表里有一订单a,其B表对应的记录是ab1,ab2,ab2,当此三条记录任意一个变化的时候,检测其他记录的状态,并按照相应的逻辑改变a的状态。 不知道该如何写。 当此三条记录任意一个变化的时候,由谁来触发检测其他记录的状态这个事件? |
|
返回顶楼 | |
发表时间:2007-06-10
看下来,确实很多人在讨论问题时,对于一个概念有不同的理解。在这里,我认为区分核心业务逻辑,服务逻辑的概念会更有利于问题的讨论。
一个相对比较复杂的的分层结构 Presentation ------------------- Application Service ------------------- Domain Service Domain Model ------------------- Persistence manager 在不同项目/产品,甚至在同一项目/产品,不同模块也可以有相应的调整。例如这个拍卖系统的例子,事实上ItemManager的职责并不属于业务逻辑层(不是Domain Service,当然更不是Domain Model),而应该属于Application Service。当Domain Model体现的业务逻辑复杂到一定程度时,Domain Service则用来协调不同Domain Model。而在拍卖系统的例子里,不存在Domain Service。 在我看来,CRUD是服务逻辑,而不是看做是业务逻辑,所以对于一个系统,可以没有业务逻辑,但不可没有服务逻辑。而对于复杂的业务系统,某个功能一定是服务逻辑+业务逻辑共同完成。 |
|
返回顶楼 | |