DDD - 持久性模型和领域模型

Posted

技术标签:

【中文标题】DDD - 持久性模型和领域模型【英文标题】:DDD - Persistence Model and Domain Model 【发布时间】:2012-12-11 02:04:19 【问题描述】:

我正在尝试学习领域驱动设计 (DDD),我想我已经掌握了基本概念。但是有些事情让我很困惑。

在 DDD 中,持久性模型和域模型是不同的东西吗?我的意思是,我们在设计领域和类时只考虑领域问题;没关系。但是在那之后,当我们构建存储库或任何其他数据持久性系统时,我们是否应该创建模型的另一个表示以在持久层中使用?

我在想我们的领域模型也用于持久性,这意味着我们的存储库从查询中返回我们的领域对象。但是今天看了这篇文章,有点懵:

Just Stop It! The Domain Model Is Not The Persistence Model

如果这是真的,将持久性对象与域对象分开有什么好处?

【问题讨论】:

这是我写的关于这个确切主题的帖子:enterprisecraftsmanship.com/2016/04/05/… @ayk 链接移至blog.sapiensworks.com/post/2012/04/07/… 【参考方案1】:

在 DDD 中,持久性模型和域模型是不同的东西吗?

是的,但这并不一定意味着一组不同的类来明确表示持久性模型。

如果使用关系数据库进行持久化,则像 NHibernate 这样的 ORM 可以通过映射到域类来处理表示持久性模型。在这种情况下,没有明确的持久性模型类。这种方法的成功取决于 ORM 的映射能力。例如,NHibernate 可以通过component mappings 支持中间映射类。这允许在需要时使用显式持久性模型类。

如果使用文档数据库进行持久化,则通常更不需要持久化模型,因为域模型只需要可序列化即可被持久化。

因此,当存在无法通过 ORM 映射到域模型的复杂映射时,请使用显式持久性模型类。无论实现如何,域模型和持久性模型之间的区别仍然存在。

【讨论】:

嗯,所以只要我能以正确的方式处理持久性,我就可以使用相同的类。不够的时候,我可以重新考虑并添加一些新的类而不是域类来进行持久化。我做对了吗? 是的,特定于持久性的类可以有多种形式。它们可以是数据库和域之间的简单 DTO,也可以是 NHibernate 等现有映射基础架构的一部分。 我想,现在清楚了,非常感谢您的关注和帮助。 我认为这里必须添加一些东西。域模型应该始终关注域行为,而持久性模型最多存储域对象状态。持久性对您想要从对象存储的内容进行建模,并且该数据将用于恢复对象。您可以使用 ORM 实体作为域实体的基础,但是您必须协调对象以遵守 ORM 需求。基本上,除了真正的目的之外,您的域对象还必须满足 ORM 的需求。然后你就在一个滑坡上。 @Sergio 我想像有一个无参数的构造函数,使一些字段非最终的,允许它们最初为空并由 ORM 工具注入,处理数据与早期版本的应用程序,...【参考方案2】:

这样想,领域模型应该不依赖任何东西,并且其中没有基础设施代码。域模型不应该是可序列化的,也不应该从某些 ORM 对象继承,甚至不应该共享它们。这些都是基础架构问题,应该与领域模型分开定义。

但是,如果您正在寻找纯 DDD 并且您的项目重视可扩展性和性能而不是初始开发速度。很多时候,将基础架构问题与您的“域模型”混合可以帮助您以可伸缩性为代价实现速度的巨大进步。关键是,您需要问自己,“纯 DDD 的好处是否值得在开发速度上付出代价?”。如果您的回答是肯定的,那么这里就是您的问题的答案。

让我们从一个示例开始,您的应用程序以域模型开始,而数据库中的表恰好与您的域模型匹配。现在,您的应用程序突飞猛进,您在查询数据库时开始遇到性能问题。您已经应用了一些经过深思熟虑的索引,但是您的表增长得如此之快,以至于看起来您可能需要对数据库进行反规范化才能跟上。因此,在 dba 的帮助下,您提出了一种新的数据库设计,可以满足您的性能需求,但是现在这些表与以前的方式大不相同,现在您的域实体块分布在多个表中,而不是而不是每个实体都有一个表。

这只是一个示例,但它说明了为什么您的域模型应该与您的持久性模型分开。在此示例中,您不想拆分域模型的类以匹配您对持久性模型设计所做的更改,并从本质上更改域模型的含义。相反,您想更改新的持久性模型和域模型之间的映射。

将这些设计分开有几个好处,例如可扩展性、性能和对紧急数据库更改的反应时间,但您应该权衡它们与初始开发的成本和速度。通常,从这种分离级别中获益最多的项目是大型企业应用程序。

评论员更新

在软件开发的世界里,有第 N 个可能的解决方案。正因为如此,灵活性与开发的初始速度之间存在间接的反比关系。作为一个简单的例子,我可以将逻辑硬编码到一个类中,或者我可以编写一个允许将动态逻辑规则传递给它的类。前一种选择将具有更高的开发速度,但代价是灵活性较低。后一种选择将具有更高程度的灵活性,但代价是开发速度较低。这在每种编码语言中都适用,因为总是有第 N 个可能的解决方案。

有许多工具可以帮助您提高初始开发速度和灵活性。例如,ORM 工具可以提高数据库访问代码的开发速度,同时还可以让您灵活地选择 ORM 支持的任何特定数据库实现。从您的角度来看,这是时间和灵活性的净收益减去工具的成本(其中一些是免费的),根据开发时间成本相对于业务需要。

但是,对于这种编码风格的对话,本质上就是领域驱动设计,你必须考虑编写你正在使用的工具所花费的时间。如果您要编写该 ORM 工具,甚至编写数据库访问逻辑以支持该工具为您提供的所有实现,那么与仅对您计划的特定实现进行硬编码相比,这将花费更长的时间在使用中。

总而言之,工具可以帮助您抵消自己的生产时间和灵活性价格,通常是通过将时间成本分配给购买工具的每个人。但是,任何代码,包括使用工具的代码,都将受到速度/灵活性关系的影响。通过这种方式,与将业务逻辑、数据库访问、服务访问和 UI 代码纠缠在一起的情况相比,领域驱动设计提供了更大的灵活性,但以生产时间为代价。领域驱动设计比小型应用程序更好地服务于企业级应用程序,因为企业级应用程序的初始开发时间与业务价值相关的成本往往更高,并且因为它们更复杂,它们也更容易发生变化,需要更大的灵活性。及时降低成本。

【讨论】:

这是一个很好的答案。我想投入我自己的两分钱 - 大多数时候都需要将域模型与持久层分离,尤其是在企业中,但不幸的是,(我认为)许多企业在成长时从未过渡到分离域从持久性,因为很多领域和业务逻辑渗透到持久层。我主要参考所有可用的额外工具,这些工具直接处理数据库并绕过包含大部分域逻辑的应用程序。一个重要的例子是报告。 @tomosius 我在很大程度上同意你的看法。如果应用程序的设计边界没有明确定义(无论应用程序架构如何),域逻辑可能会渗入持久层。这就是为什么决定和遵守架构很重要的原因。我不同意报道就是这方面的一个例子。事实上,报告通常与应用程序的主要关注点大不相同,以至于 Martin Fowler 认为它需要自己的模式,称为 CQRS 或命令查询责任分离。在这里查看:martinfowler.com/bliki/CQRS.html【参考方案3】:

在 DDD 中,持久性模型和域模型是不同的东西吗?

在 DDD 中,您拥有 域模型存储库。而已。如果在存储库中,您将直接持久化您的域模型,或者在持久化之前将其转换为持久性模型取决于您!这是一个设计问题,你的设计。这是您的存储库的实现细节,与域本身无关。

正如其他人指出的那样,每个选项都有其优点和缺点。看看这个 answer 我详细介绍了其中的一些。

【讨论】:

我阅读了很多关于 DDD 的文章,但您的简短描述是最好的。谢谢。

以上是关于DDD - 持久性模型和领域模型的主要内容,如果未能解决你的问题,请参考以下文章

DDD专栏4:DDD如何保护领域模型

DDD领域模型贫血模型充血模型概念总结

DDD领域模型贫血模型充血模型概念总结

领域模型驱动设计(DDD)之模型提炼

DDD 域实体与持久性实体

1.实现领域驱动设计 --- DDD入门