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

多类型Disposition类导出映射switch-case逻辑重构方案咨询

重构方案

针对当前分表实体转导出结构的场景,不需要调整底层库表,以下两种方案都可以解决switch分支膨胀、维护成本高的问题:


方案一:策略模式+统一字段提取接口(推荐)

这个方案完全不侵入现有实体类和数据库结构,将散落在各个switch分支的同类型逻辑收拢,符合开闭原则,后续新增类型只需要加对应实现即可。

  1. 首先定义统一的详情字段提取接口,统一所有导出字段的语义约定,不用关心不同详情类的字段名差异:
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * 不同类型 disposition 详情的导出字段提取器
 */
public interface DispositionDetailExporter {
    // 匹配当前提取器对应的业务类型
    DispositioType matchType();

    // 以下为所有导出需要的字段,默认返回null,无对应字段的类型不需要重写
    default String getLocalBankAccount(Disposition disposition) {return null;}
    default boolean getIsForeignBankAccount(Disposition disposition) {return false;}
    default String getForeignBankAccount(Disposition disposition) {return null;}
    default String getForeignBankSwift(Disposition disposition) {return null;}
    default String getDepartmentName(Disposition disposition) {return null;}
    default String getCustomerName(Disposition disposition) {return null;}
    default String getDocumentNumber(Disposition disposition) {return null;}
    default String getDocumentTitle(Disposition disposition) {return null;}
    default String getDocumentDescription(Disposition disposition) {return null;}
}
  1. 为每个业务类型写对应的实现类,把原来switch里的逻辑全部收拢到对应实现中,比如A类型、C类型(包含isExportable特殊判断)、D类型的实现示例:
// A类型详情提取逻辑
@Component
public class TypeADetailExporter implements DispositionDetailExporter {
    @Override
    public DispositioType matchType() {
        return DispositioType.DispositionA;
    }

    @Override
    public String getLocalBankAccount(Disposition disposition) {
        return disposition.getDispostionDetailsA().getLocalBankAccount();
    }

    @Override
    public boolean getIsForeignBankAccount(Disposition disposition) {
        return disposition.getDispostionDetailsA().isForeignBankAccount();
    }

    @Override
    public String getForeignBankAccount(Disposition disposition) {
        return disposition.getDispostionDetailsA().getForeignBankAccount();
    }

    @Override
    public String getForeignBankSwift(Disposition disposition) {
        return disposition.getDispostionDetailsA().getForeignBankSwift();
    }

    @Override
    public String getDepartmentName(Disposition disposition) {
        return disposition.getDispostionDetailsA().getDepartmentName();
    }
}
// C类型详情提取逻辑,包含isExportable特殊判断
@Component
public class TypeCDetailExporter implements DispositionDetailExporter {
    @Override
    public DispositioType matchType() {
        return DispositioType.DispositionC;
    }

    @Override
    public String getLocalBankAccount(Disposition disposition) {
        DispositionDetailsC details = disposition.getDispostionDetailsC();
        return details.isExportable() ? details.getLocalBankAccount() : null;
    }

    @Override
    public boolean getIsForeignBankAccount(Disposition disposition) {
        DispositionDetailsC details = disposition.getDispostionDetailsC();
        return details.isExportable() && details.isForeignBankAccount();
    }

    @Override
    public String getForeignBankAccount(Disposition disposition) {
        DispositionDetailsC details = disposition.getDispostionDetailsC();
        return details.isExportable() ? details.getForeignBankAccount() : null;
    }

    @Override
    public String getForeignBankSwift(Disposition disposition) {
        DispositionDetailsC details = disposition.getDispostionDetailsC();
        return details.isExportable() ? details.getForeignBankSwift() : null;
    }

    @Override
    public String getDocumentNumber(Disposition disposition) {
        DispositionDetailsC details = disposition.getDispostionDetailsC();
        return details.isExportable() ? details.getDocumentNumber() : null;
    }

    @Override
    public String getDocumentTitle(Disposition disposition) {
        DispositionDetailsC details = disposition.getDispostionDetailsC();
        return details.isExportable() ? details.getDocumentTitle() : null;
    }
}
// D类型详情提取逻辑,无银行类字段直接用接口默认返回值
@Component
public class TypeDDetailExporter implements DispositionDetailExporter {
    @Override
    public DispositioType matchType() {
        return DispositioType.DispositionD;
    }

    @Override
    public String getDepartmentName(Disposition disposition) {
        return disposition.getDispostionDetailsD().getDepartmentName();
    }

    @Override
    public String getCustomerName(Disposition disposition) {
        return disposition.getDispostionDetailsD().getCustomerName();
    }

    @Override
    public String getDocumentDescription(Disposition disposition) {
        return disposition.getDispostionDetailsD().getDocumentDescription();
    }
}
  1. 改造原有Exporter类,启动时自动收集所有提取器实例,构建类型和提取器的映射,完全移除switch逻辑:
@Component
public class Exporter {
    private final Map<DispositioType, DispositionDetailExporter> exporterMap;

    // 如果使用Spring容器,会自动注入所有DispositionDetailExporter的实现类
    public Exporter(List<DispositionDetailExporter> exporterList) {
        this.exporterMap = exporterList.stream()
                .collect(Collectors.toMap(DispositionDetailExporter::matchType, Function.identity()));
    }

    public ExportDataStructure exportDisposition(Disposition disposition){
        ExportDataStructure export = new ExportDataStructure();
        export.setId(disposition.getId());
        DispositionDetailExporter detailExporter = exporterMap.get(disposition.getDispositionType());
        if (detailExporter == null) {
            return export;
        }
        // 统一赋值,无需每个字段写分支判断
        export.setLocalBankAccount(detailExporter.getLocalBankAccount(disposition));
        export.setIsForeignBankAccount(detailExporter.getIsForeignBankAccount(disposition));
        export.setForeignBankAccount(detailExporter.getForeignBankAccount(disposition));
        export.setForeignBankSwift(detailExporter.getForeignBankSwift(disposition));
        export.setDepartmentName(detailExporter.getDepartmentName(disposition));
        export.setCustomerName(detailExporter.getCustomerName(disposition));
        export.setDocumentNumber(detailExporter.getDocumentNumber(disposition));
        export.setDocumentTitle(detailExporter.getDocumentTitle(disposition));
        export.setDocumentDescription(detailExporter.getDocumentDescription(disposition));
        return export;
    }
}

这个方案的优势:

  • 零库表改造,不侵入原有实体类代码,对生产环境无影响
  • 同类型的所有取值逻辑收拢在单个类中,不会散落在各个字段的switch分支里,排查问题只需要找对应类型的实现类
  • 新增业务类型时只需要新增对应的提取器实现类,不需要修改Exporter核心逻辑,不会因为加类型漏改某个字段的switch分支
  • 完美适配字段名不一致、存在特殊取值规则(比如C类型的isExportable判断)的场景,接口层统一语义,实现层做自定义映射

方案二:字段映射配置+反射取值(轻量可选)

如果不想写过多实现类,可以把每个类型的字段映射关系存在枚举或配置文件中,通过反射统一取值赋值:

  1. 定义映射枚举,存储每个类型对应的详情字段名、导出字段和详情字段的对应关系,以及特殊校验规则:
import java.util.Map;
import java.util.function.Predicate;

@Getter
public enum DispositionFieldMapping {
    A(DispositioType.DispositionA,
            "dispositionDetailsA",
            Map.of("localBankAccount","localBankAccount",
                    "isForeignBankAccount","isForeignBankAccount",
                    "foreignBankAccount","foreignBankAccount",
                    "foreignBankSwift","foreignBankSwift",
                    "departmentName","departmentName"),
            details -> true
    ),
    C(DispositioType.DispositionC,
            "dispositionDetailsC",
            Map.of("localBankAccount","localBankAccount",
                    "isForeignBankAccount","isForeignBankAccount",
                    "foreignBankAccount","foreignBankAccount",
                    "foreignBankSwift","foreignBankSwift",
                    "documentNumber","documentNumber",
                    "documentTitle","documentTitle"),
            details -> ((DispositionDetailsC)details).isExportable()
    ),
    D(DispositioType.DispositionD,
            "dispositionDetailsD",
            Map.of("departmentName","departmentName",
                    "customerName","customerName",
                    "documentDescription","documentDescription"),
            details -> true
    );

    private final DispositioType type;
    // Disposition类中存储对应详情的字段名
    private final String detailsFieldName;
    // key:ExportDataStructure的字段名,value:对应详情类的字段名
    private final Map<String, String> exportFieldToDetailField;
    // 导出前置校验,比如C类型的isExportable判断
    private final Predicate<Object> exportCheck;

    DispositionFieldMapping(DispositioType type, String detailsFieldName, Map<String, String> exportFieldToDetailField, Predicate<Object> exportCheck) {
        this.type = type;
        this.detailsFieldName = detailsFieldName;
        this.exportFieldToDetailField = exportFieldToDetailField;
        this.exportCheck = exportCheck;
    }
}
  1. 写通用的反射转换逻辑,根据映射关系自动取值赋值,不需要写任何分支判断。这个方案代码量更少,但反射存在极轻微的性能损耗,复杂逻辑的可读性比方案一差,适合业务规则简单、类型变动频繁的场景。

  • 注意:你提供的示例代码中重复定义了DispositionDetailsC类,第二个类实际应为DispositionDetailsD,实现时注意修正笔误。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.27 22:27:35