Domain driven design 基于时间的不变量

Domain driven design 基于时间的不变量,domain-driven-design,Domain Driven Design,我目前正在尝试将DDD实现到现有的系统中,对于我的一个模型的一些不变量,我有点头疼 在工资系统中,一些不变量在纳税年度开始时会发生变化,但系统仍需要支持当前纳税年度。比如说,如果现在的最低全职工作年龄是16岁,但下一个纳税年度则改为15岁,那么DDD是否可以解决这个问题 目前有一个参考数据存储库,它具有开始日期/到期日期,可以通过使用当前日期来读取,以确定在给定日期使用的正确记录,但据我所知,在模型中使用存储库有点不正确 我是否遗漏了DDD的一个明显的要点(例如,因为它需要一个存储库,而不是实体

我目前正在尝试将DDD实现到现有的系统中,对于我的一个模型的一些不变量,我有点头疼

在工资系统中,一些不变量在纳税年度开始时会发生变化,但系统仍需要支持当前纳税年度。比如说,如果现在的最低全职工作年龄是16岁,但下一个纳税年度则改为15岁,那么DDD是否可以解决这个问题

目前有一个参考数据存储库,它具有开始日期/到期日期,可以通过使用当前日期来读取,以确定在给定日期使用的正确记录,但据我所知,在模型中使用存储库有点不正确

我是否遗漏了DDD的一个明显的要点(例如,因为它需要一个存储库,而不是实体的一个不变量),或者是否有一种方法可以解决这个问题?(例如,当此类变更生效时,它们实际上是分开的集合吗?)

目前有一个参考数据存储库,它具有开始日期/到期日期,可以通过使用当前日期来读取,以确定在给定日期使用的正确记录,但据我所知,在模型中使用存储库有点不正确

使用存储库的真正问题是试图访问某些东西的“当前”状态,而不是与您正在做的工作同时发生变化

从模型中访问不可变状态并没有什么根本性的错误;在讨论中,这通常表示为传递给模型的DomainService(也称为“纯函数”),而不是存储库

在您的情况下,税收政策不受您的模型控制;这是外界强加给你的东西;您的模型所能做的最好的事情就是使用最新版本的策略历史记录


简而言之,您将对时间进行建模,并且您将拥有一个域服务,在给定的时间内,该服务将返回适用于该时间的税收政策的不可变表示(状态)(据您所知),并且该模型将显式地记录满足的税收政策,而不仅仅是使用什么键来查找该策略。

如果您的聚合需要该时基信息,那么您必须提供它,无论它在哪里持久化。另一方面,聚合应该对外部服务具有最小的依赖性,您应该保持它们的干净和纯净;因此,聚合不应执行任何IO,甚至不应执行抽象IO(通过使用域拥有并在基础设施中实现的接口)

也就是说,在调用aggregate命令方法之前,我将查询参考数据的
存储库,并将该信息作为值对象参数传递。因此,我不会在聚合中注入任何服务,甚至不会作为命令方法的参数


换个角度想想:聚合是否关心信息存储在哪里,甚至它存储在什么地方?不需要,它只需要信息,
应用程序服务
最擅长访问存储库并从存储库加载所需的数据。

这就是为什么您应该这样做的原因之一。例如,从您的案例来看,对雇佣合同进行建模非常有意义

现在你会得到这样的代码

public EmploymentContractFactory {

    public EmploymentContract(DateTime starttime, Person p) {
          if (starttime.Year == 2016 && p.Age < 16) {
             throw new TooYoungException();
          }
          else if (p.Age < 15) {
             throw new TooYoungException();
          }
          return new EmploymentContract(starttime, p);
    }
}
公共就业合同工厂{
公共雇佣合同(日期时间开始时间,人员p){
如果(起始时间=2016年和p.年龄<16岁){
抛出新的异常();
}
否则,如果(p.年龄<15岁){
抛出新的异常();
}
返回新的雇佣合同(开始时间,p);
}
}
DDD的理念是,您的实体/工厂足够聪明,能够知道它们何时有效以及可以创建什么

这在一定程度上取决于你的领域的复杂性。例如,如果您的域处理很多与合同相关的规则,您甚至可能会使用“合同规则”,它可以规避针对您的模型合同的一些法律。 在这种情况下,您可以要求法律手册(聚合根目录)在某个日期返回所有适用的法律/规则,并使用工厂中的法律/规则来查看是否允许您创建该特定合同