【问题标题】:DateTime.Now in Domain Layer of DDDDDD领域层中的DateTime.Now
【发布时间】:2022-10-17 05:55:56
【问题描述】:

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

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

  2. 公司董事不得低于 18 岁

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

    在应用程序层中,为了保持纯度和更好的测试,我们通常将 System.DateTime 与 IDateTime 接口隔离,这允许在 UnitTests 中模拟 Now。

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

    所以问题是——你如何处理这个困境?

    我看到的选项:

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

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

      您还可以根据自己的经验提出其他建议吗?

【问题讨论】:

    标签: domain-driven-design


    【解决方案1】:

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

    注入一些的选项界面可以查看的服务要好一些,因为它使显式依赖并且还允许通过存根非确定性输出以返回一些确定性的您选择的价值。

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

    如果您从不同的角度查看当前日期时间,则会更明显地发现它实际上与普通输入参数没什么两样。你可以把它看作是参考日期时间而不是当前日期时间。

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

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

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

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

    【讨论】:

      猜你喜欢
      • 2012-05-11
      • 1970-01-01
      • 2011-04-03
      • 2015-07-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-05-17
      • 2019-07-19
      相关资源
      最近更新 更多