关于领域模型

最近在逛http://forum.javaeye.com这个坛子,发现这里面的讨论氛围确实非常的好.虽然只是潜水,但是收获颇多.在此向博客园的各位兄弟强烈推荐.

广告完毕,话入正题.

对于领域模型这个概念,以前没有系统性的认识,只是根据经验,在设计系统时自发的在使用.尤其是O'R Mapping技术成熟并且逐渐成为主流以后,这种模型化的设计方法在项目应用中体现得非常之多.

http://forum.javaeye.com/viewtopic.php?t=17579

在JavaEye的这个帖子中,大牛robbin总结了4种常见的领域模型,并分析了它们的优缺点.
1、失血模型
2、贫血模型
Service(业务逻辑,事务封装) --> DAO ---> domain object
3、充血模型
Service(事务封装) ---> domain object <---> DAO
4、胀血模型
domain object(事务封装,业务逻辑) <---> DAO

其中失血模型与贫血模型的主要区别在于“domain ojbect包含了不依赖于持久化的领域逻辑,而那些依赖持久化的领域逻辑被分离到Service层”。 好理解点的表达就是:如果某个逻辑不依赖于DAO来实现,就把它放到domain object里面,否则就在Service层实现。

讨论的结果,robbin倾向于使用基于良好设计和实现技术下的贫血模型。

就我的经验而言,第一种模型是项目中使用最多的。

这是以前做过的一个Java项目,典型的失血模型,db->bean里面是按照模块划分的实体bean,也就是只含有getter和setter的domain ojbect。manager就是DAO,使用Hibernate做持久化。做业务逻辑和事务封装的Service封装在Action里面,使用Struts做MVC控制。
在使用里面,这种模型的domain ojbect和DAO实现基本都是靠工具来生成了。程序员可以更关注具体的Action实现。

另外,在最近的一个项目里面,我使用了一种比较畸形的设计模型,
domain ojbect的实现:

Domain Object示例


这个是靠工具实现的实体类的代码,其中使用的Attribute是由于我使用的持久化实现不是从配置文件而是通过反射从元数据中读取的。
DAO实现:

这其实是个通用的DAO类,只是实现了通用的ADSU方法,外加一个RunSql实现。没有设计针对具体的domain ojbect 实现具体业务逻辑的Service Objects,而是把剩下的事情,交给客户(web层代码消费者)了。
先别骂我,先看看这样的设计,是基于一种什么背景:
1、这是个所谓的web2.0网站,需要以半天为周期的进行系统更新与功能升级。
2、底层的基本数据结构不会发生变化。
3、在系统升级过程中,需要尽可能多的减少升级时间成本。
4、开发团队人员很少(1-2人),web层开发人员本身就参与底层库编码,因此,向web层开发人员隐藏底层对象没有意义。
5、新的用户功能是难以在设计时考虑周全的,甚至可能是每天都有增加或者变更。
个人认为在这种情况下,这种设计模型基本可以满足项目的需要了。需要注意的是:DAO和domain ojbect,都是独立的编译单元,在系统更新时,是无需考虑它们的。


结合我的项目经验,在认真读了JavaEye上的讨论之后,我感觉有些地方也有一些其它思路:

所有这些设计中,可能胀血模型是最符合OO的了。但是胀血模型应该也是实现成本最高,风险最大的一个模型。原因很简单,domain ojbect模型的不稳定带来的成本会非常痛苦。
因此,一个项目设计的好坏,是否不应该单纯看其设计思路是否符合OO原则,而应该考虑这个设计给项目带来的整体实施成本。相比之下,失血模型和贫血模型的domain ojbect层非常稳定(基本可以使用工具生成了),而且编写相对很简单,复杂的业务逻辑交给Service去实现,大家分工明确,不同编码水平的coder可以很好的配合起来,完成项目的高质量实现。而胀血模型中,对domain ojbect的编写显得非常重要,因为domain ojbect本身就包含了事务封装和业务逻辑。
另外大胆说一句,是否OO有时并不取决于我们的设计,而是要受技术条件的限制的。假设数据库本身可以提供的不是关系型数据而是对象集,假如我们不需要DAO编码,设计本身,会更加漂亮。

以上是我的一些体会和思考,记录下来。

另外向诸位交流几个问题:
1、在DAO实现中,有没有在DAO接口与DAO实现设计方面比较有经验的兄弟,介绍一下这样设计的好处?
我在项目中基本没有过DAO接口设计的经验,都是直接做实现,虽然使用接口可以使系统不依赖于某种具体的持久化实现方法,但是目前为止,还没有遇到过需要在项目中做更换持久化方法这种大手术的情况。况且额外增加一个接口层,还是蛮麻烦的。

2、在.net里面,大家常用的持久化工具有哪些?除了NHibernate?


posted @ 2006-04-07 10:13 Joey Yin 阅读(2735) 评论(8)  编辑 收藏 网摘

  回复  引用  查看    
#1楼2006-04-07 10:45 | Cure      
javaeye确实不错,先去学习学习楼主说的4种模型。
  回复  引用  查看    
#2楼[楼主]2006-04-07 10:49 | Joey Young      
@Cure:
其实这4种模型中的一种甚至多种,我们在开发中已经在经常自觉不自觉地使用了。所以说牛人之所以牛,是因为它们善于总结,把习惯型行为归纳为经验和条款。便于日后对设计经验的复用,呵呵,这点,我是只有佩服的份儿了。
经常写写blog的好处,也是帮助自己总结吧。。


  回复  引用  查看    
#3楼2006-04-07 14:19 | 小陆      
业务模型是从客户的业务中总结出来的,对应业务概念。业务模型的建立只能依靠人的头脑分析,需要和客户反复讨论,绝不可能自动生成的。如果一段代码可以用工具自动产生,那么他肯定不是domain object。如果硬要把这样的代码当作domain object,这样的domain object肯定丧失了很多业务含义。所丧失的含义肯定要在其他的某个位置补偿回来,于是这些业务就会分散到用户界面中。
  回复  引用  查看    
#4楼[楼主]2006-04-07 14:48 | Joey Young      
@小陆:

我认为这主要取决于我们看待domain object的角度。我理解你的意思,应该是比较支持胀血模型的设计思想.的确从语义的角度,domain object不能仅仅包括对业务对象的静态描述,还应该包括业务对象的行为描述,但是实际操作中,这种模型很难得到较好的实现.所以我的核心体会就是:应该选择最适合这个项目的设计模型,而不是理论上最"美"的模型.

不知道对你的意思理解有没有偏差,感谢你的留言,希望能与你继续探讨.


  回复  引用  查看    
#5楼2006-04-07 15:06 | 深渊野鱼      
DAO多体现于SOA模式。

  回复  引用    
#6楼2006-04-07 16:33 | 洗刷刷[未注册用户]
这个概念太理想化了,实际上基本上做到,domain的作用就是想把业务逻辑和操作数据的逻辑合到一起,表达一个 业务对象->业务数据对象 的目的,只有3,4算得上领域模型,1,2只是提出者为了更好的解释领域模型而凑上去的
  回复  引用  查看    
#7楼[楼主]2006-04-11 09:57 | Joey Young      
贫血模型理论上的主要缺陷:

1:Item和ItemManager实际是操作与数据的关系,实际完成的就是经典OO中的一个对象的能力;
2:当有许多Item时 类组变得很庞大,产生很多 xxxDao xxxImpl xxxManager 其中包含大量重复代码;
按<<重构>>的观点,上述代码存在以下臭味:
1:重复的代码 xxxDao xxxImpl xxxManager(通常)
2:霰弹式修改,一个变化影响多个类,类之间不够高内聚 item变化-->Dao,Impl,Manager均要变动
3:依恋情结,两个类之间互相作用过多 item<->Manager
4:平行继承体系,当增加一个新类时总是要增加另一个类
5:夸夸其谈未来性,在没有任何暗示的情况下考虑扩展 Dao,实际HibernateImpl可能n年内是唯一的Dao实现
6:纯稚的数据类,只有数据的类 item



转载自http://blog.donews.com/ooFrank/archive/2006/04/10/821788.aspx">http://blog.donews.com/ooFrank/archive/2006/04/10/821788.aspx

  回复  引用    
#8楼2006-04-23 03:11 | skyblue[未注册用户]
有提到ruby on rails,属于胀血模型,因为它把domain object和DAO都合并了。
ROR应该是居于表模块+活动记录模式的吧?




发表评论

昵称: [登录] [注册]

主页:

邮箱:(仅博主可见)

评论内容:

  登录  注册

[使用Ctrl+Enter键快速提交评论]

0 369022




相关文章:

相关链接: