直入主题
咱们都知道,设计模式(Design Pattern)是前辈们对代码开发经验的总结,是解决特定问题的一系列套路。它不是语法规定,而是一套用来提升代码可复用性、可维护性、可读性、稳健性以及安全性的解决方案。 那么,咱们可能都了解过设计模式,可是在项目中怎么使用可能仍是会有点疑惑,今天,公司的项目恰好有一个场景来让我使用一个设计模式:策略模式。前端
场景
关于用户订单充值(订单支付同理),咱们都知道,现今的支付方式是很是的多的,例如:支付宝、微信、银联、钱包(各个APP的帐户余额)等等。 查询实体Query:java
/** * @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; } }
<font color="red">总结:咱们能够看到,传统的实现方式是很是的笨重的,并且代码很是的不简洁,扩展性差。假如咱们要接入新的支付方式,那么咱们只能继续添加 else if。</font>微信
策略模式
Talk is cheap,show me the code. 咱们先看一下,若是使用策略模式,service的代码将变成啥样。app
/** * @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的代码了。ide
下面进行详细的讲解: 一、首先,咱们须要自定义一个注解,来标识一个支付类型对应的一个处理器。微信支付
/** * @author Howinfun * @desc 自定义注解,标识支付类型 * @date 2019/11/2 */ @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited public @interface PayWayHandler { String value(); }
二、接着,抽象一个处理器,让每一个支付方式的处理器继承此抽象处理器,实现handle方法:this
/** * @author Howinfun * @desc 抽象订单类型处理器 * @date 2019/11/2 */ public abstract class AbstractPayWayHandler { /** * * @param query * @return */ abstract public Result handler(ChargeQuery query); }
三、实现类,例如支付宝、微信、银联: 注意:每一个处理器都要加上@component,交给Spring管理。spa
/** * @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; } }
四、而后最重点的来了,建立一个类,实现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()); } } } }
<font color="red">总结:到此,ServiceImpl可根据前端传过来的payWay来选择对应的handler来处理。我利用了策略模式简化了繁杂的 if else 代码,而且扩展性获得了大大的提高,再也不担忧由于支付方式的新增而修改业务代码。</font>