Mapstruct实现Road到两类Dto转换时如何避免重复逻辑符合DRY原则
Mapstruct 多Dto场景下复用转换逻辑的可行方案
方案一:抽离公共业务逻辑,拆分筛选与转换步骤(推荐)
你原有代码中重复的核心是从Road中筛选符合条件的Point的逻辑,把这部分抽成公共方法即可完全复用,仅保留不同Dto的转换逻辑:
@Mapper(componentModel = "spring") public interface MyMapper { @Mapping(target = "lPlace", source = "road", qualifiedByName = "PointToLPlace") @Mapping(target = "uPlace", source = "road", qualifiedByName = "PointToUPlace") RoadWithloUnPlaceDto map(Road road); @Mapping(target = "loadingPlace", source = "road", qualifiedByName = "PointToLPlaceSmall") @Mapping(target = "uPlace", source = "road", qualifiedByName = "PointToUPlaceSmall") RoadWithLUPlaceSmallDto mapToRoadWithLUPlaceSmallDto(Road road); // 抽离公共的筛选Point逻辑,所有转换场景复用 default Optional<Point> getMatchPointByOperation(Road road, OperationType operationType) { return Optional.ofNullable(road) .map(Road::getPoints) .filter(points -> !CollectionUtils.isEmpty(points)) .flatMap(points -> points.stream() .sorted(Comparator.comparing(Point::getOrder)) .filter(point -> isAllowed(point.getOperations(), operationType)) .findFirst() ); } @Named("PointToLPlace") default RoadAddressDto mapLPlace(Road road) { return getMatchPointByOperation(road, OperationType.L) .map(this::mapRoadAddress) .orElse(null); } @Named("PointToLPlaceSmall") default RoadAddressSmallDto mapLPlaceSmall(Road road) { return getMatchPointByOperation(road, OperationType.L) .map(this::mapRoadAddressSmall) .orElse(null); } // UPlace的两个转换方法同理,复用getMatchPointByOperation即可 // 省略其余转换方法... }
这个方案无多余转换步骤,性能最优,核心业务逻辑仅需维护一份。
方案二:复用原有转换方法,新增Dto互转逻辑
如果RoadAddressDto和RoadAddressSmallDto字段是包含关系,你可以让Mapstruct自动生成二者的转换逻辑,直接复用原有@Named方法:
@Mapper(componentModel = "spring") public interface MyMapper { @Mapping(target = "lPlace", source = "road", qualifiedByName = "PointToLPlace") @Mapping(target = "uPlace", source = "road", qualifiedByName = "PointToUPlace") RoadWithloUnPlaceDto map(Road road); // 用expression调用原有转换方法,再转成SmallDto @Mapping(target = "loadingPlace", expression = "java(toSmallDto(mapLPlace(road)))") @Mapping(target = "uPlace", expression = "java(toSmallDto(mapUPlace(road)))") RoadWithLUPlaceSmallDto mapToRoadWithLUPlaceSmallDto(Road road); // Mapstruct会自动生成该方法的实现,按字段名匹配转换 RoadAddressSmallDto toSmallDto(RoadAddressDto dto); // 原有@Named方法完全保留不用修改 @Named("PointToLPlace") default RoadAddressDto mapLPlace(Road road) { return Optional.ofNullable(road) .map(Road::getPoints) .filter(point -> !CollectionUtils.isEmpty(points)) .flatMap( points-> points.stream() .sorted(Comparator.comparing(Point::getOrder)) .filter(point-> isAllowed(point.getOperations(), OperationType.L)) .findFirst() ).map(this::mapRoadAddress) .orElse(null); } // 省略其余方法... }
这个方案不用修改原有转换逻辑,开发成本更低,仅多了一次Dto互转的开销,适合性能要求不高的场景。
内容的提问来源于stack exchange,提问作者Matexon
相关产品推荐
相关产品推荐

