业务背景:
最近有同事在做门禁未生效预警系统。审核提交的代码时,发现了一段熟悉的内容,内容如下。
这段代码看着很眼熟,查阅了一下,发现之前悦荟在之前优化其它服务的时候优化过这段代码,暂时就不追究为什么这段代码竟然存在于多个服务中了,还是尽早改掉就好。通过阅读代码,发现按照上次的经验,从根源处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代码,适用表驱动的方式进行解决。即通过某种映射关系,将逻辑表达式用表格的方式表示;再使用表格查找的方式,找到某个输入所对应的处理函数,适用这个处理函数进行运算。除表驱动的方式,还可以考虑使用反射、策略模式+注解等多种方式处理。
当然,最好的方式还是在最初设计的时候,就做好充分的考虑和结构设计,从根源上避免产生这样的代码。
浙公网安备 33010602011771号