如安在Spring Boot项目中奇妙应用战略形式干掉if else!
2019-11-18杂谈搜奇网41°c
A+ A-直入主题
我们都晓得,设想形式(Design Pattern)是先辈们对代码开辟履历的总结,是处置惩罚特定题目的一系列套路。它不是语法划定,而是一套用来进步代码可复用性、可维护性、可读性、妥当性以及安全性的处置惩罚方案。
那末,我们能够都相识过设想形式,但是在项目中怎样运用能够照样会有点迷惑,本日,公司的项目恰好有一个场景来让我运用一个设想形式:战略形式。
场景
关于用户定单充值(定单付出同理),我们都晓得,当今的付出体式格局是异常的多的,比方:付出宝、微信、银联、钱包(各个APP的账户余额)等等。
查询实体Query:
/**
* @author Howinfun
* @desc 查询
* @date 2019/10/22
*/
@Data
public class ChargeQuery {
/** 付出体式格局(ALI/WX/UNION) */
@NotBlank(message = "付出体式格局不能为空",groups = PayWayNotBlank.class)
private String payWay;
/** 充值金额 */
@NotNull(message = "充值金额不能为空",groups = AmountNotNull.class)
private Double amount;
}
Service接口:
/**
* @author Howinfun
* @desc 充电-充值模块
* @date 2019/10/30
*/
public interface ChargeRechargeService {
/**
* 依据不必付出体式格局举行用户余额充值
* @param query
* @return
*/
Result recharge(ChargeQuery query);
/**
* 充值回调
* @param rechargeCallBack
*/
Result rechargeCallBack(RechargeCallBack rechargeCallBack);
}
传统体式格局完成
就是应用if else或许switch来举行前提推断:
/**
* @author Howinfun
* @desc
* @date 2019/10/30
*/
@Service
@AllArgsConstructor
@Slf4j
public class ChargeRechargeServiceImpl implements ChargeRechargeService {
private final CarUserMapper carUserMapper;
private final IncomePaymentMapper incomePaymentMapper;
private final RechargeRecordMapper rechargeRecordMapper;
private final PayWayHandlerContext payWayHandlerContext;
@Override
@Transactional(rollbackFor = Exception.class)
public Result recharge(ChargeQuery query) {
Result result = new Result();
// ......
// ......
if (PayConstant.PAY_WAY_WX.equals(query.getPayWay())){
// 微信
// ......
}else if (PayConstant.PAY_WAY_ALI.equals(query.getPayWay())){
// 付出宝
// ......
}else if (PayConstant.PAY_WAY_UNION_PAY.equals(query.getPayWay())){
// 银联
// ......
}
return result;
}
}
总结:我们能够看到,传统的完成体式格局是异常的笨重的,而且代码异常的不简约,扩展性差。假如我们要接入新的付出体式格局,那末我们只能继续增加 else if。
战略形式
Talk is cheap,show me the code.
我们先看一下,假如运用战略形式,service的代码将变成啥样。
/**
* @author Howinfun
* @desc
* @date 2019/10/30
*/
@Service
@AllArgsConstructor
@Slf4j
public class ChargeRechargeServiceImpl implements ChargeRechargeService {
private final PayWayHandlerContext payWayHandlerContext;
@Override
@Transactional(rollbackFor = Exception.class)
public Result recharge(ChargeQuery query) {
return this.payWayHandlerContext.getHandlerInstance(query.getPayWay()).handler(query);
}
}
emmmm,确实是简朴了不少。不只代码量少了,简约了,而且不再忧郁由于新增付出体式格局而修正serviceImpl的代码了。
下面举行细致的解说:
1、起首,我们须要自定义一个注解,来标识一个付出范例对应的一个处置惩罚器。
/**
* @author Howinfun
* @desc 自定义注解,标识付出范例
* @date 2019/11/2
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public @interface PayWayHandler {
String value();
}
2、接着,笼统一个处置惩罚器,让每一个付出体式格局的处置惩罚器继续此笼统处置惩罚器,完成handle要领:
/**
* @author Howinfun
* @desc 笼统定单范例处置惩罚器
* @date 2019/11/2
*/
public abstract class AbstractPayWayHandler {
/**
*
* @param query
* @return
*/
abstract public Result handler(ChargeQuery query);
}
3、完成类,比方付出宝、微信、银联:
注重:每一个处置惩罚器都要加上@component,交给Spring治理。
/**
* @author Howinfun
* @desc 付出宝付出
* @date 2019/11/2
*/
@Component
@PayWayHandler("ALI")
@Slf4j
@AllArgsConstructor
public class AliPayWayHandler extends AbstractPayWayHandler {
// ....种种依靠
@Override
public Result handler(ChargeQuery query) {
Result result = new Result();
// ......
return result;
}
}
/**
* @author Howinfun
* @desc 微信付出
* @date 2019/11/2
*/
@Component
@PayWayHandler("WX")
@Slf4j
@AllArgsConstructor
public class WxPayWayHandler extends AbstractPayWayHandler {
// ....种种依靠
@Override
public Result handler(ChargeQuery query) {
Result result = new Result();
// ......
return result;
}
}
/**
* @author Howinfun
* @desc 银联付出
* @date 2019/11/2
*/
@Component
@PayWayHandler("UNION")
@Slf4j
@AllArgsConstructor
public class UnionPayWayHandler extends AbstractPayWayHandler {
// ....种种依靠
@Override
public Result handler(ChargeQuery query) {
Result result = new Result();
// ......
return result;
}
}
4、然后最重点的来了,建立一个类,完成ApplicationContextAware接口,重写setApplicationContext要领,然后扫描带有自定义注解@PayWayHandler的Bean,然后存储起来,轻易Service的猎取。
/**
* @author Howinfun
* @desc
* @date 2019/11/2
*/
@Component
public class PayWayHandlerContext implements ApplicationContextAware {
@Autowired ApplicationContext applicationContext;
/** key为PayWay,value为class*/
private static final Map<String,Class> handlerMap = new HashMap<>(10);
public AbstractPayWayHandler getHandlerInstance(String payType){
Class clazz = handlerMap.get(payType);
if (clazz == null){
throw new CustomDeniedException("暂不支撑此付出体式格局");
}
return (AbstractPayWayHandler) applicationContext.getBean(clazz);
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
// 遍历带有PayTypeHandler解释的类
Map<String,Object> beans = applicationContext.getBeansWithAnnotation(PayWayHandler.class);
if (beans != null && beans.size() > 0) {
for (Object serviceBean : beans.values()) {
String payType = serviceBean.getClass().getAnnotation(PayWayHandler.class).value();
handlerMap.put(payType, serviceBean.getClass());
}
}
}
}
总结:到此,ServiceImpl可依据前端传过来的payWay来挑选对应的handler来处置惩罚。我应用了战略形式简化了冗杂的 if else 代码,而且扩展性得到了大大的提拔,不再忧郁由于付出体式格局的新增而修正营业代码。