如何重构多if分支的createSpecification方法以降低认知复杂度?
重构方案降低认知复杂度
针对你遇到的Sonar提示的认知复杂度问题,这里提供两种简单有效的重构方式:
方案一:将字段过滤逻辑拆分为独立私有方法
把每个字段的null判断和Specification构建逻辑抽离到单独的私有方法中,主方法只负责顺序调用这些方法,以此减少主方法内的分支数量:
protected Specification<Test> createSpecification(TestCriteria criteria) { Specification<Test> specification = Specification.where(null); if (criteria == null) { return specification; } specification = applyIdFilter(criteria, specification); specification = applyCustomerNameFilter(criteria, specification); specification = applyAddressFilter(criteria, specification); // 依次添加其他字段的过滤方法调用 return specification; } private Specification<Test> applyIdFilter(TestCriteria criteria, Specification<Test> spec) { return criteria.getId() != null ? spec.and(buildRangeSpecification(criteria.getId(), test_.id)) : spec; } private Specification<Test> applyCustomerNameFilter(TestCriteria criteria, Specification<Test> spec) { return criteria.getCustomerName() != null ? spec.and(buildStringSpecification(criteria.getCustomerName(), Test_.customerName)) : spec; } private Specification<Test> applyAddressFilter(TestCriteria criteria, Specification<Test> spec) { return criteria.getAddress() != null ? spec.and(buildStringSpecification(criteria.getAddress(), Test_.address)) : spec; }
这种方式将每个字段的分支逻辑隔离在子方法中,主方法的认知复杂度会显著降低——主方法内不再有大量独立的if分支,仅保留最外层的null判断和方法调用。
方案二:使用处理器列表批量处理字段
通过定义一个包含所有字段处理逻辑的列表,遍历执行处理逻辑,减少重复的if结构:
import java.util.Arrays; import java.util.List; import java.util.function.Consumer; import java.util.concurrent.atomic.AtomicReference; protected Specification<Test> createSpecification(TestCriteria criteria) { AtomicReference<Specification<Test>> specRef = new AtomicReference<>(Specification.where(null)); if (criteria == null) { return specRef.get(); } List<Consumer<TestCriteria>> filterProcessors = Arrays.asList( crit -> { if (crit.getId() != null) { specRef.updateAndGet(spec -> spec.and(buildRangeSpecification(crit.getId(), test_.id))); } }, crit -> { if (crit.getCustomerName() != null) { specRef.updateAndGet(spec -> spec.and(buildStringSpecification(crit.getCustomerName(), Test_.customerName))); } }, crit -> { if (crit.getAddress() != null) { specRef.updateAndGet(spec -> spec.and(buildStringSpecification(crit.getAddress(), Test_.address))); } } // 添加其他字段的处理器 ); filterProcessors.forEach(processor -> processor.accept(criteria)); return specRef.get(); }
这里用AtomicReference来包装Specification对象,方便在lambda表达式中更新值。遍历处理器列表的方式将多个独立的if分支合并为一个循环,有效降低主方法的认知复杂度。
两种方案都能快速将认知复杂度降到15以下,其中方案一的代码可读性更高,也更便于后续维护。
内容的提问来源于stack exchange,提问作者Berta Voica
相关产品推荐
相关产品推荐

