dinghao

记录成长点滴

 

我们仍然需要贫血的域模型

几种域模型的争论持续很久了,尤其在Martin Fowler批判贫血的域模型后,争论更加激烈,Martin的文章我刚看到,他对贫血域模型的观点我基本都同意,但是我得出的结论确和他不同。

我同意只含有属性(甚至加上CRUD)的Domain Object是不符合OO的,这样做很类似于使用事务脚本和表模块方式,只是把取出的数据再封装到类中。在这种模型下Domain object更像一个DTO和值对象。

同意域模型只包含属性和CRUD没有体现出域模型的本意,域模型实现域逻辑才能称为域模型。从这两点上说Martin的观点也是正确的。

但是总感觉有些不对的地方,毕竟自己和好多人一样用这种模式很久了,能存在这么久也是有原因的,有些人把这归结于ORMNhibernate)和DAO模式的广泛使用,确实这两种工具促使了这种模型的发挥范围,但是从本质上说,这种模式是有其优点的,至少我认为他和含有业务逻辑的域模型(充血)比较起来是半斤八两,贫血模型没有比充血域模型差。

      贫血模型的层次结构:
      
      注:domain object实现一些易于绑定控件的接口也可以当做DTO使用,但是一般DTO还是不能省的。图中的ICompare只是一个特例,可能还要实现IList等。
      
首先,贫血模型虽然不OO,但是毕竟把数据封装到类里面了,这样就为Service层实现OO打下了一个基础,要比表模块和事务脚本好很多,从这点上看他也不等同于事务脚本和表模块。

       其次,把业务逻辑和域模型(贫血)分开是有优点的,至少把业务逻辑和业务数据分离了,虽然在理论上这种分离是没有意思的也是非OO的,但在实践中这样做至少分离了变化,实现难度也没有增加,为什么是不可以接受呢?难道只是因为他不OO

       再次,特别简单是这种模型流行的基础。如果使用nhibernateORM工具,很容易再第三方工具的配合下生成代码,如果把CRUD从域中提取出来可以更方便的使用代码生成。如果自己些映射可以很容易的在数基层实现Mapper或者用ActiveRecord

再加上在简单的应用中Domain object可以当作DTO使用,这些都是贫血模型存在的理由。

他的缺点是导致服务层太庞大了,这一点可以把服务层拆分,然后再在这些细粒度的服务层上面封装一个thinService层来解决。

另一个缺点是,我直觉上认为在领域对象中不包含领域逻辑是很不合理的,但是又找不到他不合理的证据。

充血结构:

   包含域逻辑的域对象(充血)没有上面说的两个缺点,他符合
OO,很容易实现一个thinService,感觉上这种模型很好。

首先,域对象包含了操作,是真正的域对象,域对象可以重用了,只是听起来很美。

其次,服务层很薄(只包含跨多个域对象或者第三方逻辑的封装),把域逻辑分离了一部分给域对象,变化容易控制,修改也容易。

但是这些优点,很多都是直觉上的,因为业务逻辑太复杂了也太容易变化了,这就造成让域对象包含操作也不是一个很合理的方式。

缺点是实现很难,即使用ORM工具也很复杂,更不要说自己写映射层了。

总结:业务逻辑和业务数据耦合在一起是合理的,但是业务逻辑相较于业务数据是更易变的,从分离变化的角度来看是有必要把他们分开的,也就是贫血模式。同样把DAO从域对象剥离出来也没有什么必要,因为两者都是相对稳定的。
所以我认为贫血的模型是比较实用的。

posted on 2007-01-09 15:58 思无邪 阅读(...) 评论(...) 编辑 收藏

导航

统计

公告