16

我想澄清这一点。当我说领域性贫血时,我的意思是故意的领域性贫血,而不是偶然的。在一个我们的大部分业务逻辑都隐藏在一堆服务之后的世界里,一个完整的领域模型真的有必要吗?

这是我最近在从事一个“领域”模型实际上是持久性模型的项目后不得不问自己的问题。没有一个域对象包含任何方法,这是一个非常有意的决定。

最初,当我看到一个库中充满了本质上是类型安全的数据容器时,我感到不寒而栗,但在一些人认为这个特定系统只做基本的 CRUD 操作时,我感到震惊,所以在这种情况下,这可能是一个不错的选择. 我想我的问题是,到目前为止,我的经验一直非常关注丰富的域模型,所以它让我有点吃惊。

域逻辑的其余部分隐藏在一组助手、外观和工厂中,它们位于一个单独的程序集中。

我很想听听人们对此的看法。显然,重用这些类的考虑要简单得多,但真的有那么大的好处吗?

4

7 回答 7

6

我同意可能不需要完整的域模型。但是,我确实认为使用模拟数据访问对象为服务编写测试比为非贫血域对象编写测试更痛苦。我现在正在做一个项目,除了域模型之外,域逻辑无处不在,分散在助手、策略和中介中,甚至在投入生产之前,整个事情就已经变成了一堆难以管理的遗留代码。

回想以前的项目,我确实记得一个使用贫血的领域对象的项目,它有很多问题,包括一个糟糕的本土 xml 数据库,但是因为它确实采用了基于服务的方法,所以很容易一次性解决这些问题时间并取得真正的进展。在当前的项目中,他们试图巧妙地将领域对象与数据库联系起来,采用 ActiveRecord 风格,并且没有做出任何努力来控制它们的依赖关系。领域对象与数据库的紧密耦合、静态方法的过度使用以及意大利面条式的依赖关系网络是导致该代码库过早变得脆弱、不灵活和无法测试的泥球的重要原因。所以我认为虽然不了解持久性的富域对象使业务逻辑的测试变得更加容易,但最重要的是管理你的依赖关系。

于 2010-05-04T17:26:23.863 回答
5

我相信一个贫血域而一个 OO 反模式实际上是一个 SOA 模式。随着我们提高抽象级别,规则发生了一些变化。

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

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

于 2010-07-28T04:54:26.767 回答
5

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

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

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

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

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

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

不仅如此,如果您在遵循这些原则的同时遵循 DDD 和/或 TDD,您几乎根本不需要架构师。只要遵循这些原则,您自然会得到一个使用贫血域模型的面向服务的架构。

想想看。如果您的 Employee 类带有Save(), SendMessage(), 和PayEmployee()...,那么您就违反了当前 OO 原则的许多规则。

当您分析并将某些职责提取到不同的服务、存储库、命令、工厂等时……不得不拥有一个空的员工类……有点。

有点?

老实说,您需要牢记价值对象的概念。不仅OO的定义发生了演变,“贫血”的定义也发生了演变。Employee 类当然不应该为空。它可以包含大量的“业务逻辑”。

Employee 类可以有:

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

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

十多年前,当 Martin Fowler 说贫血域模型是一种反模式时,它已经变得越来越可行。他的理由是双重的,而且这两个方面都是旧闻。

他的第一个折叠是他对 OO 的辩护定义是代码和数据是结合的,或者“将数据和过程结合在一起”,这与旧的程序风格相反。不幸的是,这只适用于糟糕的代码。如果我们遵循继承和多态,我们知道函数并不真正存在于类中。它们存在于指针中,因此继承类可以覆盖和移动它们。但是......他们是否存在于代码中以增加可读性?他们当然不应该!它们应该在接口和抽象中定义,并且只在类中实现。抱歉,Martin,尽管您说代码/数据结合是 20 年前 OO 的一个巨大的原始卖点是对的,但现在已经不是手头的问题了

他的第二个观点是,他认为 SOA 做得不正确,并指出了一些与我们今天所说的 N-Tiered Architecture 非常相似的描述。诚然,我意识到这不是新技术,但这些年来定义发生了变化。

不仅 Martin Fowler,而且他之后的许多其他人都立即引用了他的文章,因此说 SOA 本身就是一种反模式,因为它需要贫血模型,Fowler 说这是一种反模式。

所以我们到了这个...

贫血领域模型并不像人们想象的那样贫血。而且 SOA 是必需的,我们不能打折扣。不幸的是,这只是事情的本来面目。

为什么需要 SOA?- 这太描述性了。但长话短说:在 90 年代,软件在 PC 和服务器上运行……而硬件“插入”这些单体。这些天来,我们周围有数以万亿计的“计算机”。烟雾探测器、冰箱、手表、电话……这些天计算机插入事物。因此,每个想法、部门、CONCERN和对象都是它自己的小领域。我们要求 SOA 将它们写成自己的小服务,甚至是子服务。

因此:应用程序现在插入服务(而不是服务插入应用程序)。要创建 SOA,我们只需遵循 OO 的当前规则,例如 SOLID 和关注点分离。当我们这样做时,我们自然会得到贫血域模型......有点。

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

于 2016-01-20T05:08:33.277 回答
3

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

于 2010-05-04T20:16:27.190 回答
2

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

于 2010-05-04T17:33:33.150 回答
1

Here are some resources that explain it better.

SOA Design Pattern

Achieving Integrity in a SOAD

Why your SOA should be like a VW Beetle

于 2010-07-28T07:57:52.747 回答
1

我发现大多数程序员只是不了解 OOP。当它被引入时,每个人都为我们不再编写另一个地址数据结构以及这些类如何将代码与数据结合在一起而感到高兴,这样我们就不必编写更多的验证代码。

然后,现实开始了:我对地址的想法并不总是与其他人的想法不一致。更糟糕的是,我对地址的概念可能会根据我今天正在使用的系统而改变。这是一个简单的。

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

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

因此,我们到达了大多数人认为“类”是结构或随机函数的倾倒场的地步,这些随机函数可能以某种方式相关,但上帝禁止你将类的实际代码与它定义的数据放在一起。

于 2010-05-04T18:08:38.060 回答