领域贫血症是否适用于面向服务的架构?

时间:2010-05-04 16:30:38

标签: design-patterns soa anti-patterns

我想明确这一点。当我说域贫血时,我的意思是故意域贫血,而不是意外。在我们大多数业务逻辑隐藏在一堆服务背后的世界中,完整的域模型真的是必要的吗?

这是我自从最近开始问自己的问题,因为“域”模型实际上是一个持久性模型。没有任何域对象包含任何方法,这是一个非常有意的决定。

最初,当我看到一个库充满了本质上属于类型安全的数据容器时,我打了个哆嗦,但经过一番思考后,让我感到震惊的是这个特定的系统并没有做太多但基本的CRUD操作,所以也许在这种情况下这是一个不错的选择。我想我的问题是,到目前为止,我的经验一直非常关注丰富的域名模型,所以它给我一点点。

域逻辑的其余部分隐藏在一组生活在单独组件中的帮助者,外墙和工厂中。

我很想知道人们对此的看法。显然,重用这些类的考虑因素要简单得多,但实际上是非常有益吗?

7 个答案:

答案 0 :(得分:5)

我同意可能没有必要使用完整的域名模型。但是,我认为使用模拟数据访问对象编写服务测试比编写非贫血域对象测试更痛苦。我正在开发一个项目,现在域名逻辑存在于除了域模型之外的任何地方,分散在帮助者和策略和调解器中,并且整个事情在它开始生产之前就变成了无法管理的遗留代码。

回想以前的项目,我确实记得一个使用贫血域对象的项目,它有很多问题,包括一个糟糕的本土xml数据库,但是因为它确实采用了基于服务的方法,所以很容易解决问题一次一个,并取得实际进展。在当前项目中,他们试图变得聪明并将域对象绑定到数据库,ActiveRecord样式,并且没有做任何努力来控制它们的依赖项。域对象与数据库的紧密耦合,过度使用静态方法以及类似意大利面条的依赖关系网已经成为导致这个代码库成为过早脆弱,不灵活和不可测试的泥球的重要组成部分。因此,我认为虽然持久性无知的丰富域对象使业务逻辑的测试变得更加容易,但重要的是管理您的依赖项。

答案 1 :(得分:5)

我认为,一个贫穷的领域,而OO反模式实际上是一种SOA模式。随着我们提升抽象水平,规则发生了一些变化。

我正在写作的系列文章中进一步探索,去年我的日志上也有一个关于它的咆哮。 metallemon.blogspot.com/2008/07/soa-and-anemic-domains.html

http://hubpages.com/hub/Building-Service-Orientated-Architecture

答案 2 :(得分:4)

六年后,这需要重大更新。

简单的答案是肯定的。但复杂的答案是否定的。

不,SOA并不需要贫血。但与此同时,企业系统并不需要使用SOA编写。同样,架构根本不是任何代码的要求。这将是一场噩梦,但如果你愿意的话,你可以把所有功能都打包到一个模块中。

简单地说:OO最初是根据它与前辈的不同来定义的。更具体地说:C ++是由它与C的不同之处定义的。但OO的定义已经改变。我们现在有很多OO原则。

免责声明:许多这些原则在OO之前部分或全部创建,并且在OO革命期间被简单地声明或更新。此外,我意识到OO已经出现在LONG-Before C ++之前,但这并没有改变我的观点:

封装,遗传,多态性,关注点分离,持久性无知,高内聚/低耦合,S,O,L,I,D等等。

不仅如此,如果你遵循这些原则遵循DDD和/或TDD,你几乎不需要建筑师。只要遵循这些原则,您自然会得到一个使用贫血域模型的面向服务的体系结构。

想一想。如果您有一个包含Save()SendMessage()PayEmployee()的员工类...您正在违反当前OO原则的许多规则。

当您分析并将某些职责划分到不同的服务,存储库,命令,工厂等中时...... 您无法帮助但拥有空员工类... ...

排序?

诚实地说,你需要牢记价值对象的想法。 OO的定义不仅有所发展,而且还有“无穷无尽”的定义。也进化了。 Employee类当然不应该是空的。它可以有很多商业逻辑"在它。

Employee类可以有:

  • 参数化构造函数,其中验证参数
  • Readonly计算字段的属性
  • Employee.ToString(),Employee.TryParse()和类似的对象方法
  • 可能是其他人,特定于员工

从本质上讲,员工仍然贫血。 肯定永远不会是域模型中的任何算法或代码流逻辑。但是,它并不仅仅是一种商业逻辑。

当马丁福勒十年前说贫血领域模型是一种反模式时,它已经变得越来越可行。他的推理是双重的,两个折叠都是旧闻。

他的第一个折叠首先是他对OO的捍卫定义是代码和数据已经结婚,或者将数据和流程结合在一起&#34;,反对旧的程序风格。不幸的是,这只适用于糟糕的代码。如果我们遵循继承和多态,我们知道函数并不真正存在于类中。他们生活在指针中,因此inherting类可以覆盖并移动它们。但是......他们是否生活在代码中以提高可读性?他们当然不应该!它们应该在Interfaces和Abstractions中定义,并且只在类中实现。对不起马丁,但是当你 对,代码/数据婚姻是OO 20年前的一个巨大的原始卖点时,它现在并不是那么重要。< / p>

他的第二个原因是他取消了SOA的错误,并指出了一些与我们今天称为N-Tiered Architecture非常相似的描述。当然,我意识到这不是一项新技术,但多年来定义发生了变化。

不仅Martin Fowler,还有其他许多人立即引用他的文章,因此说SOA本身就是一种反模式,因为它需要Anemic Models,而Fowler认为这是一种反模式。

所以我们归结为......

贫血领域模型并不像人们所认为的那样贫血。 SOA是必需的,我们不能打折。不幸的是,这只是事情的方式。

为什么需要SOA? - 这太过于描述性。但长话短说:在90年代的域名软件中运行的是PC和服务器......以及硬件&#34; Plugged-Into&#34;那些巨石。这些天我们的计算机&#34;计算机&#34;实际上是万亿我们周围。烟雾探测器,冰箱,手表,手机......现在计算机插入物体。所以每个想法,部门, CONCERN 和对象都是它自己的小域。我们要求SOA将它们写入自己的小服务,甚至是子服务。

因此:应用程序现在插入服务(而不是插入应用程序的服务)。要创建SOA,我们只需遵循OO的当前规则,例如SOLID和Separation of Concerns。当我们这样做时,我们自然会得到Anemic Domain Models ... sorta。

所以不,SOA不需要贫血领域模型。它们是遵循现行原则和标准的自然结果。

答案 3 :(得分:3)

这正是我无法理解的人们对网络服务如此兴奋。不要误会我的意思,那里有一些好的想法,但我认为程序式编程没有区别。看看你的架构。你所描述的只是使用所有OOP的东西来使它完美地程序化。使用普通数据结构,算法和模块有多容易?我不知道你的情况,但考虑使用关系数据库与存储过程和一些绑定到Web服务是多么容易。另一个答案似乎在某种程度上与我达成一致......我想听听你的想法,如果它在你的情况下更有意义,如果不是为什么?我是否误解了Web服务的程序性质?

答案 4 :(得分:2)

我猜你的架构是基于SOA的,并使用消息传递实现,然后域模型应该放在服务层内。这意味着没有必要强制整个架构形成域模型,但您可以在子架构中应用它。

答案 5 :(得分:1)

我发现大多数程序员都没有理解OOP。当它被介绍时,每个人都对我们如何不再编写另一个地址数据结构以及这些类如何将代码与数据结合以使我们不必编写更多验证代码感到高兴。

然后,现实开始了:我对地址的想法并不总是和其他人一起生活。更糟糕的是,我的地址概念可能会根据我今天正在进行的系统而改变。这很简单。

而且,情况变得更糟。遗产?那是什么?抽象,虚拟,..只是放入代码中的关键字来关闭编译器。

更糟糕的是:代码模式。需要验证一个对象?在这里使用这个辅助模式......

所以我们到达的地步是大多数人认为“类”是一个结构或者是随机函数的倾倒场,可能以某种方式相关但是上帝禁止你把实际的代码对于具有由其定义的数据的类。

答案 6 :(得分:1)