DDD - 如何在应用层重用代码?
DDD - How to reuse code in Application layer?
如何在没有映射的情况下复用应用层的代码?
让我们使用 AddOrder(OrderDto) 方法创建一个应用程序服务 OrderService。
该方法由 rest api 使用。控制器方法调用 OrderService.AddOrder(OrderDto) 并将 OrderDto 参数映射到 Order 实体。然后将 Order 实体添加到存储库中。映射在那里完成,因为 OrderService 和 AddOrder 是一个应用程序接口。
最好重用代码并不仅从控制器调用 OrderService.AddOrder(orderDto),而且从 OrderService 中的另一个方法甚至从另一个应用程序服务调用 OrderService.AddOrder(orderDto)。
但是,在调用另一个应用程序方法之前,总是需要在应用程序服务方法内部从实体映射到 DTO,然后将结果从 DTO 映射回实体。
=> 同层无用映射。随着系统变得越来越大,它最终会到处映射到 DTO。不好。
最好避免内部映射,只在应用程序界面的顶部进行映射。
我们可以编写一个服务,在参数中接受域模型(实体)而不是 DTO:OrderDomainService.AddOrder(order).
这解决了“映射问题”。领域服务可以相互调用,无需映射,应用服务也可以调用领域服务。但是,这意味着领域服务必须使用基础设施层的存储库来加载数据,因为我们将代码从应用程序服务方法移到了领域服务方法。这会创建从领域层到基础设施层的依赖关系。
=> 错误的依赖关系。 Infrastructure 应该依赖于 Domain,而不是 Domain on Inrastructure。
如何解决?
应用程序服务不应包含带有域模型类型参数的方法。
域服务无法使用存储库。
那么可复用代码写到哪里呢?
或者我错了,域服务可以使用存储库。通过域层中的接口,它不会直接依赖于基础设施层。
然而,它最终会以一个控制器方法调用一个应用程序服务方法调用一个域服务方法。
我认为在重用逻辑方面,您正朝着领域服务迈进。应用程序服务适用于编排特定用例,并且仅以正确的顺序调用不同的操作。领域逻辑应该总是在领域层。
关于基础设施依赖:为了在 DDD(或干净的架构)中使用存储库,存储库接口 应该位于 领域层,而这些接口的具体实现位于基础结构层。
那么应用层和领域层都应该依赖于接口而不是基础设施层。
The domain service can't use repository.
所以它可以通过依赖于存储库接口来使用存储库,而具体的基础设施存储库是在依赖注入之后在运行时注入的。
However then it would end up with a controller method calling an application service method calling an domain service method.
如果应用程序服务没有理由,因为没有真正的编排要求,那么在让控制器直接调用域 类 时,至少不要破坏任何依赖关系规则,例如如果用例太简单并且不需要 API 层(这里是控制器)和领域层之间的抽象。但我通常更喜欢使用应用程序服务,因为它们使领域层独立于该外层,并允许领域层和 API 层相互独立发展。
如何在没有映射的情况下复用应用层的代码?
让我们使用 AddOrder(OrderDto) 方法创建一个应用程序服务 OrderService。 该方法由 rest api 使用。控制器方法调用 OrderService.AddOrder(OrderDto) 并将 OrderDto 参数映射到 Order 实体。然后将 Order 实体添加到存储库中。映射在那里完成,因为 OrderService 和 AddOrder 是一个应用程序接口。
最好重用代码并不仅从控制器调用 OrderService.AddOrder(orderDto),而且从 OrderService 中的另一个方法甚至从另一个应用程序服务调用 OrderService.AddOrder(orderDto)。
但是,在调用另一个应用程序方法之前,总是需要在应用程序服务方法内部从实体映射到 DTO,然后将结果从 DTO 映射回实体。
=> 同层无用映射。随着系统变得越来越大,它最终会到处映射到 DTO。不好。
最好避免内部映射,只在应用程序界面的顶部进行映射。 我们可以编写一个服务,在参数中接受域模型(实体)而不是 DTO:OrderDomainService.AddOrder(order).
这解决了“映射问题”。领域服务可以相互调用,无需映射,应用服务也可以调用领域服务。但是,这意味着领域服务必须使用基础设施层的存储库来加载数据,因为我们将代码从应用程序服务方法移到了领域服务方法。这会创建从领域层到基础设施层的依赖关系。
=> 错误的依赖关系。 Infrastructure 应该依赖于 Domain,而不是 Domain on Inrastructure。
如何解决?
应用程序服务不应包含带有域模型类型参数的方法。 域服务无法使用存储库。
那么可复用代码写到哪里呢?
或者我错了,域服务可以使用存储库。通过域层中的接口,它不会直接依赖于基础设施层。 然而,它最终会以一个控制器方法调用一个应用程序服务方法调用一个域服务方法。
我认为在重用逻辑方面,您正朝着领域服务迈进。应用程序服务适用于编排特定用例,并且仅以正确的顺序调用不同的操作。领域逻辑应该总是在领域层。
关于基础设施依赖:为了在 DDD(或干净的架构)中使用存储库,存储库接口 应该位于 领域层,而这些接口的具体实现位于基础结构层。
那么应用层和领域层都应该依赖于接口而不是基础设施层。
The domain service can't use repository.
所以它可以通过依赖于存储库接口来使用存储库,而具体的基础设施存储库是在依赖注入之后在运行时注入的。
However then it would end up with a controller method calling an application service method calling an domain service method.
如果应用程序服务没有理由,因为没有真正的编排要求,那么在让控制器直接调用域 类 时,至少不要破坏任何依赖关系规则,例如如果用例太简单并且不需要 API 层(这里是控制器)和领域层之间的抽象。但我通常更喜欢使用应用程序服务,因为它们使领域层独立于该外层,并允许领域层和 API 层相互独立发展。