You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

六边形架构下API结构问题:跨域DTO数据获取方案咨询

API结构设计问题:六边形架构下跨领域关联数据的DTO处理

我在API结构设计上遇到了问题。我的API包含Study领域类,它有一个educationLevelId属性,该属性关联AcademicLevel领域类的层级结构。

领域层代码

Study领域

public class Study {
    private final Long id;
    private final Long employeeId;
    private Long educationLevelId;
    //其他属性和方法
}

AcademicLevel领域

public class EducationLevel {
    private final Long id;
    //其他属性和方法
}

public class AcademicLevel {
    private final Long id;
    private List<EducationLevel> educationLevels;
    //其他属性和方法
}

应用层代码

Study领域的DTO

在Study领域的findStudiesByEmployeeIdUseCase中需要返回StudyDTO,但StudyDTO需要来自AcademicLevel领域的academicLevelId属性:

public class StudyDTO {
    private Long id;
    private Long employeeId;
    private Long educationLevelId;
    private Long academicLevelId;
    //其他属性
}

共享服务定义

为此我创建了共享服务接口,实现放在AcademicLevel领域的应用层:

public class AcademicAndEducationLevelIdDTO {
    private Long academicLevelId;
    private Long educationLevelId;
    //Getters
}

public interface FindAcademicLevelIdsByEducationLevelIdsService {
    List<AcademicAndEducationLevelIdDTO> execute(List<Long> educationLevelIds);
}

核心问题

该服务实现依赖领域层的AcademicLevelRepository,但根据六边形架构原则,领域层不应依赖应用层,现在陷入了依赖矛盾。

现有可选方案

方案1:泛型仓库方法

在AcademicLevelRepository中定义泛型方法,通过指定类类型返回结果:

<R> List<R> findAcademicLevelIdsBy(List<Long> educationLevelIds, Class<R> clazz);

仓库实现使用entityManager动态映射结果,这样AcademicLevelRepository不会依赖应用层的DTO。

方案2:领域层内部DTO

在领域层创建内部DTO包,让仓库返回领域内部DTO,再映射为应用层的AcademicAndEducationLevelIdDTO。但我不喜欢这个方案,因为按照六边形架构原则,DTO属于应用层。

优化建议与替代方案

推荐方案:领域层定义值对象(Value Object)

既然academicLevelId和educationLevelId的关联是领域内的核心关联关系,可以在AcademicLevel领域层定义一个值对象来承载这对关联:

// 领域层 - AcademicLevel领域
public record AcademicLevelEducationLevelPair(Long academicLevelId, Long educationLevelId) {}

然后让AcademicLevelRepository返回这个值对象列表:

// 领域层 - AcademicLevel领域
public interface AcademicLevelRepository {
    List<AcademicLevelEducationLevelPair> findAcademicLevelIdsByEducationLevelIds(List<Long> educationLevelIds);
}

这样应用层的服务实现可以调用仓库获取领域值对象,再映射为AcademicAndEducationLevelIdDTO,完全符合六边形架构的依赖规则:领域层不依赖应用层,应用层依赖领域层的定义。

方案1的补充分析

方案1的泛型仓库方法虽然能解决依赖问题,但会让仓库接口变得不够清晰,同时泛型返回会降低代码可读性,后续维护成本较高。如果只是临时解决小问题可以用,但长期来看不如值对象方案更符合领域驱动设计的思想。

为什么不选方案2

方案2把DTO放到领域层,违反了六边形架构中"领域层专注于业务逻辑,不关心外部数据格式"的原则,会污染领域层的纯净性,不推荐。

内容的提问来源于stack exchange,提问作者JUAN PABLO SOLARTE HOYOS

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.14 18:42:37