4Manuals

  • PDF Cloud HOME

DDD-更改汇总内的实体 Download

    如何将依赖项注入与Autofac 4.x集成的NHibernate 5.x实体中?

在阅读DDD - Modifications of child objects within aggregate和Update an entity inside an aggregate之后,我仍然对聚合中实体更改的实现仍然感到困惑。据我了解,聚合根代表整个(或整个聚合),并将“命令”的更改委托给其余部分。

最后一部分,委托给其余部分,会引起一些问题。在下面的示例中,我想更改特定订单行的数量。我正在处理根“订单”,并告诉它更改由本地标识符标识的订单行的数量。

当满足所有业务规则时,可以创建一个事件并将其应用于聚合。目前,所有事件都应用于聚合根,并且我认为这是一个好习惯,因此所有命令都针对根,这会更改聚合状态。同样,聚合根是唯一一个创建事件,让世界知道发生了什么。

class Order extends AggregateRoot
{
    private $orderLines = [];
    public function changeOrderLineQuantity(string $id, int $quantity)
    {
        if ($quantity < 0) {
            throw new \Exception("Quantity may not be lower than zero.");
        }

        $this->applyChange(new OrderLineQuantityChangedEvent(
            $id, $quantity
        ));
    }

    private function onOrderLineQuantityChangedEvent(OrderLineQuantityChangedEvent $event)
    {
        $orderLine = $this->orderLines[$event->getId()];

        $orderLine->changeQuantity($event->getQuantity());
    }
}

class OrderLine extends Entity
{
    private $quantity = 0;

    public function changeQuantity(int $quantity)
    {
        if ($quantity < 0) {
            throw new \Exception("Quantity may not be lower than zero.");
        }

        $this->quantity = $quantity;
    }
}

但是,当我应用此实现时,我遇到了一个问题,因为您注意到检查$ quantity值的业务规则位于两个类中。这是有目的的,因为我不太了解最佳地点。该规则仅适用于OrderLine类,因此不属于Order。但是,当我从Order中删除此事件时,将创建无法应用的事件,因为并非所有业务规则都得到满足。这也是不想要的。

我可以在OrderLine类中创建一个方法,例如:

    public function canChangeQuantity(int $quantity)
    {
        if ($quantity < 0) {
            return false;
        }
        return true;
    }

将OrderLine中的方法更改为:

    public function changeQuantity(int $quantity)
    {
        if ($this->canChangeQuantity($quantity) < 0) {
            throw new \Exception("Quantity may not be lower than zero.");
        }

        $this->quantity = $quantity;
    }

现在我可以将Order类中的方法更改为:

    public function changeOrderLineQuantity(string $id, int $quantity)
    {
        $orderLine = $this->orderLines[$event->getId()];
        if ($orderLine->canChangeQuantity($quantity)) {
            throw new \Exception("Quantity may not be lower than zero.");
        }

        $this->applyChange(new OrderLineQuantityChangedEvent(
            $id, $quantity
        ));
    }

确保业务逻辑在其中,而不是在两个地方。这是一个选择,但是如果复杂度增加并且模型变大,我可以想象这些做法会变得更加复杂。

现在我要提问: (1)您如何应对从根开始的聚合中的深层变化? (2)当业务规则增加时(例如,最大数量为10,但在星期一增加3,对于产品X,最大数量为3)。在聚合根上为验证这些业务规则的域服务提供每个命令/方法是否是一种好习惯?

1 个答案:

答案 0 :(得分:0)

  

我有一个问题,因为您注意到检查$ quantity值的业务规则位于两个类中。

从“面向对象”的角度来看,Order::changeOrderLineQuantity($id, $quantity)是消息。消息具有架构,并且架构限制任何给定字段中允许的值范围是很正常的。

所以这里的代码:

public function changeOrderLineQuantity(string $id, int $quantity)
{
    if ($quantity < 0) {
        throw new \Exception("Quantity may not be lower than zero.");
    }

是消息验证的示例,您正在检查数量是否在允许的值范围内,因为通用int基元太宽容了。

使用强类型语言的域建模人员通常会在这里引入一种新的类型,又名ValueObject,该模型使用范围限制对数据进行建模。

// Disclaimer: PHP is not my first language
class Quantity {
    public function __construct(int $quantity) {
        if ($quantity < 0) {
            throw new \Exception("Quantity may not be lower than zero.");
        }
        $this.quantity = quantity
    }
    //  ...
}

在轻松的情况下,Quantity所理解的Orders::changeOrderLineQuantity(...)与Quantity是相同的域概念,OrderLineQuantityChangedEvent(...)所理解的与{{1 }},如Quantity所理解,因此您可以在任何地方重复使用相同的类型;因此,类型检查器可确保满足正确的约束条件。



Similar searches
    Samsung RSA1D Refrigerator User Manual 如何在react图表上的datakey中操作DateTime 删除结尾意外输入的多余空格 AJAX jQuery实时评论 如何使用硒更改Googlestore过滤器