业务背景:
最近有同事在做门禁未生效预警系统。审核提交的代码时,发现了一段熟悉的内容,内容如下。
这段代码看着很眼熟,查阅了一下,发现之前悦荟在之前优化其它服务的时候优化过这段代码,暂时就不追究为什么这段代码竟然存在于多个服务中了,还是尽早改掉就好。通过阅读代码,发现按照上次的经验,从根源处ThresholdInfoData的结构进行重新设计优化,可能不好修改,设计的地方会比较多。于是考虑采用一种简洁快速的方式,先优化掉这种if else过多的情况——表驱动的方式。
修改前代码:
private void setThresholdValue(ThresholdInfoData thresholdInfoData, net.sf.json.JSONArray thresholds) { if (thresholds.isEmpty()) { logger.info("thresholds is null"); return; } int thresSize = thresholds.size(); for (int j = 0; j < thresSize; j++) { if (thresholds.getJSONObject(j).has(Constant.VALUE)) { String threshold_desc = thresholds.getJSONObject(j).getString(Constant.THRESHOLD_DESC); double value = Double.parseDouble(thresholds.getJSONObject(j).getString(Constant.VALUE)); int validityValue = Constant.ZERO; validityValue = thresholds.getJSONObject(j).get("validity") == null ? validityValue : thresholds.getJSONObject(j).getInt("validity"); value = validityValue == 1 ? Constant.TEN_THOUSAND : value; if (threshold_desc.equals(Constant.OPENINGRATE)) { thresholdInfoData.setOpeningRate(value); } else if (threshold_desc.equals(Constant.COMPLE_TOTAL_ERROR_THRESHOLD)) { thresholdInfoData.setCompileError(value); thresholdInfoData.setCompileValidity(validityValue); } else if (threshold_desc.equals(Constant.CMTRICS_UNSAFE_FUNC_THRESHOLD)) { thresholdInfoData.setCscheckerUnsafe(value); thresholdInfoData.setCscheckerUnsafeValidity(validityValue); } else if (threshold_desc.equals(Constant.CMETRICS_REDUNDANT_CODE_TOATL_THRESHOLD)) { thresholdInfoData.setCscheckerIf0(value); thresholdInfoData.setCscheckerIf0Validity(validityValue); } else if (threshold_desc.equals(Constant.STATIC_ERROR)) { thresholdInfoData.setStatiError(value); thresholdInfoData.setStatiErrorValidity(value); } else if (threshold_desc.equals(Constant.SOURCEMONITOR_NEW_METHOD_COMPLEXITY_THRESHOLD)) { thresholdInfoData.setSourcemonitorComplexity(value); } else if (threshold_desc.equals(Constant.SOURCEMONITOR_NEW_METHOD_STATEMENT_THRESHOLD)) { thresholdInfoData.setSourcemonitorStatement(value); } else if (threshold_desc.equals(Constant.CMETRICS_CODE_DUPLICATION_RATIO_THRESHOLD)) { thresholdInfoData.setSimianDuplicationpercent(value); thresholdInfoData.setSimianDuplicationpercentValidity(validityValue); } else if (threshold_desc.equals(Constant.CMETRICS_FILE_DUPLICATION_RATIO_THRESHOLD)) { thresholdInfoData.setMetricRepeatFilesRate(value); thresholdInfoData.setMetricRepeatFilesRateValidity(validityValue); } else if (threshold_desc.equals(Constant.LLT_TC_CHANGED_COVERAGE_THRESHOLD)) { thresholdInfoData.setLltChangedCoverage(value); } else if (threshold_desc.equals(Constant.LLT_TC_PASS_PERCENT_THRESHOLD)) { thresholdInfoData.setLltPassPercent(value); } } } }
修改后的代码:
private void setThresholdValue(ThresholdInfoData thresholdInfoData, net.sf.json.JSONArray thresholds) { if (thresholds.isEmpty()) { logger.info("thresholds is null"); return; } int thresSize = thresholds.size(); for (int j = 0; j < thresSize; j++) { if (thresholds.getJSONObject(j).has(Constant.VALUE)) { String threshold_desc = thresholds.getJSONObject(j).getString(Constant.THRESHOLD_DESC); double value = Double.parseDouble(thresholds.getJSONObject(j).getString(Constant.VALUE)); int validityValue = Constant.ZERO; validityValue = thresholds.getJSONObject(j).get("validity") == null ? validityValue : thresholds.getJSONObject(j).getInt("validity"); value = validityValue == 1 ? Constant.TEN_THOUSAND : value; Map<String, BiConSumer<Double, Integer>> actionMappings = getComparisionTable(thresholdInfoData); try { actionMappings.get(threshold_desc).accept(value, validityValue); } catch (NullPointerException e) { logger.warn("get" + threshold_desc + " is null"); } } } } // 生成阈值描述和不同赋值方法的对照表 private Map<String, BiConsumer<Double, Integer>> getComparisionTable(ThresholdInfoData thresholdInfoData) { Map<String, BiConsumer<Double, Integer>> actionMappings = new HashMap<>(); actionMappings.put(Constant.OPENNINGRATE, (a, b) -> {thresholdInfoData.setOpeningRate(a);}); actionMappings.put(Constant.COMPILE_TOTAL_ERROR_THRESHOLD, (a, b) -> { thresholdInfoData.setCompileError(a); thresholdInfoData.setCompileValidity(b); }); actionMappings.put(Constant.CSCHECKER_UNSAFE_FUNC_THRESHOLD, (a, b) -> { thresholdInfoData.setCscheckUnsafe(a); thresholdInfoData.setCscheckerUnsafeValidity(b); }); actionMappings.put(Constant.CMTRICS_REDUNDANT_CODE_TOATL_THRESHOLD, (a, b) -> { thresholdInfoData.setCscheckerIf0(a); thresholdInfoData.setCscheckerIf0Validity(b); }); actionMappings.put(Constant.STATIC_ERROR, (a, b) -> { thresholdInfoData.setStatiError(a); thresholdInfoData.setStatuErrorValidity(b); }); actionMappings.put(Constant.SOURCEMONITOR_NEW_METHOD_COMPLEXITY_THRESHOLD, (a, b) -> { thresholdInfoData.setSourcemonitorComplexity(a); }); actionMappings.put(Constant.SOURCEMONITOR_NEW_METHOD_STATEMNET_THRESHOLD, (a, b) -> { thresholdInfoData.setSourcemonitorStatement(a); }); actionMappings.put(Constant.CMETRICS_CODE_DUPLICATION_RATIO_THRESHOLD, (a, b) -> { thresholdInfoData.setSimianDuplicationpercent(a); thresholdInfoData.setSimianDuplicationpercentValidity(b); }); actionMappings.put(Constant.CMETRICS_FILE_DUPLICATION_RATIO_THRESHOLD, (a, b) -> { thresholdInfoData.setMetricRepeatFilesRate(a); thresholdInfoData.setMetricRepeatFilesRateValidity(b); }); actionMappings.put(Constant.LLT_TC_CHANGED_COVERAGE_THRESHOLD, (a, b) -> { thresholdInfoData.setLltChangedCoverage(a); }); actionMappings.put(Constant.LLT_TC_PASS_PERCENT_THRESHOLD, (a, b) -> { thresholdInfoData.setLltPassPercent(a); }); return actionMappings; }
总结:
对于上述这种逻辑表达模式固定的if else代码,适用表驱动的方式进行解决。即通过某种映射关系,将逻辑表达式用表格的方式表示;再使用表格查找的方式,找到某个输入所对应的处理函数,适用这个处理函数进行运算。除表驱动的方式,还可以考虑使用反射、策略模式+注解等多种方式处理。
当然,最好的方式还是在最初设计的时候,就做好充分的考虑和结构设计,从根源上避免产生这样的代码。