DDD 建模中的价值对象、实体和字典类型

7
我希望能将我的问题推广到更广泛的受众,因为我们在公司已经讨论了一段时间,但找不到答案。
假设我们有一个聚合根对象“Transaction”。在“Transaction”内部,我们有一个值对象“Money”。
class Transaction {
    private Money money;
    // other stuff
}

class Money {
    private BigDecimal amount;
    private String currency;
}

这样的交易可以使用Hibernate持久化到数据库中的简单表transaction
+-----------------+
| transaction     |
+-----------------+
|id : bigint      |
|amount: decimal  |
|currency: varchar|
|other...         |
+-----------------+

一切都很好,但是...客户要求我们在数据库中拥有货币表(我们称之为字典表),并且每个具有货币的表格(包括交易)都需要指向货币表:

+-----------------+           +-----------------+
| transaction     |           |curency          |
+-----------------+           +-----------------+
|id : bigint      |     +---> | id: bigint      |
|amount: decimal  |     |     | code: varchar   |
|curr_id: bigint  | ----+     | name: varchar   |
|other...         |           +-----------------+
+-----------------+

从现在开始,Money对象应该像这样:

class Money {
    private BigDecimal amount;
    private Currency currency;
}

现在我们不能再称它为值对象 :(,或者说我们可以吗?这也使得我们持久化对象的方式变得更加复杂,因为我们不能再使用Hibernate embedable,而是需要编写自己的自定义类型enter link description here。毫无疑问,我们不是第一个面临这些问题的人,因为字典类型在使用中很受欢迎,问题是,在DDD建模范围内如何处理它们。

当处理地址时,我们将面临类似的问题。所以,我们知道我们有像国家和联邦州这样的字典(它们是分层的)。我们也知道我们应用程序中的许多对象(例如Institution)有自己的地址,但也与联邦州有联系。因此,在简单情况下,我们将会有:

class Institution {
    Address address;
    // ...
}

在哪里

class Address {
    String street;
    String houseNo;
    // etc..
    String federalState;
    String country;
}

但是我们需要它与联邦州表有关,因此地址将如下所示:
class Address {
    String street;
    String houseNo;
    // etc..
    FederalState federalState;
}

我们再次面临着同样的问题,地址不再是值对象。技术上我们知道该如何处理,但从DDD的角度来看,什么是正确的方法?


"从现在开始我们不能再称之为值对象了 :(" - 为什么?" - guillaume31
1
@guillaume31因为现在它有了自己的表格,所以它获得了更高的地位,可能会感到受到冒犯? - Adrian Colomitchi
1
我在你的问题中看不到一个Money表。此外,确定一个对象是否是值对象与数据库表几乎没有关系。 - guillaume31
1
@guillaume31 不仅仅是“任何时刻的本质”,而且还要考虑到“跟踪演变的需求”——如果其属性的变化足够显著以至于需要跟踪它们的演变,那么我们肯定在谈论一个“实体”而不是一个“值”。 - Adrian Colomitchi
1
你的模型中可能有一个值对象,从持久化世界的角度来看它是一个实体,只要它在模型中保持为一个值,那就没问题。并不是所有的值对象都必须是可嵌入的,否则你就无法在关系型数据库中有效地建模一个值的集合。现在,在你的货币-联邦州示例中,只要货币只参考所在州的ID,那就没问题了。 - plalx
显示剩余6条评论
2个回答

1

从DDD的角度来看,什么是正确的方法?

首先,使用字典实体并没有错。即使只是因为与字符串值相比,使用与字典实体的关系:

  1. 避免了拼写错误(更加健壮)
  2. 允许在不修改代码的情况下管理“值”的集合 - 您只需从存储中加载字典并填充下拉列表,而不是在代码中定义枚举(更加灵活)。

撇开上述两个原因,业务要求可能会强制采用这种设计。例如对于货币案例:当表示为实体时,允许定义汇率关系,这本身可能受到'审计记录/历史'方法的影响,以便随时间存储汇率的演变。
拥有一个State字典是处理不同销售税政策或法律限制(产品/服务在某些州不允许 - 参见“药用”杂草等)的可能未来扩展的良好基础。


1

1
目前你的回答不够清晰。请编辑并添加更多细节,以帮助其他人理解它如何回答所提出的问题。你可以在帮助中心找到有关如何撰写好答案的更多信息。 - Community

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接