为什么存储库与域实体一起工作?

问题描述

在 DDD 中,我多次看到以下代码,其中将实体作为参数传递给存储库的 save 方法

class MysqLUserRepository
{
    public function save(User $user) {}
}

据我所知,基础设施不应该对域一无所知。如果这是正确的,我在这里遗漏了什么?

解决方法

存储库在域和数据映射层之间起到中介作用,就像内存中的域对象集合。

见:https://martinfowler.com/eaaCatalog/repository.html

Repository 是一个中介,它必须“翻译”从持久性到域,反之亦然。持久性基础设施获取/提供“原始”数据,因此必须有一些东西可以以最可能的解耦方式将这两个世界粘合在一起。这意味着 Repository 必须了解两个世界。

,

据我所知,基础设施不应该了解域的任何信息

这是一个有效的观点,我相信可以从 Eric Evans 的“领域驱动设计”一书中得出结论。但是请注意,埃里克·埃文斯让我们有些自相矛盾。

在他的书中,他从上到下谈到了分层架构: “用户界面”——>“应用程序”——>“领域”——>“基础设施”。

有了它,他说:

基本原则是层的任何元素仅依赖于同一层中的其他元素或它“下方”层的元素。

由此我们可以得出结论,基础设施层(位于领域层之下)应该对领域层一无所知。然而,埃文斯还谈到域层是定义存储库的层。换句话说,我们已经达到了不可能的状态。

从那时起,关于领域驱动设计的文章越来越多,我相信是 Vaughn Vernon 的“实施领域驱动设计”一书提供了解决方案。

我们可以使用 Alistair Cockburn 定义的六边形架构,而不是使用分层架构。 Hexagonal Architecture 的转变是应用程序不再是不对称的、自上而下的分层架构。相反,它将领域层置于中心。其他一切,包括基础设施层,都放置在这个中心(或六边形)之外。使用域“层”定义的端口可以进行通信。 Repository 可以看作是这种端口的一个例子。

因此域层可以公开端口,在您的情况下为 UserRepositoryInterface。遵循六边形架构,基础设施层可以与域“层”通信。因此,它可以使用 MysqlUserRepository 实现接口。

,

...基础设施不应该知道任何关于域的信息。如果这是正确的...

这不正确。在 DDD 中,基础结构层依赖于域层,因此它知道域想要显示的任何内容。 DDD 中没有关于域应该显示多少内容的规则。这取决于您:您可以显示整个实体,您可以显示 DTO、DPO,...

另一方面,域对基础结构一无所知(这是正确的)。