1

我在 DDD 世界中很新,我想知道如何处理我有一个聚合根 (AggregateRootA) 需要来自其他聚合根 (AggregareRootB) 的一些信息才能做某事的情况(例如更改聚合根A)。

如果我尝试使用更多真实世界的场景,也许这会更清楚......让我们考虑一个预订系统。在系统中,我们有 Reservation 聚合根和 Resource 聚合根。资源具有可用/不可用状态。系统允许创建预订并向其添加资源(在代码中,当然是通过 Id 引用来完成的)。下一步是接受预订,在这一步中,预订必须检查其所有资源是否都处于可用状态。可以说它不能在添加步骤中完成,或者只是该资源在它已经处于保留状态时改变了它的状态。如何执行此类验证?

我想出了一个解决方案,其中 Reservation 可以访问 ResourceRepository,但我发现不应允许 AggregateRoot 在 DDD 中进行此类访问。

我的第二个想法是将验证转移到 ApplicationService 但对我来说这种验证看起来像域逻辑,所以它应该放在域模型中。

我最后的想法是,也许我应该编写专门的 DomainService 来处理这种情况,但是再次...... DomainService 应该可以访问存储库吗?

4

2 回答 2

1

这是一个非常常见且易于解决的问题,但您需要退后一步。

您基本上应该有两个有界上下文 - 保留和资源。保留不能访问任何其他有界上下文的任何类/服务/对象,因为它违反了封装规则。

相反,您应该在资源有界上下文中创建一个查询处理程序。这些资源应该共享查询和响应类,它们将提供您需要的信息——公共 API,它是您的域之间的合同。最重要的是,reservations bounded context 不应该知道resources的任何实现细节。

PHP 中的示例:

资源域:

索取信息:

class IsResourceAvaiableQuery
{
    private int $resourceId;

    __construct(int $resourceId)
    {
        $this->resourceId = $resourceId;
    }

    public function getResourceId(): int 
    {
        return $this->resourceId;
    }
}

要获得不应该是简单类型但由类表示的响应:

class IsResourceAvaiableDTO
{
    private bool $isAvailable;

   __construct(bool $isAvailable)
   {
       $this->isAvailable = $isAvailable;
   }

   public function isAvailable(): bool 
   {
       return $this->isAvailable;
   }
}

请注意,查询和响应 DTO 都是不可变对象 - 您不能改变它们的状态。

现在在预订域中:

class ReservationValidator
{
    
   public function validate(Reservation $reservation): ViolationsList 
   {
       $isResourceAvailableQuery = new IsResourceAvaiableQuery($reservation->getResourceId());
       $isResourceAvailableDTO = $this->messageBus->query($isResourceAvailableQuery);


      if (false === $isResourceAvailableDTO->isAvailable()) {
          // mark $reservation as invalid  
      }
   }
}

概括

这样,您就有了一个单一的事实来源,并且保留域不需要知道您如何确定资源是否可用。此外,您可以随时更改实现,只要您不更改合同(IsResourceAvaiableQuery & IsResourceAvaiableDTO) ,它就不会影响预订域。

请注意,资源可能在两个域中以不同的方式可用,您也需要进行拆分:

  • 资源- 可供预订 - 存在并标记为可操作的项目
  • 预订- 项目尚未预订。您需要合并来自两个域的决策才能全面了解情况。
于 2021-06-28T10:28:11.213 回答
1

我认为您在最后一段中接近了这一点,但问题不在于DomainService是否可以访问存储库,而更多的是关于它是否可以(在您的技术实现中)的问题?在技​​术基础上评估该方法的优缺点,如果没有出现真正的坏事,那就去做。对我来说,这似乎是你的大脑一直在告诉你要做的事情。

然后随着时间的推移,你对周围领域、限界上下文、语言等的理解会变得更好(而且会),你总是可以重构和重构。没有什么是一成不变的。

于 2021-06-28T06:58:31.400 回答