DDD 客户、联系人和地址(聚合根)

DDD Customer, Contacts, and Addresses (aggregate root)

我正在构建一个应用程序来管理我公司的大部分 LOB 内容。我正试图全神贯注于 DDD……从客户管理开始。关于域模型,许多示例非常非常简单,对我帮助不大。

我的聚合根是一个Customerclass,它包含一个Addresses集合(通讯录),一个Contacts集合,一个通讯历史集合。

看来这个聚合根会很大,有修改地址、联系人(可以有x个phone号码)、通讯等功能。

例如

UpdateCustomerName(...)
SetCustomerType(...) // Business or individual
SetProspect(...) // if the customer is a prospect
SetDefaultPaymentTerms(...) // line of credit, etc. for future orders
SetPreferredShippingMethod(...) // for future orders
SetTaxInfo(...) // tax exempt, etc.
SetCreditLimit(...)
AddAddress(...)
RemoveAddress(...)
UpdateAddress(...)
VerifyAddress(...)
SetDefaultBillingAddress(...)
SetDefaultShippingAddress(...)
AddContact(...)
UpdateContact(...)
RemoveContact(...)
SetPrimaryContact(...)
AddContactPhoneNumber(...)
RemoveContactPhoneNumber(...)
UpdateContactPhoneNumber(...)
AddCommunication(...)
RemoveCommunication(...)
UpdateCommunication(...)
etc.

我读到值对象没有身份。在这个系统中,每个地址(在数据库中)都有一个 ID,并且有一个 customerId 作为外键。如果 Address 是它自己的聚合根,那么我将无法使用我的业务逻辑来设置默认计费/送货。许多示例都有没有 ID 的值对象...我不知道如何在没有 ID 的情况下将更改保存到我的客户 table。

任何人,如果它要变得如此巨大,我觉得我的结构走错了路。有人做类似的事情吗?不确定如何分解结构并维护基本业务规则(例如确保在将地址设置为默认计费或送货之前将地址分配给客户)。

您之所以反对业务逻辑应该位于何处的问题,是因为您在混合有界上下文。 LoB 应用程序是 DDD 中的典型示例之一,其中大部分显示应用程序被分解为多个限界上下文:

  • 客户服务
  • 结算
  • 运费
  • 等等

每个限界上下文可能需要您的客户提供一些信息 class,但很可能不是全部。在处理实体定义时,DDD 违背了标准的 DRY 概念。定义多个 Customer class 是可以的,一个用于需要它的每个限界上下文。在每个限界上下文中,您将使用属性和业务逻辑定义 classes 以满足该限界上下文中的要求:

  • 客服:联系方式,联系历史
  • 账单:账单地址、付款信息、订单
  • 送货:订单项,送货地址

这些限界上下文可以全部指向同一个数据库,也可以指向多个数据库,具体取决于系统的复杂性。如果是同一个数据库,您将设置数据访问层来填充限界上下文所需的属性。

Steve Smith 和 Julie Lerman 在 Pluralsight 上有一门很棒的课程,叫做领域驱动设计基础,深入介绍了这些概念。