Domain Object(领域对象)模型包含对象属性的定义和操作对象属性的getter/setter 方法并包含了对象的行为(例如:就像一个完整的人,具有一些属性如姓名、性别、年龄等,还具有一些能力,如走路、吃饭、恋爱等,这样才是一个完整的对象), 但不包含依赖 Dao 层 (持久层) 的业务逻辑。这部分依赖于 Dao 层的业务逻辑将会放到Business Logic 层(业务逻辑层)中的服务类来实现,组合逻辑也由服务类负责。可以看出,贫血模型中的领域对象是不依赖于持久层的。代码架构层次结构是: Client-> Business Facade Service -> Business Logic Service(Business Logic Service 是依赖 Domain Object 的行为) -> Data Access Service
优点
层次结构清楚,各层之间单向依赖
对于只有少量业务逻辑的应用来说,使用起来非常自然
开发迅速,易于理解
缺点
无法良好的应对非常复杂逻辑和场景
充血模型
Domain Object(领域对象)模型包含对象属性的定义和操作对象属性的getter/setter 方法并包含了大多数相关的业务逻辑,也包含了依赖于持久层的业务逻辑,Business Logic 层是很薄的一层,仅仅简单封装少量业务逻辑以及控制事务、权限逻辑等,不和 DAO 层打交道。所以**,使用充血模型的领域对象是依赖于持久层的。代码架构层次结构是**: Client-> Business Facade Service -> Business Logic Service -> Domain Object -> Data Access Service
优点
更加符合 OO 的原则
Business Logic 层很薄,**符合单一职责,不像在贫血模型里面那样包含所有的业务逻辑太过沉重,**只充当 Facade 的角色,不和 DAO 打交道。
缺点
什么样的逻辑应该放在 Domain Object 中,什么样的业务逻辑应该放在 Business Logic 中,这是很含糊的。即使划分好了业务逻辑,由于分散在 Business Logic 和 Domain Object 层中,不能更好的分模块开发。熟悉业务逻辑的开发人员需要渗透到 Domain Logic 中去,而在 Domian Logic 又包含了持久化,对于开发者来说这十分混乱。
其次,因为 Business Logic 要控制事务并且为上层提供一个统一的服务调用入口点,它就必须把在 Domain Logic 里实现的业务逻辑全部重新包装一遍,完全属于重复劳动。
胀血模型
Domain Object(领域对象)模型包含对象属性的定义和操作对象属性的getter/setter 方法并包含了所有相关的的业务逻辑,也包含了不想关的其它应用逻辑(如授权、事务等)。胀血模型取消了 Business Logic 层 (业务逻辑层),只剩下 Domain Object 和 DAO 两层,在 Domain Object 的 Domain Logic 上面封装事务,授权逻辑等。
publicclassItemManager {
private ItemDao itemDao;
publicvoidsetItemDao(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 {
if (currentMaxBid != null && currentMaxBid.getAmount().compareTo(bidAmount) > 0) {
thrownewBusinessException("Bid too low.");
}
// Auction is active if ( !state.equals(ItemState.ACTIVE) )
thrownewBusinessException("Auction is not active yet.");
// Auction still valid if ( item.getEndDate().before( newDate() ) )
thrownewBusinessException("Can't place new bid, auction already ended.");
// Create new Bid BidnewBid=newBid(bidAmount, item, bidder);
// Place bid for this Item
item.getBids().add(newBid);
itemDao.update(item); // 调用 DAO 完成持久化操作 return newBid;
}
}
publicclassItemimplementsSerializable {
// 所有的属性和 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) {
thrownewBusinessException("Bid too low.");
}
// Auction is active if ( !state.equals(ItemState.ACTIVE) )
thrownewBusinessException("Auction is not active yet.");
// Auction still valid if ( this.getEndDate().before( newDate() ) )
thrownewBusinessException("Can't place new bid, auction already ended.");
// Create new Bid BidnewBid=newBid(bidAmount, this, bidder);
// Place bid for this Item this.getBids.add(newBid); // 请注意这一句,透明的进行了持久化,但是不能在这里调用 ItemDao,Item 不能对 ItemDao 产生依赖!return newBid;
}
}