论坛首页 Java企业应用论坛

贫血的Domain Model

浏览 46159 次
该帖已经被评为精华帖
作者 正文
   发表时间:2008-05-11  
同意你的说法。使用内存数据库,然后再用spring给domain对象注入一个generic的DAO。我上文提到的解决方案,其实那个RichSet就是一个generic DAO。而注入是通过hibernate实现的。异曲同工而已。也同意你对于脱离数据库“可测试性”的质疑。我也没有明确的例证可以说明其优点。不过,通过RichSet的隔离,至少使用数据库和不使用数据库的选择,交在了你的手上,而不是被框架给限定住了。另外RoR的Fixture让数据库相关的测试变得容易。但是Java中缺乏相因的设施,使得结合数据库的测试显得相对冗长。
其实Persistent就不是一层。。。持久化也压根不是逻辑。它只是Domain的一种存在形式。Domain可以在内存中也可以在数据库中,也可以部分在内存中部分在数据库中。
0 请登录后投票
   发表时间:2008-05-11  
taowen 写道
同意你的说法。使用内存数据库,然后再用spring给domain对象注入一个generic的DAO。我上文提到的解决方案,其实那个RichSet就是一个generic DAO。而注入是通过hibernate实现的。异曲同工而已。也同意你对于脱离数据库“可测试性”的质疑。我也没有明确的例证可以说明其优点。不过,通过RichSet的隔离,至少使用数据库和不使用数据库的选择,交在了你的手上,而不是被框架给限定住了。另外RoR的Fixture让数据库相关的测试变得容易。但是Java中缺乏相因的设施,使得结合数据库的测试显得相对冗长。
其实Persistent就不是一层。。。持久化也压根不是逻辑。它只是Domain的一种存在形式。Domain可以在内存中也可以在数据库中,也可以部分在内存中部分在数据库中。

其实我是建议直接使用JPA,毕竟已经是java的标准设施。
另外理论上Persistent应该是透明(无业务逻辑),但目前技术情况下,其实很多的JPQL/HQL里面确实包含了不少的Domain逻辑的判定,Domain使用JPA也能尽量将这些逻辑收集到DomainModel的内部。
0 请登录后投票
   发表时间:2008-05-11  
JPQL和HQL就不是持久化逻辑。他们是查询逻辑。查询逻辑是典型的Domain Model应该关心的东西。
0 请登录后投票
   发表时间:2008-05-11  
taowen 写道
JPQL和HQL就不是持久化逻辑。他们是查询逻辑。查询逻辑是典型的Domain Model应该关心的东西。

呵呵,也是。
那就更需要在Domain中使用JPA了。
0 请登录后投票
   发表时间:2008-05-12  
我是不太赞同Java采用Rich Domain Model的,起码Java的框架做不到Rails的ActiveRecord那样简洁,这不仅仅是语法差异造成的,也和Rails的部署运行方式有紧密的关系。

1、Rails的进程运行模式是每个进程持有一个永久连接,一直不释放。

由于Rails不需要释放连接,所以不存在数据库连接资源的清理问题。但是Java的每个线程最终要释放数据库连接,所以必须精心的设计和编码,确保资源得到正确顺序的释放。但是一旦考虑到一个数据库连接的范围内,要跨多个domain model的方法调用进行数据库访问,那么你如何确定连接释放的顺序和时间点?起码你不可能在domain model的方法调用内部进行close了,必须依赖外部的容器管理,比方说依赖Spring提供的资源管理能力,由Spring来确认最后一个方法调用结束之后来帮助你关闭数据库连接。正因为Java的domain model摆脱不掉外在容器的依赖,所以他没有办法做到ActiveRecord那么简洁。

2、Rails的事务管理机制是很粗糙的,不像Java的事务管理那么精细

Rails默认情况下是单步提交的数据库事务,如果你希望跨多个model的事务,则必须手工写代码来管理。当然用Java也可以手工管理,但是对于已经适应了由容器来提供声明式事务管理的程序员来说,能够接受在Web层手工写丑陋的Transaction代码来管理事务的方式吗?

3、Rails没有IoC,但是有open class和mixin

因为ruby的open class和mixin,所以Rails没有IoC并不是什么问题,domain之间的调用不需要依赖外部容器,单元测试也不需要依赖外部容器,但是Java没有open class和mixin,所以必须强调接口编程和IoC容器管理,但这样一来,事情就复杂了,你背着一个容器编程,必须受到容器的制约。

因为以上的三个原因,Java要实现类似ActiveRecord的rich domain model,就面临比Ruby困难的多的问题,处处要背着一个IoC框架,而且这还意味着你的domain model也应该由IoC框架来创建,否则IoC框架无法给你注入依赖关系。所以这个IoC具有很强的传染性,你必须把所有的依赖关系全部放在IoC的控制之下。但是偏偏你用IoC去管理domain model,特别是prototype的model却是一件非常复杂和困难的事情,尤其Spring框架更是如此。

因此我个人不看好Java的rich domain model,尤其是当你不能摆脱Spring/Hibernate依赖的情况下,无法真正实现rich domain。所以我更希望看到Java领域出现一些新的框架或者思路出来,不要老是Spring/Hibernate那一套。或者可以这样说,正是Spring/Hibernate导致了Java领域贫血模型的出现,如果没有超越Spring/Hibernate(EJB3/JPA也一样)的Java框架出现,是不可能rich domain的。
2 请登录后投票
   发表时间:2008-05-12  
Configurable这个annotation需要多出很多aspectj的配置,运行起来也有点麻烦,是java目前在rich domain model这个问题上的权宜之计,不过如果真正实现起来对于前期的分析是很有好处的,只不过编码的时候有些麻烦
0 请登录后投票
   发表时间:2008-05-12  
To Robbin:
连接的获取和释放,和事务的管理是Service层的职责,无论Domain Model是贫血还是不贫血,都不会牵涉到连接和事务的管理。Service在使用Domain Model的时候,就要保证连接已经获得。事务可以用在Service层的方法上加Annotation,用AOP来织入实现的代码。
对于连接和事务的存在,使得在Java中必须存在Service层。这个是架构原因造成的,和Rich Domain Model无关。当然,由于Service层的存在,Java写的程序自然无法如RoR那么简洁了。所以我认同你的这个观点。确实,很多时候,Service层的代码写起来很无聊。但是为了管理事务和安全,又不得不有这么一层。

在我的方案中,Domain对象的注入不是由IoC容器来完成的。Domain对象的注入,其实是POJO->PO的过程。这个过程是由Hibernate完成的。Java的class虽然不是open的,但是也非完全closed。Hibernate用反射同样实现了Collection的增强。通过改写Hibernate增强POJO的过程,让Domain对象具有了查询自身Collection的能力。我认为具有了查询能力,Domain Model可以更加Rich。更重要的是,人们所担心的Domain对象变得复杂无比,与持久化代码发生纠缠的局面并没有出现。因为实现细节被RichSet,RichList这样的Collection API隔离了。甚至RoR更好,因为Domain对象可以脱离数据库构造出来做单元测试,完全不牵涉容器和数据库。
0 请登录后投票
   发表时间:2008-05-12  
Ashela 写道
Configurable这个annotation需要多出很多aspectj的配置,运行起来也有点麻烦,是java目前在rich domain model这个问题上的权宜之计,不过如果真正实现起来对于前期的分析是很有好处的,只不过编码的时候有些麻烦

其实我没有实践过这个option。希望有经验的人贡献一些实际的例子。不过我相信,增强Collection比注入DAO要更好(因为不依赖容器和数据库)。
0 请登录后投票
   发表时间:2008-05-12  
taowen 写道
To Robbin:
连接的获取和释放,和事务的管理是Service层的职责,无论Domain Model是贫血还是不贫血,都不会牵涉到连接和事务的管理。Service在使用Domain Model的时候,就要保证连接已经获得。事务可以用在Service层的方法上加Annotation,用AOP来织入实现的代码。
对于连接和事务的存在,使得在Java中必须存在Service层。这个是架构原因造成的,和Rich Domain Model无关。当然,由于Service层的存在,Java写的程序自然无法如RoR那么简洁了。所以我认同你的这个观点。确实,很多时候,Service层的代码写起来很无聊。但是为了管理事务和安全,又不得不有这么一层。

在我的方案中,Domain对象的注入不是由IoC容器来完成的。Domain对象的注入,其实是POJO->PO的过程。这个过程是由Hibernate完成的。Java的class虽然不是open的,但是也非完全closed。Hibernate用反射同样实现了Collection的增强。通过改写Hibernate增强POJO的过程,让Domain对象具有了查询自身Collection的能力。我认为具有了查询能力,Domain Model可以更加Rich。更重要的是,人们所担心的Domain对象变得复杂无比,与持久化代码发生纠缠的局面并没有出现。因为实现细节被RichSet,RichList这样的Collection API隔离了。甚至RoR更好,因为Domain对象可以脱离数据库构造出来做单元测试,完全不牵涉容器和数据库。


我原意是指抛弃Service层,不过下载你的代码看了单元测试以后,明白了。其实我希望看到的是消除Service层,否则Rich Domain Model的意义就被削弱很多了。因为最终你不得不在Service层针对domain logic再封装一层transaction script,这样Service层就显得颇为罗嗦。

而且更麻烦的是,会造成Web层的程序员的困扰。他明明看到domain model的逻辑是自洽的,却偏偏要搞清楚哪些logic不能直接调用,必须通过Service;哪些logic可以直接调用,不能通过Service,否则就会出错。与其这样,倒不如干脆把所有的逻辑剥离到Service层更直观了。

所以我的想法就是:如果不能够消除Service层的话,使用rich domain model没什么意义。



0 请登录后投票
   发表时间:2008-05-12  
抛弃Service层太难了。这个正如你所说,是Ruby和Java的WEB执行环境的差异造成的。连接的开关还好说,事务要加在Domain对象可真是不容易。不过不知道我的方案部分剞劂了贫血的问题不?是不是大家又开始觉得Domain对象缺的血是事务控制了?
但是我不大认同不能抛弃service层,实现Rich Domain Model就没有意义的说法。但是我也无法给出实际的例子来证明,在保持Service层情况下,实现Rich Domain Model的好处。我正在思考一个更具有实际背景的例子,来比较一下各种实现方式的差别。
另外你提及的Web层的Developer。是不是隐含的说,写web层的开发者不是写service层的开发者?至少在我们公司,是不存在这个区别的。如果都是一个人来写的话,把事务控制放在service层中,还是在web层中手写,那纯粹就是实现优劣的问题了,不牵涉团队协作问题。
0 请登录后投票
论坛首页 Java企业应用版

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