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

如何将Lombok @Data类作为参数传入公共函数实现代码复用?

提取重复数据转换逻辑的几种实现方案

这个场景我太熟了——一堆结构相似的Lombok @Data类,一堆换汤不换药的接口方法,就差个通用逻辑来收口!下面给你几个实用的实现思路,从手写泛型到工具类都有,你可以根据自己的场景选:

方案一:泛型方法 + Supplier(类型安全,推荐)

这是最直接的手写方案,核心是用泛型定义公共转换逻辑,通过Supplier传入目标类的实例化方式,既避免反射,又保证类型安全。

步骤:

  1. 提取公共的转换逻辑到泛型方法中
  2. 每个业务方法只需要传入原始数据和目标类的构造引用

示例代码:

// 假设原始数据类是RawData,业务参数类是SomeParam
public class DataService {

    // 公共转换方法:泛型T代表目标@Data类
    private <T> T convertRawData(RawData rawData, Supplier<T> targetCreator) {
        T target = targetCreator.get();
        // 这里是你重复的转换逻辑,所有目标类通用
        target.setUserId(rawData.getUserId());
        target.setCreateTime(rawData.getCreateTime());
        target.setAmount(rawData.getAmount());
        // ... 其他相同的字段映射
        return target;
    }

    // 原来的业务方法简化成这样
    public DataForMSDForAdvanceRequest fetchDataMSDForAdvanceRequest(SomeParam param) {
        RawData rawData = getRawDataFromSource(param); // 原始数据获取逻辑(比如查DB/调接口)
        return convertRawData(rawData, DataForMSDForAdvanceRequest::new);
    }

    public DataForMSDForAnotherRequest fetchDataMSDForAnotherRequest(SomeParam param) {
        RawData rawData = getRawDataFromSource(param);
        return convertRawData(rawData, DataForMSDForAnotherRequest::new);
    }

    // 原始数据获取的公共方法
    private RawData getRawDataFromSource(SomeParam param) {
        // 实际的原始数据获取逻辑
        return new RawData();
    }
}

优点:类型安全、无反射开销、代码简洁,每个业务方法只需要一行调用。
注意:确保你的Lombok @Data类有无参构造(默认会生成,除非你手动加了@AllArgsConstructor但没加@NoArgsConstructor)。

方案二:泛型方法 + 反射(无需传入构造引用)

如果不想每个业务方法都传构造引用,可以用反射自动创建目标类实例,但要注意异常处理和性能开销。

示例代码:

public class DataService {

    private <T> T convertRawData(RawData rawData, Class<T> targetClass) {
        try {
            // 通过反射创建目标实例
            T target = targetClass.getDeclaredConstructor().newInstance();
            // 公共转换逻辑
            target.setUserId(rawData.getUserId());
            target.setCreateTime(rawData.getCreateTime());
            // ...
            return target;
        } catch (Exception e) {
            throw new RuntimeException("Failed to create target DTO instance", e);
        }
    }

    // 业务方法调用
    public DataForMSDForAdvanceRequest fetchDataMSDForAdvanceRequest(SomeParam param) {
        RawData rawData = getRawDataFromSource(param);
        return convertRawData(rawData, DataForMSDForAdvanceRequest.class);
    }
}

优点:调用时只需要传Class对象,无需构造引用;
缺点:有反射开销,且如果目标类没有无参构造会抛出异常,类型安全性不如方案一。

方案三:模板方法模式(适合未来有扩展需求)

如果以后某个业务的转换逻辑可能有细微调整,可以用模板方法模式,把公共逻辑放在抽象类,子类负责实例化目标类。

示例代码:

// 抽象模板类
public abstract class AbstractDataFetcher<T> {

    public T fetch(SomeParam param) {
        RawData rawData = getRawData(param);
        T target = createTarget();
        convertRawData(rawData, target);
        return target;
    }

    // 子类实现:创建目标DTO实例
    protected abstract T createTarget();

    // 公共转换逻辑(如果某子类需要调整,可以改成protected让子类重写)
    private void convertRawData(RawData rawData, T target) {
        target.setUserId(rawData.getUserId());
        target.setCreateTime(rawData.getCreateTime());
        // ...
    }

    private RawData getRawData(SomeParam param) {
        // 原始数据获取逻辑
        return new RawData();
    }
}

// 具体业务实现类
public class MSDForAdvanceFetcher extends AbstractDataFetcher<DataForMSDForAdvanceRequest> {
    @Override
    protected DataForMSDForAdvanceRequest createTarget() {
        return new DataForMSDForAdvanceRequest();
    }
}

// 使用方式
public class DataService {
    public DataForMSDForAdvanceRequest fetchDataMSDForAdvanceRequest(SomeParam param) {
        return new MSDForAdvanceFetcher().fetch(param);
    }
}

优点:扩展性好,未来如果某个业务需要修改转换逻辑,只需要重写对应的方法;
缺点:需要创建多个子类,代码量比泛型方法多。

方案四:用Bean映射工具(零手写转换逻辑,强烈推荐)

如果你的转换逻辑只是简单的字段映射(字段名一致或有规律),直接用MapStruct、ModelMapper这类工具,完全不用自己写转换代码,工具会在编译期自动生成高效的映射实现。

以MapStruct为例:

  1. 引入MapStruct依赖(Maven/Gradle)
  2. 定义映射接口:
@Mapper
public interface RawDataMapper {
    // 单例实例,直接调用
    RawDataMapper INSTANCE = Mappers.getMapper(RawDataMapper.class);

    // 定义每个DTO的映射方法
    DataForMSDForAdvanceRequest toMSDForAdvance(RawData rawData);
    DataForMSDForAnotherRequest toMSDForAnother(RawData rawData);
    // 其他DTO的映射方法...
}
  1. 业务方法简化:
public class DataService {
    public DataForMSDForAdvanceRequest fetchDataMSDForAdvanceRequest(SomeParam param) {
        RawData rawData = getRawDataFromSource(param);
        return RawDataMapper.INSTANCE.toMSDForAdvance(rawData);
    }
}

优点:零手写转换逻辑、编译期生成代码(性能和手写一样)、支持自定义映射规则;
缺点:需要引入第三方依赖,但对于字段映射场景来说,这绝对是最省心的方案。


内容的提问来源于stack exchange,提问作者Max

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 10:06:33