Domain driven design 领域驱动设计,如何处理特定于用户的数据?
在阅读了Eric Evans的DDD之后,我试图将其应用到我正在管理的项目中。有一些特定于用户的查询数据,我不确定如何以DDD的方式实现 例如,如果用户查询通知,应用程序应该告诉用户是否阅读了每篇文章。通常在这种情况下,我会用如下数据进行响应:Domain driven design 领域驱动设计,如何处理特定于用户的数据?,domain-driven-design,Domain Driven Design,在阅读了Eric Evans的DDD之后,我试图将其应用到我正在管理的项目中。有一些特定于用户的查询数据,我不确定如何以DDD的方式实现 例如,如果用户查询通知,应用程序应该告诉用户是否阅读了每篇文章。通常在这种情况下,我会用如下数据进行响应: { "notices": [ {"content": "foo", "is_read": true}, {"content": "bar", "is_read": false} ] } 假设存在通知实体
{
"notices": [
{"content": "foo", "is_read": true},
{"content": "bar", "is_read": false}
]
}
假设存在通知
实体和读取
实体,用于保存用户是否已读取该实体。还假设有如此多的用户在阅读通知,因此检索is\u read
的所有用户不是一种有效的方法
- 由于
Read
实体在没有Notice
实体的情况下是不会被查询的,所以我可以将它放在Notice
聚合中。然后以请求用户为参数实现查询功能
- 或者,我可以将
NoticeRepository
和ReadRepository
分开,查询通知,然后在应用程序层将它们与使用通知ID查询的读取连接起来
第一个选项似乎是假设用户查询通知并用应用程序逻辑破坏域层。另一方面,第二个选项让我感觉到我正在以一种不必要的复杂方式实现一个简单的特性。我现在真的想不出其他的选择。。对于这种情况,最佳做法是什么
我现在真的想不出其他的选择
我可以看到两个可能会让你绊倒的问题
首先,您的域模型可能缺少一个重要的概念。我们如何知道Bob是否阅读了特定的通知?域中可能有一些实体,可能是一个确认
,它捕获了Bob和他阅读的文档,以及该域感兴趣的其他信息(他阅读了文档的哪个版本?什么时候?什么渠道?什么时候?等等)
因此,将生成的视图看起来类似于与来自Bob的确认保持连接的活动通知列表
另一件可能让你感到困惑的事情是,试图“手工”进行连接,使用存储库获取数据,这是一个真正的阻力。此外,人们在蓝皮书问世后的几年里已经意识到,这可能是没有必要的。因为查询是,它们不会改变基础数据——如果基础数据不会改变,我们就不需要域模型来保护业务不变量。这需要在查询服务中实现
Eric Evans的书是一个很好的基础,现在它已经发展到更现代的模式,例如Vaughn Vernon的书中的CQR,实现领域驱动设计(IDDD)
您的查询服务将负责显示通知列表,并在单独的表中更新此用户的读取列
您可以在此处查看一些查询服务示例(用java编写):
我不会有一个读取实体。只需注意和用户。在User中,您将有一个用户已阅读的通知ID列表(反之亦然,在Notice中,您将有一个已阅读通知的用户ID列表)
然后,要查询您需要在用户界面中显示的信息,您有几种选择,正如沃恩·弗农(Vaughn Vernon)在其《实现DDD》(第512页)一书中所说:
- DTOs
- 调解人
- 域有效负载对象
- 国家陈述
- 用例优化存储库查询(不适用于CQR)
- 数据转换器
谢谢。说得好!CQR可能是您在最后一段中告诉我的吗?读写分离不会导致代码库被复制吗?而且,几乎每个域存储库都实现了单个项检索,让它显示给客户机不是很简单吗?DDD中的代码复制不是问题。事实上,它是一个Pro,考虑一下:你想更新你的读取模型,而不是你的写模型,代码已经被分开,你不需要检查潜在的回归。这是一场胜利