gpt4 book ai didi

domain-driven-design - DDD 领域层中的 DateTime.Now

转载 作者:行者123 更新时间:2023-12-05 03:28:44 27 4
gpt4 key购买 nike

最近我在我的域模型中遇到了以下不变量:

  1. 如果 ExpiryAt (DateTimeOffset) < DateTimeOffset.Now,则报价被视为已过期。

  2. 公司董事年龄不得小于18岁

  3. 下载文档时,我们应该将 DownloadedAt 字段设置为 DateTimeOffset.Now

在应用层中,为了保持纯度和更好的测试,我们通常将 System.DateTime 与 IDateTime 接口(interface)隔离开来,这允许在单元测试中模拟 Now。

但这3个场景都属于领域层,不属于应用层。我们不应该将外部接口(interface)注入(inject) DomainModel 以保持它的纯净。但从另一方面来看,直接在 DomainLayer 中使用 DateTime.Now 或 DateTimeOffset.Now 可能不好,因为这会增加对系统时钟的依赖性,并且有时会更难测试,因为 DateTime.Now 永远不会返回相同的结果。

那么问题是 - 您如何应对这种困境?

我看到的选项:

  1. 现在作为域实体方法的参数提供。这是一个可行的选择,可以简化测试,但会使代码更加冗长,有时甚至是愚蠢的。

  2. 只需在领域层使用 DateTime.Now。我已经提到了这种方法的缺点。

根据您的经验,您还有什么建议吗?

最佳答案

从不同的选项来看,访问静态DateTime.Now() 功能显然是最不利的。它既不允许测试,也隐藏了域模型对实现细节中某些非确定性基础设施的依赖。

将一些接口(interface)注入(inject)到可以查看的服务的选项要好一些,因为它使依赖显式并且还允许通过对非依赖进行 stub 来进行单元测试- 确定性输出以返回您选择的一些确定性值。

但是,在运行时您的域模型仍然需要访问一些基础设施依赖项。在某些情况下,这可能是一个合理的妥协,但如果可能的话,我会尽量避免这种情况,以保持域模型的纯净。

如果您从不同的角度看您案例中的当前日期时间,您会发现它实际上与普通输入参数完全不同。您可以将其视为类似于引用日期时间,而不是当前日期时间。

引用您的第一个示例 - 检查报价是否已过期 - 从域模型的角度来看,它需要检查报价是否已在某个给定时间点过期 。在执行域逻辑的用例之一中,这个给定时间点恰好是当前日期时间。

所以最重要的是,在这种情况下,我建议注入(inject)(当前)日期时间的值,而不是某些功能的接口(interface)。它明确了除了域自己封装的数据之外真正需要哪些数据以及执行业务逻辑所需的数据。

此外,它使客户端代码(例如用例或应用程序服务)想要告诉或询问域模型的内容更加明确。例如,检查优惠是否已经过期,或者如果需要,告诉我优惠是否已经在给定的时间点过期,或者即使它会在重要的时间点过期。

作为进一步阅读,我推荐这个很棒的 article from Vladimir Khorikov他详细阐述了该主题。

关于domain-driven-design - DDD 领域层中的 DateTime.Now,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/71179194/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com