DDD 存储库和工厂
DDD repository and factory
在我的应用程序中有几层。
在本主题中,将重点关注领域和基础设施层。
我在域层有存储库接口ClientRepositoryInterface。
我在基础设施层实现了这个接口 ClientRepositoryImpl。
但是要在对象存在的周期中重建对象,我需要工厂 (ReconstitutionClientFactory)。
调用工厂将在存储库中。
埃里克埃文斯的书被描述为一种正常的做法。
但是这个工厂(ReconstitutionClientFactory)应该位于哪里呢?在领域还是在基础设施层?
我认为在领域...
但!但是下层会直接调用上层!
这是错误的,但是如何做对呢?
首先,分层方法有点过时了。层层交谈时想想'context',谁在谁之上并不重要。
存储库负责恢复一个对象。工厂只是 创建 一个新对象。注意不同的语义。存储库知道 saving/restoring to/from 持久化是如何完成的,这取决于存储和访问方法。
因此,一切都在存储库内完成,即在基础架构中完成。如果你序列化了东西,那么你只需要反序列化(这就是文档数据库做事的方式)。如果您正在使用 ORM 或将内容存储在表中,那么您将执行获取数据和重新填充对象所需的所有查询。 ORM 是最简单的方法,因为它可以使用反射来填充私有属性。在这种情况下,ORM 本身就是工厂。
还有一件事,恢复,虽然从技术上讲可以由域工厂完成,但这不是工厂的目的,因为它打破了层边界。我们希望在基础架构中保留与持久性相关的所有内容。
工厂和存储库概念
为了回答您的问题,我认为重点关注 DDD 定义的概念的责任 很重要。
在蓝皮书中,有一个部分处理您描述的问题:
A FACTORY handles the beginning of an object’s life; a REPOSITORY helps manage the middle and the end.
特别针对您的问题:
Because the REPOSITORY is, in this case, creating objects based on data, many people consider the REPOSITORY to be a FACTORY—indeed it is, from a technical point of view.
(均引自 Evans,第 6 章,第 "The relationship with factories" 节)
为了保持概念的纯净,重要的是您的工厂和存储库的接口[=52=] 是干净的。所以不允许通过repository接口创建新的业务对象,也不允许通过factory接口查询已有的。
但是,保持接口清洁并不意味着您不应该使用存储库实现中的工厂,因为毕竟存储库会在某个时候创建一个实例,并且如果实例创建很复杂,那么工厂是合适的解决方案。
再次引用埃文斯的话:
Whenever there is exposed complexity in reconstituting an object from another medium, the FACTORY is a good option.
但是请注意,与真正想要创建新域对象(与重构相反)的客户端相比,存储库很可能会在工厂上调用不同的方法。
埃文斯的书中甚至有一个例子说明了方法:
回答你的问题
现在很明显这是允许的,让我们把注意力集中在你的问题上,把工厂放在哪里:
DDD 工厂接口 属于域,因为您的域逻辑使用它来创建域对象。
DDD 重构工厂接口 不属于该域,因为这仅与您的存储库相关。它不存在于您域的真实世界中。
现在,如果您使用的架构禁止从域到基础架构的依赖性(在应用 DDD 时您可能应该这样做),很明显 工厂实现属于基础架构.请注意,无论您将图层称为 layers、rings、realms 还是其他名称,依赖项都是重要的部分。
在我的应用程序中有几层。 在本主题中,将重点关注领域和基础设施层。
我在域层有存储库接口ClientRepositoryInterface。 我在基础设施层实现了这个接口 ClientRepositoryImpl。
但是要在对象存在的周期中重建对象,我需要工厂 (ReconstitutionClientFactory)。 调用工厂将在存储库中。 埃里克埃文斯的书被描述为一种正常的做法。
但是这个工厂(ReconstitutionClientFactory)应该位于哪里呢?在领域还是在基础设施层?
我认为在领域... 但!但是下层会直接调用上层! 这是错误的,但是如何做对呢?
首先,分层方法有点过时了。层层交谈时想想'context',谁在谁之上并不重要。
存储库负责恢复一个对象。工厂只是 创建 一个新对象。注意不同的语义。存储库知道 saving/restoring to/from 持久化是如何完成的,这取决于存储和访问方法。
因此,一切都在存储库内完成,即在基础架构中完成。如果你序列化了东西,那么你只需要反序列化(这就是文档数据库做事的方式)。如果您正在使用 ORM 或将内容存储在表中,那么您将执行获取数据和重新填充对象所需的所有查询。 ORM 是最简单的方法,因为它可以使用反射来填充私有属性。在这种情况下,ORM 本身就是工厂。
还有一件事,恢复,虽然从技术上讲可以由域工厂完成,但这不是工厂的目的,因为它打破了层边界。我们希望在基础架构中保留与持久性相关的所有内容。
工厂和存储库概念
为了回答您的问题,我认为重点关注 DDD 定义的概念的责任 很重要。
在蓝皮书中,有一个部分处理您描述的问题:
A FACTORY handles the beginning of an object’s life; a REPOSITORY helps manage the middle and the end.
特别针对您的问题:
Because the REPOSITORY is, in this case, creating objects based on data, many people consider the REPOSITORY to be a FACTORY—indeed it is, from a technical point of view.
(均引自 Evans,第 6 章,第 "The relationship with factories" 节)
为了保持概念的纯净,重要的是您的工厂和存储库的接口[=52=] 是干净的。所以不允许通过repository接口创建新的业务对象,也不允许通过factory接口查询已有的。
但是,保持接口清洁并不意味着您不应该使用存储库实现中的工厂,因为毕竟存储库会在某个时候创建一个实例,并且如果实例创建很复杂,那么工厂是合适的解决方案。
再次引用埃文斯的话:
Whenever there is exposed complexity in reconstituting an object from another medium, the FACTORY is a good option.
但是请注意,与真正想要创建新域对象(与重构相反)的客户端相比,存储库很可能会在工厂上调用不同的方法。
埃文斯的书中甚至有一个例子说明了方法:
回答你的问题
现在很明显这是允许的,让我们把注意力集中在你的问题上,把工厂放在哪里:
DDD 工厂接口 属于域,因为您的域逻辑使用它来创建域对象。
DDD 重构工厂接口 不属于该域,因为这仅与您的存储库相关。它不存在于您域的真实世界中。
现在,如果您使用的架构禁止从域到基础架构的依赖性(在应用 DDD 时您可能应该这样做),很明显 工厂实现属于基础架构.请注意,无论您将图层称为 layers、rings、realms 还是其他名称,依赖项都是重要的部分。