领域驱动设计——创建通用实体与上下文特定实体

Domain Driven Design - Creating general purpose entities vs. Context specific Entities

情况

假设您的应用程序中有订单和客户作为实体。在一个集合中,Order 实体被认为是根,但您还想使用 Client 实体来做一些简单的事情。在另一个中,客户是根实体,订单实体被轻轻触及。

例子:

假设在订单聚合中,我仅使用客户端来读取名称、地址、构建订单历史记录等详细信息,而不是让客户端执行特定于客户端的业务逻辑。 (如持久性、密码重置和后退..)。

另一方面,在客户端聚合中,我使用订单实体来报告客户的购买习惯、订单总数、订单计数,而不需要高级订单功能,如订单处理、更新、状态更改等。

可能的解决方案

我认为更好的解决方案是为特定于聚合上下文的每个聚合创建实体,因为使它们功能齐全(通用)并为任何情况和使用做好准备似乎有点矫枉过正,可能会成为维护的噩梦. (并且可能会占用大量内存)

问题

DDD 推荐的处理这种情况的方法是什么? 你对此事有何看法?

你是对的。在 DDD 中,实体不仅仅是封装与 "subject" 相关的所有属性的容器(例如:客户,或订单)。这是一个非常重要的概念,但很多人都避而不谈。 DDD 中的实体表示操作边界,因此只有执行操作所需的数据才被认为是实体的一部分。很难考虑将哪些数据确切地包含在一个实体中,因为某些数据在不同的 use-cases 中是相关的。以下是分析数据时的一些技巧:

  • 分析不变量,应用验证规则时必须考虑的事情和不能不同步的事情应该在同一个聚合中。
  • 删除 database-thinking,规范化不是 DDD 的关注点
  • 仅仅因为事物看起来相同,并不意味着它们是相同的。例如:客户注册的当前送货地址与特定订单的送货地址不同。
  • 不看书。阅读,如创建报告或填充 av viewmodel/dto/whatever 与操作边界无关,通常可以是数据的 360 度视图。事实上,在返回读取时不要使用您的域模型,使用不同的体系结构堆栈。

这些决定的基本驱动因素应该是无处不在的语言,因此是您正在建模的现实世界领域。如果两者都在特定领域工作,出于可维护性的原因,我 倾向于分离而不是 god-classes

除了将行为分离到不同的聚合中,您还应该注意不要混合不同的限界上下文。根据您的域的要求,将 购买上下文 报告上下文 分开可能是有意义的(以扩展您的示例)。

要决定上下文设计,上下文映射是一个有用的工具