文档介绍:最近taowen同学连续发起了两起关于贫血模型和领域模型的讨论,引起了大家的广泛热烈的讨论,但是讨论(或者说是争论)的结果到底怎样,我想值得商榷。问题是大家对贫血模型和领域模型都有自己的看法,如果没有对此达到概念上的共识,那么讨论的结果应该可想而知,讨论的收获也是有的,至少知道了分歧的存在。为了使问题具有确定性,我想从一个简单例子着手,用我对贫血模型和领域模型的概念来分别实现例子。至于我的理解对与否,大家可以做评判,至少有个可以评判的标准在这。
一个例子
我要举的是一个银行转帐的例子,又是一个被用滥了的例子。但即使这个例子也不是自己想出来的,而是剽窃的<<POJOs in Action>>中的例子,原谅我可怜的想像力。当钱从一个帐户转到另一个帐户时,转帐的金额不能超过第一个帐户的存款余额,余额总数不能变,钱只是从一个账户流向另一个帐户,因此它们必须在一个事务内完成,每次事务成功完成都要记录此次转帐事务,这是所有的规则。
 
 
贫血模型
我们首先用贫血模型来实现。所谓贫血模型就是模型对象之间存在完整的关联(可能存在多余的关联),但是对象除了get和set方外外几乎就没有其它的方法,整个对象充当的就是一个数据容器,用C语言的话来说就是一个结构体,所有的业务方法都在一个无状态的Service类中实现,Service类仅仅包含一些行为。这是Java Web程序采用的最常用开发模型,你可能采用的就是这种方法,虽然可能不知道它有个&ldquo;贫血模型&rdquo;的称号,这要多亏Martin Flower(这个家伙惯会发明术语!)。
 
包结构
在讨论具体的实现之前,我们先来看来贫血模型的包结构,以便对此有个大概的了解。
 
贫血模型的实现一般包括如下包:
dao:负责持久化逻辑
model:包含数据对象,是service操纵的对象
service:放置所有的服务类,其中包含了所有的业务逻辑
facade:提供对UI层访问的入口
代码实现
先看model包的两个类,Account和TransferTransaction对象,分别代表帐户和一次转账事务。由于它们不包含业务逻辑,就是一个普通的Java Bean,下面的代码省略了get和set方法。
Java代码
public class Account {   
    private String accountId;   
    private BigDecimal balance;   
  
    public Account() {}   
    public Account(String accountId, BigDecimal balance) {   
         = accountId;   
         = balance;   
    }   
    // getter and setter ....   
  
}  
public class Account {
private String accountId;
private BigDecimal balance;
public Account() {}
public Account(String accountId, BigDecimal balance) {
= accountId;
= balance;
}
// getter and setter ....
}
 
Java代码
public class TransferTransaction {   
    private Date timestamp;   
    private String ountId;   
    private String ountId;   
    private BigDecimal amount;     
  
    public TransferTransaction() {}   
  
    public TransferTransaction(String ountId, String ountId, BigDecimal amount, Date timestamp) {   
         = ountId;   
         = ountId;