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

如何减少对象字段更新校验中的if语句?

优化重复if校验的几种方案

你的需求是校验DTO与实体对象的字段差异并收集变更字段,当前大量重复if的写法确实冗余,以下是几种可行的优化方案:

方案1:函数式接口封装校验逻辑(推荐)

通过封装字段的获取逻辑和对应名称,把重复的校验逻辑抽象成通用规则,遍历执行即可。这种方式性能无损耗,可读性和维护性都很强。

/**
 * 检查公司信息是否有更新
 *
 * @param company 从数据库获取的待更新公司数据
 * @param companyDTO 可能包含更新数据的DTO
 * @return 包含变更字段名的列表
 */
private List<String> getChanges(Company company, CompanyDTO companyDTO) {
    List<String> changes = new ArrayList<>();

    // 定义所有字段的校验规则:DTO字段获取器、实体字段获取器、变更记录用的字段名
    List<FieldCheckRule> checkRules = Arrays.asList(
        new FieldCheckRule(companyDTO::getName, company::getName, COMPANY_NAME),
        new FieldCheckRule(companyDTO::getShortName, company::getShortName, COMPANY_SHORTNAME),
        new FieldCheckRule(companyDTO::getAddress, company::getAddress, COMPANY_ADDRESS),
        new FieldCheckRule(companyDTO::getTaxNumber, company::getTaxNumber, COMPANY_TAX_NUMBER),
        new FieldCheckRule(companyDTO::getFirmId, company::getFirmId, COMPANY_FIRM_ID),
        new FieldCheckRule(companyDTO::getBankName, company::getBankName, COMPANY_BANK_NAME),
        new FieldCheckRule(companyDTO::getBankAccountNumber, company::getBankAccountNumber, COMPANY_BANK_ACCOUNT_NUMBER),
        new FieldCheckRule(companyDTO::getInternalComment, company::getInternalComment, COMPANY_INTERNAL_COMMENT),
        new FieldCheckRule(companyDTO::getEnabled, company::getEnabled, ENABLED)
    );

    // 统一执行校验逻辑
    for (FieldCheckRule rule : checkRules) {
        Object dtoValue = rule.dtoGetter.get();
        if (dtoValue != null && !dtoValue.equals(rule.entityGetter.get())) {
            changes.add(rule.fieldName);
        }
    }

    return changes;
}

// 内部辅助类,封装单字段的校验规则
private static class FieldCheckRule {
    final Supplier<Object> dtoGetter;
    final Supplier<Object> entityGetter;
    final String fieldName;

    FieldCheckRule(Supplier<Object> dtoGetter, Supplier<Object> entityGetter, String fieldName) {
        this.dtoGetter = dtoGetter;
        this.entityGetter = entityGetter;
        this.fieldName = fieldName;
    }
}

方案2:反射遍历字段(适合字段极多的场景)

如果字段数量非常多,不想逐个编写getter,可以用反射自动遍历字段。但反射会有一定性能开销,且需要处理字段名映射和异常。

private List<String> getChanges(Company company, CompanyDTO companyDTO) throws IllegalAccessException {
    List<String> changes = new ArrayList<>();

    // 定义DTO字段名 -> 实体字段名 -> 变更记录字段名的映射
    Map<String, Map.Entry<String, String>> fieldMapping = new HashMap<>();
    fieldMapping.put("name", new AbstractMap.SimpleEntry<>("name", COMPANY_NAME));
    fieldMapping.put("shortName", new AbstractMap.SimpleEntry<>("shortName", COMPANY_SHORTNAME));
    fieldMapping.put("address", new AbstractMap.SimpleEntry<>("address", COMPANY_ADDRESS));
    // 其他字段依次添加...

    for (Map.Entry<String, Map.Entry<String, String>> entry : fieldMapping.entrySet()) {
        String dtoFieldName = entry.getKey();
        String entityFieldName = entry.getValue().getKey();
        String changeFieldName = entry.getValue().getValue();

        // 获取DTO字段值
        Field dtoField = CompanyDTO.class.getDeclaredField(dtoFieldName);
        dtoField.setAccessible(true);
        Object dtoValue = dtoField.get(companyDTO);

        if (dtoValue != null) {
            // 获取实体字段值并对比
            Field entityField = Company.class.getDeclaredField(entityFieldName);
            entityField.setAccessible(true);
            Object entityValue = entityField.get(company);
            if (!dtoValue.equals(entityValue)) {
                changes.add(changeFieldName);
            }
        }
    }

    return changes;
}

方案3:借助第三方对象映射库

如果你的项目已经在使用ModelMapper、MapStruct这类对象映射库,可以扩展它们的功能来收集变更字段。比如ModelMapper可以通过自定义转换器记录差异,这种方式适合同时需要对象映射和变更记录的场景,避免重复开发。

方案选择建议

  • 字段数量适中时,优先用方案1:代码清晰、性能好,新增字段只需加一行规则,维护成本低。
  • 字段数量极多且维护成本优先时,考虑方案2:减少重复代码,但要注意反射的性能和异常处理。
  • 已有对象映射需求时,用方案3:复用现有依赖,避免重复造轮子。

内容的提问来源于stack exchange,提问作者Aron.jt

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.17 06:11:17