我正在学习DDD,如果我的问题很幼稚,请见谅。我认为我需要使用本地数据传输对象来向用户显示数据,因为许多属性不属于任何实体/值对象。
然而,我不确定这个DTO应该在哪里实现 - 在域层还是在应用程序服务层。DTO的实现似乎是域的一部分,但这意味着当我在服务层中创建DTO集合并将其传递给演示层时,我必须在演示层中引用域层,这似乎是错误的。
使用DDD原则实现DTO的正确方法是什么?
我正在学习DDD,如果我的问题很幼稚,请见谅。我认为我需要使用本地数据传输对象来向用户显示数据,因为许多属性不属于任何实体/值对象。
然而,我不确定这个DTO应该在哪里实现 - 在域层还是在应用程序服务层。DTO的实现似乎是域的一部分,但这意味着当我在服务层中创建DTO集合并将其传递给演示层时,我必须在演示层中引用域层,这似乎是错误的。
使用DDD原则实现DTO的正确方法是什么?
将DTO定义到源值来自的层级。
相对于OP的问题:将DTO放在应用服务层中。 DTO是该层的输出,如果您在此定义它,则很合理。不要将DTO放在领域层中。领域层不关心将事物映射为服务外部层(领域不知道其外部世界存在)。
表示层(面向消费者)
应用服务层
领域层
Data / Infrastructure Layer(最接近您的数据库或外部服务)
DTO和Domain是不同的层级。
因此,需要从一个层级映射到另一个层级,通常在所谓的应用程序服务层中完成。
请阅读以下文章以深入了解DTO和分层:
六边形架构(端口/适配器)
这里要提到的是所谓的六边形(端口/适配器)架构[Vernon, 红书第125页]。它非常方便地放置了代表外部(领域和应用程序之外)消费者的数据对象。该架构是DDD通常隐含的分层架构的重要补充。
以下是示例。
除了DB、电子邮件服务等端口/适配器之外,我们还可以定义一个ports/adapters/http/ui/myestore/ShoppingCartResponse.valueobject.ext
(假设我们使用一些虚构的编程语言EXT),其中包含您的UI应用程序MyEStore
将用于显示最终用户的购物车状态的数据。
ShoppingCartResponse.valueobject.ext
由ports/adapters/http/ui/myestore/EStoreHTTP.adapter.ext
创建(在我们的示例中,为简洁起见,它可以是来自REST世界中非常轻巧的HTTP REST API控制器的同义词)。
适配器请求领域服务ShoppingCart.service.ext
获取聚合、实体、其他值对象。然后它从它们中创建所需的ShoppingCartResponse.valueobject.ext
(由自己或使用创建者-工厂、构建器等)。然后将值对象作为HTTP响应发送给消费者。
DTO还是值对象?
您应该根据以下内容决定ShoppingCartResponse
是否为值对象或DTO(.dto.ext
):
我更喜欢从最简单的方法开始,只允许使用值对象,并且仅在出现明确的架构需求时添加DTO。
这种方法既具有很大的灵活性,又使代码设计简洁明了。端口/适配器部分容纳了彼此相关的对象(适配器、VO或DTO及其创建者),并保持应用程序层的清晰,为更相关的应用程序层对象保留空间。