我如何最好,安全地将父母/孩子的物体连接在一起

时间:2018-06-21 10:30:30

标签: php immutability

这是我的示范案例:

[EEEE, CCC1]

我希望在OrderPosition中有一个指向“父级” /拥有的Order项目的指针;但是,由于Order被视为汇总根,因此我希望Order负责创建OrderPositions的集合。

当最终订单尚未创建时,应如何在每个OrderPosition中放置Order项目? 我目前的方法是将其延迟设置在Order的ctor中,但是严格来说,这会使OrderPosition发生变化。

1 个答案:

答案 0 :(得分:1)

您在这里有几个冲突的设计决策:

  1. 不可变的对象
  2. 循环参考
  3. 一个不负责构造依赖对象的构造函数
  4. 不允许看到和变异部分对象的工厂方法

正如您所说,当前的实现方式允许(OrderPosition在以后添加额外的引用,从而损害了(1)。

如果卸下(2),可以使问题消失。在什么情况下,您将引用OrderPosition并想导航到它所属的Order?是否可以将这种情况重新定义为Order的责任,从而删除循环引用?

您可以更改(3),以使构造函数使用信息来创建OrderPositions,而不是OrderPositions本身。在您的示例中,这是微不足道的,但是如果实际上您有多个不同的工厂供入一个构造函数,则可能会变得混乱。

或者,如果您放松(4),则可以将部分构造的对象传递到OrderPosition构造函数/工厂中:

public static function fromArray($orderData)
{
    assert(isset($orderData['orderId']));
    assert(isset($orderData['positions']));

    $instance = new self($orderData['orderId']);
    foreach ( $orderData['positions'] as $positionData ) {
        $instance->orderPositions[] = OrderPosition::fromArray($positionData, $instance);
    }
    return $instance;
}

虽然它看起来仍然像是突变,但它与您在任何构造函数中所做的突变相同-您正在创建对象的初始状态。

在支持重载或命名构造函数的语言中,fromArray成为构造函数,并且可能不会与其他构造函数共享任何实现。在PHP中,您可以使用空的private function __construct(){}和以$instance = new self;开头的静态方法来模拟该模式