【问题标题】:OOP - manage a unique identifier in a collectionOOP - 管理集合中的唯一标识符
【发布时间】:2017-07-05 08:35:16
【问题描述】:

我正在开发一个遵循 OOP 和 DDD 的 php 购物车。 我有一个 ShoppingCart 类作为不同类型的 CartItem 实例(Type1ProductItem、Type2ProductItem 等)的集合,它们都实现了 CartItemInterface。

管理要用作 ShoppingCart 内部集合中的键的唯一标识符的最佳方法是什么?

我当前的解决方案是 CartItemInterface 中的“getPrimaryKey()”方法返回基于类型和 id 的唯一标识符:

购物车:

public function add(CartItemInterface $CartItem) {
    $this->items[$CartItem->getPrimaryKey()] = $CartItem;
}
public function remove(CartItemInterface $CartItem) {
    unset($this->items[$CartItem->getPrimaryKey()]);
}

导致:

ShoppingCart->add($CartItem);
ShoppingCart->doSomething($CartItem);

但是通过这种方式,我必须在购物车上的每个操作(添加、删除、更新..)之前创建一个 CartItem,具体取决于 uri 的参数,然后将其传递给 ShoppingCart 的相关方法:

// type and id coming as parameters
switch ($type) {
    case 1 : $CartItem = new Type1ProductItem($id); break;
    case 2 : $CartItem = new Type2ProductItem($id); break;
    ....
}
ShoppingCart->doSomething($CartItem);

这不是一个大问题,因为我可以使用工厂来避免重复的逻辑,但如果唯一标识符 (UID) 在 CartItem 实例之外创建并在第一次项目时传递给 ShoppingCart 是否会是一个更可行的解决方案添加了吗?

ShoppingCart->add($UID, CartItemInterface $CartItem);
 ShoppingCart->doSomething($UID); // no need of CartItem instance here

我不确定在 CartItem 实例之外管理 uid 是否好。 你怎么看? 解决方案的优缺点是什么? 非常感谢。

【问题讨论】:

  • $UID 传递给工厂。它应该使用它来初始化它创建的CartItemInterface 对象的PK 字段。不要修改ShoppingCart的接口。
  • 为什么需要将CartItemInterface 传递给add?为什么不传递所需的属性,如 productId、productType、数量和价格?
  • 我认为您不需要 shoppingCart 类中的 cartItem 主键。为什么不简单地做 $this->items[] = $CartItem;我认为 cartItem 应该是一个值对象,因为它只是一个项目的描述,而不是项目本身。所以它并不需要一个 id
  • @ConstantinGALBENU 我需要 CartItem 中的一些行为,属性数组或值对象是不够的。
  • @MohamedBouallegue 我需要 CartItem 中的一些行为,因此值对象是不够的。关于$this->items[] = $CartItem,我同意它会更快,但这样我每次需要识别一个项目时都必须循环遍历项目集合,没有主键..或者我错过了什么?

标签: php oop domain-driven-design


【解决方案1】:

一般来说,不建议将可变对象传递给聚合的实例,因为聚合可能会在其自己的方法之外发生变异。您可以传递对象,但它们必须是不可变的,例如 Value 对象。

在您的情况下,如果 CartItemInterface 是可变对象,那么这不是一件好事。您必须使它们不可变(因此 Value 对象)或不传递它们而是传递它们的属性(并且这些属性也必须是不可变的),如下所示:

public function addItemToCart($productId, $productType, $quantity, $price)

然后,如果您需要对购物车商品执行某些操作,例如更改数量,则将购物车商品标识符传递给 ShoppingCart(聚合)方法。该标识符将来自 ShoppingCart 聚合本身,当您向用户显示购物车项目并且不一定是 GUID 或其他全局唯一的东西时,它必须仅在聚合内是唯一的,因此即使是从零开始的索引就足够了。通过这种方式,聚合决定自己如何识别其购物车项目,聚合负责,聚合是其自己的购物车项目的权威,聚合可以随时更改此设置而无需“请求”其他人的许可系统的组成部分。例如,如果您需要从购物车中移除商品,您可以这样做:

public function remove($cartItemIndex) {
    unset($this->items[cartItemIndex]);
}

因为您说(在 cmets 中)您需要在购物车项目中进行一些行为,我建议使它们成为值对象(如此不可变),然后您可以根据需要传递它们(即当向用户显示购物车时没有需要创建一个额外的本地 DTO 类)。

【讨论】:

  • 非常感谢您的努力,当然我的经验远不如您:-)。感谢您的建议,它们甚至超出了问题的范围。所以,再次感谢您。
  • 我试图分享一些关于聚合的经验,因为它们非常重要。
猜你喜欢
  • 2021-11-22
  • 1970-01-01
  • 2015-10-18
  • 2012-07-15
  • 1970-01-01
  • 2011-08-29
  • 2011-08-17
  • 2012-07-18
  • 1970-01-01
相关资源
最近更新 更多