首页 > 解决方案 > DDD 关于设计决策

问题描述

我必须解决一个域问题,我对什么是更好的解决方案有些疑问。我将提出问题:

我有 Applications ,每个Application都有很多Process。应用程序也有一些ProcessSettings。当我必须创建一个流程时,我有一些业务规则,例如,基于应用程序的流程设置,我必须在一些流程属性上应用一些规则。

我将Application视为聚合根,将Process视为其他聚合根,并将 ProcessSettings 视为 Application 聚合中的值对象。

我有一个创建流程的用例,其逻辑是创建一个有效的流程实例并将其与 ProcessRepository 持久化。好吧,我想我有两个选项可以应用流程设置:

  1. 在用例中,通过Application聚合中的域服务通过ApplicationId从Application聚合中获取进程设置,并将ProcessSettings传递给进程创建方法。
  2. 在用例中,创建流程并通过应用程序聚合中的域服务传递流程的副本(值对象)以应用流程设置。

您认为哪种方法最适合使用?或者您是否以其他方式实现它?

提前致谢!

标签: domain-driven-designaggregateroot

解决方案


我们的产品负责人告诉我们,如果客户立即支付了一些设置并创建了一个流程,那么如果客户不更新它,这些设置将对该流程有效。如果客户离开支付一些设置,那么当客户想要更新该流程时,我们的系统将不允许更新它,因为实际设置将不适合流程数据

这使得实施更加容易,因为基于流程设置的验证只需要在流程创建/更新场景中进行。此外,我猜想竞争条件也与业务无关,例如如果在创建/更新流程的同时更改设置。

鉴于此,我们可以假设ProcessSettings并且Process可以处于不同的一致性边界。换句话说,两者都可以是单独聚合根的一部分。

此外,重要的是要认识到基于设置的验证不是Process一成不变的,这意味着Process不应该负责执行这些规则本身。由于这些不是不变量,您也不应该争取始终有效的策略,而应使用延迟验证策略。

从那时起,有很多很好的方法可以对这个用例进行建模,这些方法都可以归结为:

//Application layer service
void createProcess(processId, applicationId, data) {
    application = applicationRepository.applicationOfId(applicationId);
    process = application.createProcess(processId, data);
    processRepository.add(process);
}

//Application AR
Process createProcess(processId, data) {
    process = new Process(processId, this.id, data);
    this.processSettings.ensureRespectedBy(process);
    return process;
}

如果ProcessSettingsApplicationAR 的一部分,那么将工厂方法用于创建流程是有意义的,Application因为它拥有执行验证所需的状态,就像上面的示例一样。这消除了为任务引入专用域服务的需要,例如独立工厂。

如果ProcessSettings可以是它自己的聚合根,你总是可以这样做,但引入一个查找域服务进行设置:

//Application AR
Process createProcess(processId, data, settingsLookupService) {
    process = new Process(processId, this.id, data);
    processSettings = settingsLookupService.findByApplicationId(this.id);
    processSettings.ensureRespectedBy(process);
    return process;
}

有人可能会说您的聚合不再是纯粹的,因为它通过调用settingsLookupService. 如果你想避免这种依赖,你可以引入一个领域服务,比如ProcessDomainService封装创建/更新逻辑,或者你甚至可以考虑查找逻辑不够复杂,直接放在应用层。

//Application layer service
void createProcess(processId, applicationId, data) {
    processSettings = processRepository.findByApplicationId(applicationId);
    process = application.createProcess(processId, data, processSettings);
    processRepository.add(process);
}

我们无法判断哪种方法在您的特定情况下更好,有时甚至没有完美的方法,许多不同的方法可能同样好。根据经验,保持聚合纯粹是一个好主意,因为它更容易进行单元测试(更少模拟)。


推荐阅读