昨天 CR 代码,被吐槽了👇的代码,自己也看不下去:
// 福利配置校验
configs.forEach(x -> doValidate(x, welfareSendCreateBO));
这段又臭又长的Switch
/**
* 发送校验配置信息
*
* @param configDO
* @param welfareSendCreateBO 校验参数
*/
private void doValidate(WelfareConfigDO configDO, WelfareSendCreateBO welfareSendCreateBO) {
switch (configDO.getCode()) {
case WelfareConfigConstants.CURRENCIES:
checkCurrencies(configDO.getValue(), welfareSendCreateBO);
break;
case WelfareConfigConstants.AMOUNT_MAX:
checkAmountMax(configDO.getValue(), welfareSendCreateBO);
break;
case WelfareConfigConstants.AMOUNT_MIN:
checkAmountMin(configDO.getValue(), welfareSendCreateBO);
break;
case WelfareConfigConstants.CURRENCY_MIN:
checkCurrencyMin(configDO.getValue(), welfareSendCreateBO);
break;
case WelfareConfigConstants.CURRENCY_MAX:
checkCurrencyMax(configDO.getValue(), welfareSendCreateBO);
break;
case WelfareConfigConstants.CURRENCY_MAX_NUM:
checkCurrencyMaxNum(configDO.getValue(), welfareSendCreateBO.getSendNum());
break;
case WelfareConfigConstants.CURRENCY_MIN_NUM:
checkCurrencyMinNum(configDO.getValue(), welfareSendCreateBO.getSendNum());
break;
case WelfareConfigConstants.FLOATING_LOWERBOUND:
checkFloatingLowerBound(configDO.getValue(), welfareSendCreateBO);
break;
case WelfareConfigConstants.FLOATING_UPPERBOUND:
checkFloatingUpperBound(configDO.getValue(), welfareSendCreateBO);
break;
default:
break;
}
}
功能是为了校验参数,不同的参数有不同的规则,可是规则越长,分支越多,代码丑死,被diss的心悦臣服,写的太赶都没有考虑代码的扩展性。
早上起来重构了下代码,采用策略模式接口的形式进行调用。
- 抽象一个配置项的处理器
- 处理配置项
- 获取配置项处理器名称 (唯一且约定的)
/**
* 发送福利参数校验
* <p>
* Created by Reeta on 2019-07-12
*/
public interface IConfigHandler {
/**
* 发送福利配置校验,校验值是否满足配置值
*
* @param configValue 配置值
* @param checkValue 校验值
*/
void handleTheConfig(String configValue, WelfareSendCreateBO checkValue);
/**
* 返回校验配置项的名称
*
* @return WelfareConfigConstants
*/
String getConfigHandleName();
}
- 不同的配置项去实现处理逻辑,就列举了两个,不一一列举了
/**
* 校验币种是否在配置值中
* <p>
* Created by Reeta on 2019-07-12
*/
@Component
public class CurrenciesConfigHandler implements IConfigHandler {
@Override
public void handleTheConfig(String value, WelfareSendCreateBO currency) {
boolean anyMatch = Arrays.stream(value.split(",")).anyMatch(s -> s.equals(currency.getCurrency()));
AssertUtil.assertTrue(anyMatch, "Invalid currency to send welfare", WelfareErrorCode.BIZ_ERROR);
}
@Override
public String getConfigHandleName() {
return WelfareConfigConstants.CURRENCIES;
}
}
/**
* 单个福利发送数量上限
* <p>
* Created by Reeta on 2019-07-13
*/
@Component
public class CurrencyMaxConfigHandler implements IConfigHandler {
@Override
public void handleTheConfig(String configValue, WelfareSendCreateBO checkValue) {
int to = checkValue.getSendAmount().divide(new BigDecimal(checkValue.getSendNum()), 20, BigDecimal.ROUND_DOWN)
.compareTo(new BigDecimal(configValue));
AssertUtil.assertTrue(to < 1, WelfareErrorCode.WELFARE_CURRENCY_MAX);
}
@Override
public String getConfigHandleName() {
return WelfareConfigConstants.CURRENCY_MAX;
}
}
- 使用简单工厂模式 将配置项的处理器放入List 容器内,通过配置项的唯一code值获取不同的处理器
/**
* 福利配置处理器工厂类
* <p>
* Created by Reeta on 2019-07-13
*/
@Component
public class ConfigHandlerFactory {
@Autowired
List<IConfigHandler> configHandlers;
/**
* 通过配置值返回配置处理器
*
* @param code 配置的唯一code
* @return 配置处理器
*/
public IConfigHandler getConfigHandler(String code) {
AssertUtil.assertNotBlank(code, "ConfigHandler name is empty!", CommonErrorCode.INNER_ERROR);
AssertUtil.assertNotNull(configHandlers, "ConfigHandler is null", CommonErrorCode.INNER_ERROR);
for (IConfigHandler configHandler : configHandlers) {
if (code.equalsIgnoreCase(configHandler.getConfigHandleName())) {
return configHandler;
}
}
throw new BaseException("No ConfigHandler was found for name: " + code, CommonErrorCode.SYSTEM_EXCEPTION);
}
}
- 最后 干掉Switch 语句 :) ~~~~
// 福利配置校验
configs.forEach(x -> {
AssertUtil.assertNotBlank(x.getValue(),
x.getCode() + "cannot be empty", CommonErrorCode.SYSTEM_EXCEPTION);
configHandlerFactory.getConfigHandler(x.getCode()).handleTheConfig(x.getValue(), welfareSendCreateBO);
});