论坛首页 Java企业应用论坛

Hibernate实体类 == 领域模型 ?

浏览 24153 次
该帖已经被评为精华帖
作者 正文
   发表时间:2005-03-21  
自从Martin Fowler的DDD提出来之后,无数的人就开始非议ORM方式下的持久化实体类,抨击这种方式下的实体类是“贫血”的,缺乏丰富业务语义的。其实他们都犯了一个最基本的逻辑错误 - 偷换概念。

概念是如何被偷换的呢?请注意,领域模型(Domain Model)是一个商业建模范畴的概念,他和软件开发并无一丝一毫的关系,即使一个企业他不开发软件,他也具备他的业务模型,所有的同行业的企业他们的业务模型必定有非常大的共性和内在的规律性,由这个行业内的各个企业的业务模型再向上抽象出来整个行业的业务模型,这个东西即“领域模型”。一个掌握了行业领域模型的软件公司,根本不需要再给人家开发项目了,根本不需要靠软件开发养活自己了,你光给这个行业的企业提供业务咨询已经赚得非常丰厚的利润了。以我现在兼职所在的公司来说,就是这样一家软件公司,在行业内积累了足够的领域模型,成立了一个专门的咨询部门,这个部门下面都是咨询师,他们是不管软件开发的,也不懂软件开发,他们就专门教这个行业的客户,教他们怎么去做自己的业务,他们比客户还精通客户的业务,光是业务咨询已经可以为公司带来很多的收入。

而软件开发呢?一个并没有行业经验积累的软件公司,它开发的软件,基本上完全是需求驱动,而不是领域模型驱动。只有具备了领域模型积累的公司才有资格去谈领域模型驱动软件开发。在由领域模型往某种编程语言如Java上来实现的时候,绝对不会是1:1的对应关系,即使是粗颗粒度的EJB2模型都做不到,更不要说更加强调细颗粒度的POJO模型呢?用面向对象的语言如Java来编写一个领域模型,如果是用EJB2模型,你需要使用最少两个以上的EJB,即一个 Session Bean,处理面向流程的控制逻辑,一个Entity Bean,处理面向持久化的实体逻辑(持久化操作附着在Entity Bean的Home接口上)。如果是更加复杂的领域模型,那么你需要更多的EJB,也许是一个领域模型需要多个Entity Bean和多个Session Bean。现在我们使用基于POJO模型的实现,那么粗颗粒度的EJB还要继续细分:一个Entity Bean要剥离出来至少三个以上的POJO,即一个或者多个实体类,一个或者多个DAO接口类,一个或者多个DAO接口实现类;一个Session Bean要切分为多个业务Bean。

由此我们终于看出来概念是怎样被偷换的了,一个商业概念的抽象领域模型被一个Java持久化实体类替代了。但是我们应该看到,Martin批评的贫血的领域模型并不是Hibernate实体类,Martin指的贫血的领域模型实际上是缺乏丰富业务逻辑概念的领域抽象模型,这和Hibernate实体类完全是风牛马不相及的东西。而Hibernate实体类只是具体编码过程中,为了实现一个领域模型而编写的一组基于POJO的对象中的,完成领域模型某个特征的类。而这个领域模型完整的特征并不应该,也不可能由一个非常粗颗粒度的单类完成,而是由一组互相协作的类完成:即Hibernate的实体类保持领域模型的状态;DAO接口实现类完成领域模型的持久化操作;Spring Bean类完成领域模型的逻辑控制功能。
   发表时间:2005-03-21  
I don't know why this anti-pattern is so common. I suspect it's due to many people who haven't really worked with a proper domain model, particularly if they come from a data background. Some technologies encourage it; such as J2EE's Entity Beans which is one of the reasons I prefer POJO domain models.
http://www.martinfowler.com/bliki/AnemicDomainModel.html

那怎么理解这句话里的POJO domain models?
0 请登录后投票
   发表时间:2005-03-21  
很赞同“商业概念的抽象领域模型”的概念。概念搞清楚固然重要,不过,这些“商业概念的抽象领域模型”在我们的应用开发中处在一个什么层次中呢,如何表现呢?在使用hibernate的系统中,这些“商业概念的抽象领域模型”不是通过hibernate的实体类表现出来的么,如果不是,那么用什么其他表现手段合适呢。
0 请登录后投票
   发表时间:2005-03-21  
Archie 写道
I don't know why this anti-pattern is so common. I suspect it's due to many people who haven't really worked with a proper domain model, particularly if they come from a data background. Some technologies encourage it; such as J2EE's Entity Beans which is one of the reasons I prefer POJO domain models.
http://www.martinfowler.com/bliki/AnemicDomainModel.html

那怎么理解这句话里的POJO domain models?


POJO指的就是非EJB那种重量级,高侵入性的组件模型,关于POJO的定义,你同样可以在Martin Fowler的bliki上面找到。

Spring的Bean是不是POJO? 是的!
Hibernate的entity是不是POJO?是的!
DAO接口是不是POJO?是的!
EJB是不是POJO? 不是的!

我没有看过Martin的DDD,我按照自己的理解, POJO domain models指的就是轻量级的领域模型。何为轻量级? 把领域模型的各个特征,各个属性,各个逻辑都塞到一个class里面叫做轻量级吗?

我认为,Martin批评的贫血的领域模型是指只关注了领域模型持久化特征方面,而忽略了领域模型其他特征方面的模型,这样的模型是贫血的。因为这种模型只关注了模型在技术层面的外在表现,也就是说只关注了数据的存取操作,而忽视了模型蕴含的业务核心价值。

举例来说,我们编一个银行软件,如果你只关注了账户的增删改查,这叫做贫血!而实际上你应该关注的是账户的业务特征,而不是数据特征,你应该关注的是账号开立的业务,账户注销的业务,账号过户的业务等等,这才是领域模型。这种领域模型在一个单纯的技术实现层面来说,对于最简单的业务,你可能只是Account类的增删改查,但是对于复杂的业务来说,他就不单但是一个类,一个表的简单操作了,例如开立账户,你要收手续费,以及考察个人财务状况,那么此时你需要的就是一组协作的类。

Martin提到领域模型,意在强调我们应该关注软件的业务,关注行业知识的内在规律,并且把这种规律建模为领域模型,批评拿到一个软件,脑子里面光想到数据库增删改查的人。这和我们的Hibernate持久化类毫无关系!

我的看法是:一个抽象的领域模型具备多方面的特征,你需要用一组互相协作的类来完成它,每一个或者一组类承担这个领域模型的某个特征。例如某个领域模型,例如上面的账户,你需要一组Hibernate持久化类:包括Account类,User类,Finance类,一组SpringBean类,AccountManager,FinanceManager,一组DAO接口和实现类。由这些POJO的类互相协作来共同完成这个领域模型。如果你仅仅关注Account的增删改查,那就贫血了,而如果你关注了账户的业务规则,并且考虑一组互相协作的类去完成它,就不是贫血的。
2 请登录后投票
   发表时间:2005-03-21  
eway 写道
很赞同“商业概念的抽象领域模型”的概念。概念搞清楚固然重要,不过,这些“商业概念的抽象领域模型”在我们的应用开发中处在一个什么层次中呢,如何表现呢?在使用hibernate的系统中,这些“商业概念的抽象领域模型”不是通过hibernate的实体类表现出来的么,如果不是,那么用什么其他表现手段合适呢。


我上面已经重点强调过了,这种商业概念的抽象领域模型是独立于软件开发体系之外的,你就算不开发软件,你也可以并且需要去抽象你的领域模型。

具体到软件开发活动,你应该由领域模型来驱动你的软件内在规则,由需求驱动你的软件外在交互。

这个领域模型的代码实现我上面也强调过了你需要用一组互相协作的类来完成它,每一个或者一组类承担这个领域模型的某个特征。而Hibernate的实体类只不过是其中的一组类,它承担的职责就是保持领域模型的状态的。
0 请登录后投票
   发表时间:2005-03-21  
我觉得Martin所说的AnemicDomainModel和Robbin说的不是同一个DomainModel。看看Martin对AnemicDomainModel的定义:
The basic symptom of an Anemic Domain Model is that at first blush it looks like the real thing. There are objects, many named after the nouns in the domain space, and these objects are connected with the rich relationships and structure that true domain models have.

显然是把Robbin说的DomainModel直接映射成ObjectModel的结果。
0 请登录后投票
   发表时间:2005-03-21  
Martin Fowler提出Domain Model的本意就是希望能提升业务领域模型的重用性,也就可知Domain Model是针对业务而抽象产生的模型,此模型和数据源层的持久模型并不一定完全相同,Domain Model中关注的层面更多的是业务方面,Domain Model由Domain Object构成,Domain Object共同协作完成业务逻辑的处理,觉得概念上而言Hibernate的实体类并不等同于Domain Model中的Domain Object,但由于很多应用的业务逻辑几乎是没有,在此时Hibernate的实体类同时也就可以充当Domain Object,觉得这也是为什么两者容易搞混的原因吧!
1 请登录后投票
   发表时间:2005-03-21  
同意楼主的观点,不过认为没必要那么严格,Spring Bean类就可以看作领域模型了.模糊一点说,80%的模型都在这里面吧.傻一点说来,领域模型一定要DAO和ORM进行操作吗?
0 请登录后投票
   发表时间:2005-03-21  
robbin 写道

概念是如何被偷换的呢?请注意,领域模型(Domain Model)是一个商业建模范畴的概念,他和软件开发并无一丝一毫的关系,即使一个企业他不开发软件,他也具备他的业务模型,所有的同行业的企业他们的业务模型必定有非常大的共性和内在的规律性,由这个行业内的各个企业的业务模型再向上抽象出来整个行业的业务模型,这个东西即“领域模型”。一个掌握了行业领域模型的软件公司,根本不需要再给人家开发项目了,根本不需要靠软件开发养活自己了,你光给这个行业的企业提供业务咨询已经赚得非常丰厚的利润了。以我现在兼职所在的公司来说,就是这样一家软件公司,在行业内积累了足够的领域模型,成立了一个专门的咨询部门,这个部门下面都是咨询师,他们是不管软件开发的,也不懂软件开发,他们就专门教这个行业的客户,教他们怎么去做自己的业务,他们比客户还精通客户的业务,光是业务咨询已经可以为公司带来很多的收入。

这实际上是因为术语的不同定义和理解导致的问题。
Martin Fowler提到的Domain Model并不是你这里所说的概念。
你所说的概念是RUP的概念,领域模型是作为业务建模的简化版本来定义的。
想想看,Martin Fowler是把TransactionScript,TableModule,DomainModel三者是放在并列的位置讨论的。用你的观点来解释能解释得通吗?
下面是martin Fowler认为 贫血的DomainModel的问题所在。
The fundamental horror of this anti-pattern is that it's so contrary to the basic idea of object-oriented design; which is to combine data and process together. The anemic domain model is really just a procedural style design, exactly the kind of thing that object bigots like me (and Eric) have been fighting since our early days in Smalltalk. What's worse, many people think that anemic objects are real objects, and thus completely miss the point of what object-oriented design is all about.

数据与行为分离,违反OO封装的基本原理。我想这是最明显不过了。
1 请登录后投票
   发表时间:2005-03-21  
举一个简单的例子吧
比如Order类,每个Order有好些Item
按照Hibernate实体类是这样

public class Order {
...
   public void setItems(Collection items); {
      ...
   }
   public Collection getItems(); {
      return items;
   }
}

这样的话,添加item的逻辑写在Order外面,Order什么都没做,只是一个数据容器,当然是“贫血”的

而用domain 方式如下:
public class Order {
   public void addItem(Item item); {
      ...判断是否重复,重复则只增加数量等等逻辑
   }
   public Collection getItems(); ...
   public void removeItem(Item item); ...
}

这就好多了
0 请登录后投票
论坛首页 Java企业应用版

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