Domain driven design 将聚合验证放在何处?

Domain driven design 将聚合验证放在何处?,domain-driven-design,Domain Driven Design,我有一个关于外部聚合验证的问题 在我们的域中,合作伙伴可以下包含特定产品的订单(1) 一旦下了订单,他可以在我们的系统中将其标记为已付款 一旦订单标记为已付款(4),我们将为外部图书馆服务(5)中的产品分配许可证 一旦我们知道许可证被分配,我们就结束了整个传奇 下面是一张小图,说明了该过程: 此时,除了命令、命令处理程序和事件之外,整个过程还涉及两个域类: 包含业务逻辑的订单聚合 订购传奇,协调整个流程并分配许可证 现在,有一个不变量在这个过程中还没有建模——在我们将订单标记为付费之前,我

我有一个关于外部聚合验证的问题

  • 在我们的域中,合作伙伴可以下包含特定产品的订单(1)
  • 一旦下了订单,他可以在我们的系统中将其标记为已付款
  • 一旦订单标记为已付款(4),我们将为外部图书馆服务(5)中的产品分配许可证
  • 一旦我们知道许可证被分配,我们就结束了整个传奇
下面是一张小图,说明了该过程:

此时,除了命令、命令处理程序和事件之外,整个过程还涉及两个域类:

包含业务逻辑的订单聚合 订购传奇,协调整个流程并分配许可证

现在,有一个不变量在这个过程中还没有建模——在我们将订单标记为付费之前,我们必须检查用户是否还没有分配特定的许可证。我们也从图书馆服务处得到这个

你会把这个验证放在哪里?命令处理程序?在某个域服务中包装订单?将一些验证器传递给订单构造函数

class Order
{
    public function __construct(OrderValidator $validator)
    {
        if (!$validator->isValid($this)) {
            throw new \DomainException();
        }

        // else proceed
    }
}

class OrderValidator
{
    private $libraryServiceClient;

    public function isValid(Order $order)
    {
        // check licence using $libraryServiceClient
    }
}

据我所知,问题在步骤3(将订单标记为已付款)。在这一步中,我们需要一个将订单标记为已付款的用户(我们称之为payer)。因此,在创建这个付款人对象(可能使用factory)时,我们需要知道是否允许他将订单标记为payed。为了获得这些信息,应致电外部图书馆

我建议使用一个具有
->markOrderAsPayed($orderId,$payerUserId)
此方法将调用2个域服务。一个用于获取付款人,另一个用于将订单标记为已付款

$payer = $this->payerService->getPayer($payerUserId);
$this->orderService->payOrder($orderId, $payer);
getPayer()
函数中,您应该调用外部库以了解付款人拥有多少许可证


我希望这会有所帮助,这只是基于我从问题和评论中了解到的。

据我所知,问题在第3步(将订单标记为已付款)。在这一步中,我们需要一个将订单标记为已付款的用户(我们称之为payer)。因此,在创建这个付款人对象(可能使用factory)时,我们需要知道是否允许他将订单标记为payed。为了获得这些信息,应致电外部图书馆

我建议使用一个具有
->markOrderAsPayed($orderId,$payerUserId)
此方法将调用2个域服务。一个用于获取付款人,另一个用于将订单标记为已付款

$payer = $this->payerService->getPayer($payerUserId);
$this->orderService->payOrder($orderId, $payer);
getPayer()
函数中,您应该调用外部库以了解付款人拥有多少许可证


我希望这会有所帮助,这只是基于我从问题和评论中了解的情况。

如果您想要严格的验证,您可以传递一个“服务”,在执行MarkPaid命令的聚合方法中进行验证,在更改状态之前检查它我认为用户应该是模型的一部分,因为每个订单都有一个创建它的用户。然后验证可以很简单,并且仍然在聚合的一侧。用户类只能有一个方法->isAllowedToMakePayment()或->HasLicense()@MohamedBooAllegue当然,但是许可证检查实际上是不同的有界上下文的一部分,所以它必须被委托到某个地方-我的问题是如何委托。如果你想要严格的验证,你可以传递一个“服务”这会在执行MarkPaid命令的聚合方法上进行验证,并在更改状态之前进行检查。我认为用户应该是模型的一部分,因为每个订单都有一个创建它的用户。然后验证可以很简单,并且仍然在聚合的一侧。用户类只能有一个方法->isAllowedToMakePayment()或->HasLicense()@MohamedBooAllegue当然,但是许可证检查实际上是不同的有界上下文的一部分,所以它必须被委托到某个地方-我的问题是如何委托。