【发布时间】:2019-12-30 12:58:29
【问题描述】:
阅读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。但是当我从订单中删除它时,将创建无法应用的事件,因为并非所有业务规则都得到满足。这也是不想要的。
我可以在 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 件)。为聚合根上的每个命令/方法提供验证这些业务规则的域服务是否是良好做法?
【问题讨论】:
标签: domain-driven-design aggregateroot