六边形架构中服务层修改方法返回DTO的合理性咨询
六边形架构中服务层修改方法返回DTO的合理性咨询
嘿,这问题其实是六边形架构(端口适配器模式)里很常见的边界职责困惑,我来给你捋捋~
首先明确说:你想改成服务方法返回DTO、把接口仅用于依赖注入的思路是合理的,但要注意调整职责边界,别把领域层和应用层的活儿混在一起
先回忆下六边形架构的核心:它的本质是把核心领域逻辑和外部依赖(比如API、数据库)彻底隔离开。其中「端口」分为两类:
- 驱动端口:外部系统(比如你的API控制器)调用领域逻辑的入口,就是你定义的
ICreateProduct这类接口,它们是面向领域的,应该只处理领域模型 - 被驱动端口:领域逻辑调用外部依赖(比如数据库)的出口,比如数据库访问接口
再看你的代码现状:你当前的ProductService其实更像是一个应用服务——它的职责就是协调领域逻辑,同时处理外部和领域之间的数据转换(也就是领域模型转DTO),这完全是应用服务该干的事儿!
你之前的问题出在:原本应该放在应用层的DTO转换,不小心想塞到领域层的接口里了,导致冲突。现在调整成「应用服务依赖领域接口(用于解耦注入),然后对外暴露返回DTO的方法」,刚好契合六边形架构的设计:
具体调整建议
- 让领域层保持纯净:
ICreateProduct、IUpdateProduct这些驱动端口,以及它们的实现(真正的领域服务),都只处理Product领域模型,不要出现任何DTO的影子——这样领域逻辑才不会被外部细节污染。 - 应用服务承担转换职责:你的
ProductService作为应用服务,不需要实现那些领域接口,而是依赖它们的实现,然后在方法里完成「DTO转领域模型」或者「领域模型转DTO」的工作,对外暴露给API控制器调用的方法都返回DTO。
调整后的代码大概是这样:
public class ProductService { private final ICreateProduct createProduct; private final IUpdateProduct updateProduct; private final IRetrieveProduct retrieveProduct; private final IDeleteProduct deleteProduct; public ProductService(ICreateProduct createProduct, IUpdateProduct updateProduct, IRetrieveProduct retrieveProduct, IDeleteProduct deleteProduct) { this.createProduct = createProduct; this.updateProduct = updateProduct; this.retrieveProduct = retrieveProduct; this.deleteProduct = deleteProduct; } public boolean deleteProductById(Long id) { return deleteProduct.deleteProductById(id); } public GetAllProductsDTO getAllProducts() { List<ProductDto> products = retrieveProduct.getAllProducts().stream() .map(ProductMapper::toDto) .collect(Collectors.toList()); return new GetAllProductsDTO(products); } public ProductDto getProductById(Long id) { Product product = retrieveProduct.getProductById(id) .orElseThrow(() -> new RuntimeException("¡Product not found!")); return ProductMapper.toDto(product); } public ProductDto updateProduct(Long id, ProductDto productDto) { // 先把外部传来的DTO转成领域模型 Product product = ProductMapper.toDomain(productDto); Product updatedProduct = updateProduct.updateProduct(id, product) .orElseThrow(() -> new RuntimeException("¡Product not found!")); // 再把更新后的领域模型转成DTO返回 return ProductMapper.toDto(updatedProduct); } public ProductDto createProduct(ProductDto productDto) { Product product = ProductMapper.toDomain(productDto); Product createdProduct = createProduct.createProduct(product); return ProductMapper.toDto(createdProduct); } }
额外的边界提示
从你提供的项目文件夹结构来看,已经区分了不同层级,继续保持这个划分:
- DTO放在适配器层(比如api模块),属于外部边界的一部分
- 领域模型、驱动接口(
ICreateProduct等)放在领域层 - 应用服务放在应用层,作为连接外部和领域的桥梁
这样调整后,既解决了你之前的转换错误问题,又完美契合六边形架构的解耦思想——接口依然用来做依赖注入(解耦应用服务和领域实现),同时领域层不会被外部的DTO污染,职责划分清晰。
备注:内容来源于stack exchange,提问作者Frank2497
相关产品推荐
相关产品推荐

