关于oop:购物上下文建模

Shopping context modelling

我想以DDD方式编写我的第一个应用程序(电子商务),我想知道我是否做对了所有事情,所以我希望您对我的建模有何看法-如何改进它,应该怎么做?我正在寻找等。每一个反馈将不胜感激。

我已将我的应用程序划分为几个有界上下文(目录,购物,订购),下面的示例基于购物环境。我也尝试使用CQRS(因此AddProductToCart命令)。

我的业务要求如下:

  • 客户应该能够将产品添加到他的购物车中
  • 附加产品的价格应特定于用户,并应基于以下几个因素:(全球折扣,用户折扣和客户所在的国家/地区(某些国家/地区降低了基本价格)

我认识以下演员(请注意方法和类的注释):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
/**
 * A customer (Aggregate Root) having an unique cart
 */
class Customer
{
    /**
     * @var int
     */
    private $customerId;

    /**
     * @var string
     */
    private $country;

    /**
     * @var Cart
     */
    private $cart;

    /**
     * @var PriceProvider
     */
    private $priceProvider;

    /**
     * Adds product to customers cart with user-specific price
     *
     * @param $productId
     * @return CartLine
     */
    public function addProductToCart($productId)
    {
        $price = $this->priceProvider->priceForProduct($productId, $this->customerId, $this->country);
        return $this->cart->addLine($productId, $price);
    }
}

/**
 * Simple CartLine object for persisting purposes
 */
class CartLine
{
    public $productId;
    public $price;
    public $cartId;

    function __construct($cartId, $productId, $price)
    {
        $this->cartId    = $cartId;
        $this->price     = $price;
        $this->productId = $productId;
    }
}

class Cart
{
    private $cartId;

    public function addLine($productId, $price)
    {
        return new CartLine($this->cartId, $productId, $price);
    }
}

/**
 * Provides price for specific country
 */
class PriceProvider
{
    public function priceForProduct($productId, $userId, $country)
    {
        // Logic for determining product price for customer
        // Based on available global discounts, user discounts and country
    }
}

/**
 * Command for adding product to cart
 */
class AddProductToCart
{
    public $customerId;
    public $productId;
}

/**
 * An application service to bind everything together
 */
class CustomerService
{
    public function addProductToCart(AddProductToCart $command)
    {
        /** @var Customer $customer */
        $customer = $this->customerRepository->customerOfId($command->customerId);
        $cartLine = $customer->addProductToCart($command->productId);

        $this->cartLineRepository->save($cartLine);
    }
}

这是正确的方法吗?我在这里违反任何DDD原则吗?我可以改善吗?


CQRS通常涉及命令处理程序。
命令与"命令式"动词相关联。
CustomerService太宽泛,因此不代表" command "的意图。

我将CustomerService更改为AddProductToCart

1
2
3
4
5
6
class AddProductToCart
{
    public function handle(AddProductToCartCommand $command) {
      ...
    }
}

通过将所有各种功能拆分为适当的命令,您将能够根据需要为一个特定命令制作多个版本。


所以稀疏顺序(部分取决于编程语言):

  • 您的聚合根目录应进行显式标记(例如,使用IAggregateRoot接口),因此,如果您的语言支持通用语言,则只能实现聚合根目录的存储库。
  • 您的构造函数应始终是私有的,而应使用工厂。仅将构造函数用于初始化问题。在您的下一个未来中,Customer的构造规则可能会增加复杂性,而工厂将为您提供灵活性。
  • 不变逻辑是域逻辑。取决于用例的逻辑是应用逻辑(即PriceProvide r与域逻辑无关)