Entity与DTO互转映射器:除Service层外的更优放置位置?
除Service层外,是否存在更优的位置放置Entity与DTO互转的映射器?
我们团队一直将Entity与DTO的互转映射器(Mapper)放在Service层,但渐渐发现这种做法可能不是最优解。
目前的实现中,Service层包含大量以DTO为参数或返回DTO的方法,Controller层直接调用这些方法时流程很顺畅。但当ServiceA需要调用ServiceB的方法时,会出现完全没必要的对象转换操作:
// A SERVICE IMPL public Integer save(ADto aDto) { AEntity aEntity = aMapper.toEntity(aDto); BEntity bEntity = aEntity.getBEntity(); BDto bDto = bMapper.toDto(bEntity); bService.save(bDto); aEntity = aRepository.save(aEntity); return aEntity.getId(); } // B SERVICE IMPL public Integer save(BDto bDto) { BEntity bEntity = bMapper.toEntity(bDto); bEntity = bRepository.save(bEntity); return bEntity.getId(); }
在这个场景里,以下两次转换完全可以避免:
bMapper.toDto(bEntity);bMapper.toEntity(bDto);
为了绕开这个问题,我们不得不给每个Service新增一批“重复”方法:
Integer save(Entity entity) Integer saveFromDto(Dto dto) Integer save(List<Entity> entities) Integer saveFromDtos(List<Dto> dtos) Entity findById(Integer id) Dto findByIdToDto(Integer id) List<Entity> findAll() List<Dto> findAllToDto()
现在我们考虑了两种重构方案:
方案一:将Mapper迁移至Controller层
Controller层负责处理请求响应,本身就需要知晓返回的数据格式,而Service层可以不用承担DTO转换的职责。
- 优点:无需为每个Service新增Adapter类
- 缺点:Controller层会增加额外的转换逻辑
方案二:创建Service的Adapter层并在Controller中使用
Adapter层的核心职责是:
- 调用映射器将DTO转换为Entity,再调用接收Entity参数的Service方法
- 调用映射器将Entity转换为DTO,再将结果返回给Controller层
- 优点:Controller层无需新增转换逻辑,保持职责单一
- 缺点:需要为每个Service单独新增对应的Adapter类
这两种重构思路的核心目标都是让Service层摆脱DTO处理的额外工作,专注于业务逻辑与Entity的操作。
内容的提问来源于stack exchange,提问作者Paul Marcelin Bejan
相关产品推荐
相关产品推荐

