我们仍然需要贫血的域模型
2007-01-09 15:58
323 查看
几种域模型的争论持续很久了,尤其在Martin Fowler批判贫血的域模型后,争论更加激烈,Martin的文章我刚看到,他对贫血域模型的观点我基本都同意,但是我得出的结论确和他不同。
我同意只含有属性(甚至加上CRUD)的Domain Object是不符合OO的,这样做很类似于使用事务脚本和表模块方式,只是把取出的数据再封装到类中。在这种模型下Domain object更像一个DTO和值对象。
同意域模型只包含属性和CRUD没有体现出域模型的本意,域模型实现域逻辑才能称为域模型。从这两点上说Martin的观点也是正确的。
但是总感觉有些不对的地方,毕竟自己和好多人一样用这种模式很久了,能存在这么久也是有原因的,有些人把这归结于ORM(Nhibernate)和DAO模式的广泛使用,确实这两种工具促使了这种模型的发挥范围,但是从本质上说,这种模式是有其优点的,至少我认为他和含有业务逻辑的域模型(充血)比较起来是半斤八两,贫血模型没有比充血域模型差。
贫血模型的层次结构:
注:domain object实现一些易于绑定控件的接口也可以当做DTO使用,但是一般DTO还是不能省的。图中的ICompare只是一个特例,可能还要实现IList等。
首先,贫血模型虽然不OO,但是毕竟把数据封装到类里面了,这样就为Service层实现OO打下了一个基础,要比表模块和事务脚本好很多,从这点上看他也不等同于事务脚本和表模块。
其次,把业务逻辑和域模型(贫血)分开是有优点的,至少把业务逻辑和业务数据分离了,虽然在理论上这种分离是没有意思的也是非OO的,但在实践中这样做至少分离了变化,实现难度也没有增加,为什么是不可以接受呢?难道只是因为他不OO?
再次,特别简单是这种模型流行的基础。如果使用nhibernate等ORM工具,很容易再第三方工具的配合下生成代码,如果把CRUD从域中提取出来可以更方便的使用代码生成。如果自己些映射可以很容易的在数基层实现Mapper或者用ActiveRecord。
再加上在简单的应用中Domain object可以当作DTO使用,这些都是贫血模型存在的理由。
他的缺点是导致服务层太庞大了,这一点可以把服务层拆分,然后再在这些细粒度的服务层上面封装一个thinService层来解决。
另一个缺点是,我直觉上认为在领域对象中不包含领域逻辑是很不合理的,但是又找不到他不合理的证据。
充血结构:
包含域逻辑的域对象(充血)没有上面说的两个缺点,他符合OO,很容易实现一个thinService,感觉上这种模型很好。
首先,域对象包含了操作,是真正的域对象,域对象可以重用了,只是听起来很美。
其次,服务层很薄(只包含跨多个域对象或者第三方逻辑的封装),把域逻辑分离了一部分给域对象,变化容易控制,修改也容易。
但是这些优点,很多都是直觉上的,因为业务逻辑太复杂了也太容易变化了,这就造成让域对象包含操作也不是一个很合理的方式。
缺点是实现很难,即使用ORM工具也很复杂,更不要说自己写映射层了。
总结:业务逻辑和业务数据耦合在一起是合理的,但是业务逻辑相较于业务数据是更易变的,从分离变化的角度来看是有必要把他们分开的,也就是贫血模式。同样把DAO从域对象剥离出来也没有什么必要,因为两者都是相对稳定的。
所以我认为贫血的模型是比较实用的。
我同意只含有属性(甚至加上CRUD)的Domain Object是不符合OO的,这样做很类似于使用事务脚本和表模块方式,只是把取出的数据再封装到类中。在这种模型下Domain object更像一个DTO和值对象。
同意域模型只包含属性和CRUD没有体现出域模型的本意,域模型实现域逻辑才能称为域模型。从这两点上说Martin的观点也是正确的。
但是总感觉有些不对的地方,毕竟自己和好多人一样用这种模式很久了,能存在这么久也是有原因的,有些人把这归结于ORM(Nhibernate)和DAO模式的广泛使用,确实这两种工具促使了这种模型的发挥范围,但是从本质上说,这种模式是有其优点的,至少我认为他和含有业务逻辑的域模型(充血)比较起来是半斤八两,贫血模型没有比充血域模型差。
贫血模型的层次结构:
注:domain object实现一些易于绑定控件的接口也可以当做DTO使用,但是一般DTO还是不能省的。图中的ICompare只是一个特例,可能还要实现IList等。
首先,贫血模型虽然不OO,但是毕竟把数据封装到类里面了,这样就为Service层实现OO打下了一个基础,要比表模块和事务脚本好很多,从这点上看他也不等同于事务脚本和表模块。
其次,把业务逻辑和域模型(贫血)分开是有优点的,至少把业务逻辑和业务数据分离了,虽然在理论上这种分离是没有意思的也是非OO的,但在实践中这样做至少分离了变化,实现难度也没有增加,为什么是不可以接受呢?难道只是因为他不OO?
再次,特别简单是这种模型流行的基础。如果使用nhibernate等ORM工具,很容易再第三方工具的配合下生成代码,如果把CRUD从域中提取出来可以更方便的使用代码生成。如果自己些映射可以很容易的在数基层实现Mapper或者用ActiveRecord。
再加上在简单的应用中Domain object可以当作DTO使用,这些都是贫血模型存在的理由。
他的缺点是导致服务层太庞大了,这一点可以把服务层拆分,然后再在这些细粒度的服务层上面封装一个thinService层来解决。
另一个缺点是,我直觉上认为在领域对象中不包含领域逻辑是很不合理的,但是又找不到他不合理的证据。
充血结构:
包含域逻辑的域对象(充血)没有上面说的两个缺点,他符合OO,很容易实现一个thinService,感觉上这种模型很好。
首先,域对象包含了操作,是真正的域对象,域对象可以重用了,只是听起来很美。
其次,服务层很薄(只包含跨多个域对象或者第三方逻辑的封装),把域逻辑分离了一部分给域对象,变化容易控制,修改也容易。
但是这些优点,很多都是直觉上的,因为业务逻辑太复杂了也太容易变化了,这就造成让域对象包含操作也不是一个很合理的方式。
缺点是实现很难,即使用ORM工具也很复杂,更不要说自己写映射层了。
总结:业务逻辑和业务数据耦合在一起是合理的,但是业务逻辑相较于业务数据是更易变的,从分离变化的角度来看是有必要把他们分开的,也就是贫血模式。同样把DAO从域对象剥离出来也没有什么必要,因为两者都是相对稳定的。
所以我认为贫血的模型是比较实用的。
相关文章推荐
- 在情报传递过程中,为了防止情报被截获,往往需要对情报用一定的方式加密,简单的加密算法虽然不足以完全避免情报被破译,但仍然能防止情报被轻易的识别。我们给出一种最简的的加密方法,对给定的一个字符串,把其中
- SQL2000系统表、存储过程、函数的功能介绍及应用2009年01月21日 星期三 11:38虽然使用系统存储过程、系统函数与信息架构视图已经可以为我们提供了相当丰富的元数据信息,但是对于某些特殊的元数据信息,我们仍然需要直接对系统表进行查询。因为SQL
- 为什么要让我们的“领域模型”充血裸奔?
- 输入两个单调递增的链表,输出两个链表合成后的链表,当然我们需要合成后的链表满足单调不减规则。
- 作为一名运维工程师我们需要哪些技术
- 我们为什么需要微软Windows Phone 7
- 我们需要什么怎样的OLAP(转摘并修改)
- EntityFramework Core 1.1有哪些新特性呢?我们需要知道_0
- 专家访谈:为什么我们需要Erlang
- 创建实体数据模型需要注意的,不要选单复数形式,否则AddObject出问题
- 基线系统需要受到更多关注:基于词向量的简单模型
- LSTM模型在问答系统中的应用 2017-06-27 21:03 在问答系统的应用中,用户输入一个问题,系统需要根据问题去寻找最合适的答案。 1:采用句子相似度的方式。根据问题的字面相似度选择相似度最
- 有时我们需要调用一个函数时,返回多个不同类型的数据
- Foursquare: 如何构建我们的模型训练引擎(Model Training Engine)
- 为什么我们需要nginx
- 我们仍然在路上-走出软件作坊(五十) 推荐
- 一个典型的SaaS模式需要的三种计算模型支撑
- 我们仍然在路上-走出软件作坊(五十)
- (15.1.9)为什么我们总会需要一款APP?
- 【转载】我们为什么需要Windows Workflow Foundation?