脚本宝典收集整理的这篇文章主要介绍了重构聚合支付案例教你如何写出高扩展性易读的代码,脚本宝典觉得挺不错的,现在分享给大家,也给大家做个参考。
人间清醒
以下代码逻辑为:按照不同的支付方式调用不同支付方式的逻辑流程。 痛点:
/**
* 旧的支付
*
* @param mode 模式
* @param payVO 支付签证官
* @return {@link String}
*/
@PostMapping("/old/{mode}")
public String oldPay(@PathVariable("mode") String mode, @RequestBody PayVO payVO) {
switch (mode) {
case "ALIPAY":
// 调用支付宝支付流程逻辑方法
break;
case "WXPAY":
// 调用微信支付流程逻辑方法
break;
case "EBANK":
// 调用E支付流程逻辑方法
break;
default:
return "支付方式未找到!";
}
return "支付成功!";
}
看逻辑和你写的代码八九不离十吧? 当时你的想法可能是“能实现这个需求就行,扩展性是啥?可维护性是啥?关我鸟事”,于是劈里啪啦一千又一千行造就了一个万行类诞生,根据需求的变更,需求的迭代慢慢的发现自己都改不动万行类,这时候咋办?(-v-,程序和人一个能跑就行-。-);
考虑到大部分项目使用了Spring,那咋们今天就用Spring的特性来实现这次重构的需求。
这里DTO定义两个参数:
/**
* 支付dto
*
* @author wentao.wu
* @date 2022/01/05
*/
@Data
public class PayDTO<T> implements Serializable {
/**
* 模式
*/
private String mode;
/**
* 数据
*/
private T data;
}
这里定义好一个支付行为需要做的事情,方法作用解读:
/**
* 支付服务
*
* @author wentao.wu
* @date 2022/01/04
*/
public interface PayService {
/**
* 支付之前
*
* @param payDTO 支付dto
*/
<T> void befor(PayDTO<T> payDTO);
/**
* 执行支付
*
* @param payDTO 支付dto
* @return boolean
*/
<T> boolean invoke(PayDTO<T> payDTO);
/**
* 支付失败后
*
* @param payDTO 支付dto
*/
<T> void errorAfter(PayDTO<T> payDTO);
/**
* 支付成功后
*
* @param payDTO 支付dto
*/
<T> void okAfter(PayDTO<T> payDTO);
}
这里定义注解主要是声明PayService实现类对应了什么方式,用来标注在具体的支付方式实现类中。
/**
* 支付
*
* @author wentao.wu
* @date 2022/01/05
*/
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Pay {
/**
* 模式: WXPAY ,ALIPAY.....
*
* @return {@link String}
*/
String mode();
}
这里主要是保存所有PayService的实现类,后续会通过前端参数传入的支付方式从容器中寻找系统是否支持该支付方式。
/**
* 支付bean容器
*
* @author wentao.wu
* @date 2022/01/05
*/
public class PayBeanContainer {
/**
* bean管理器
*/
public Map<String, PayService> CONTAINER = new HashMap<>(16);
/**
* 添加bean
*
* @param mode 支付方式
* @param bean Bean
*/
public void addBean(String mode, PayService bean) {
if (checkBean(mode)) {
throw new RuntimeException("已存在该业务规则!");
}
CONTAINER.put(mode, bean);
}
/**
* 获取Bean
*
* @param mode 支付方式
* @return {@link PayService}
*/
public PayService getBean(String mode) {
if (!checkBean(mode)) {
throw new RuntimeException("不存在该Bean!");
}
return CONTAINER.get(mode);
}
/**
* 检查Bean是否存在
*
* @param mode 支付方式
* @return boolean
*/
public boolean checkBean(String mode) {
return CONTAINER.containsKey(mode);
}
}
这里通过Spring初始化Bean后将所有PayService的实现类注册到支付容器中,支付方式则对应Pay注解中的mode。
/**
* 支付bean注册表
*
* @author wentao.wu
* @date 2022/01/04
*/
@Slf4j
@Component
public class PayServiceInstantiationAwareBeanPostProcessor implements InstantiationAwareBeanPostProcessor {
@Autowired
private PayBeanContainer payBeanContainer;
/**
* 发布过程实例化后
*
* @param bean 豆
* @param beanName bean的名字
* @return boolean
* @throws BeansException 豆子例外
*/
@Override
public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
if (bean instanceof PayService) {
Pay annotation = bean.getClass().getAnnotation(Pay.class);
payBeanContainer.addBean(annotation.mode(), (PayService) bean);
log.info(" PayBeanContainer.addBean:{}", bean.getClass().getName());
}
return true;
}
}
统一支付流程的规范,并且实现调用的流程,具体子流程由开发自己实现。 当前模板方法主要统一了支付调用流程:
这里定义了大概流程,具体微信支付,支付前,支付,支付后回调需要处理什么逻辑由开发自行实现。
/**
* 支付模板
*
* @author wentao.wu
* @date 2022/01/04
*/
@Component
public class PayTemplate {
@Autowired
private PayBeanContainer payBeanContainer;
/**
* 支付
*
* @param payDTO 支付dto
* @return boolean
*/
public <T> boolean pay(PayDTO<T> payDTO) {
if (!payBeanContainer.checkBean(payDTO.getMode())) {
throw new RuntimeException("平台不支持该支付方式,非法调用!");
}
PayService server = payBeanContainer.getBean(payDTO.getMode());
server.befor(payDTO);
boolean result = server.invoke(payDTO);
if (result) {
server.okAfter(payDTO);
} else {
server.errorAfter(payDTO);
}
return result;
}
}
经过我们上面的铺垫开发实现微信支付只需要统一实现PayService并且声明这个子类为微信支付的具体调用逻辑(@Pay(mode = "WXPAY"))
/**
* wxpay impl
*
* @author wentao.wu
* @date 2022/01/06
*/
@Component
@Slf4j
@Pay(mode = "WXPAY")
public class WXPayImpl implements PayService {
@Override
public <T> void befor(PayDTO<T> payDTO) {
log.info("微信支付前,准备参数等....");
}
@Override
public <T> boolean invoke(PayDTO<T> payDTO) {
log.info("调用微信支付接口提交支付....");
return true;
}
@Override
public <T> void errorAfter(PayDTO<T> payDTO) {
log.info("微信支付失败记录日志....");
}
@Override
public <T> void okAfter(PayDTO<T> payDTO) {
log.info("微信支付成功给用户发送消息通知用户支付成功了....");
}
}
创建前端参数VO:
/**
* 支付VO
*
* @author wentao.wu
* @date 2022/01/05
*/
@Data
public class PayVO implements Serializable {
private String param1;// xx支付需要的参数
}
提供接口给前端调用:
@RestController
@RequestMapping("/pay")
public class PayController {
@Autowired
private PayTemplate payTemplate;
/**
* 支付
*
* @param mode 模式
* @param payVO 支付签证官
* @return {@link String}
*/
@PostMapping("/{mode}")
public String pay(@PathVariable("mode") String mode, @RequestBody PayVO payVO) {
PayDTO<PayVO> payDTO = new PayDTO<>();
payDTO.setMode(mode);
boolean reslult = payTemplate.pay(payDTO);
if (reslult) {
return "支付成功!";
}
return "支付失败!";
}
/**
* 旧的支付
*
* @param mode 模式
* @param payVO 支付签证官
* @return {@link String}
*/
@PostMapping("/old/{mode}")
public String oldPay(@PathVariable("mode") String mode, @RequestBody PayVO payVO) {
switch (mode) {
case "ALIPAY":
// 调用支付宝支付流程逻辑方法
break;
case "WXPAY":
// 调用微信支付流程逻辑方法
break;
case "EBANK":
// 调用E支付流程逻辑方法
break;
default:
return "支付方式未找到!";
}
return "支付成功!";
}
}
Postman调用:http://localhost:7776/pay/WXPAY RequestBody参数为:{"param1":"参数1"} 调用结果:支付成功! 控制台打印日志:
2022-01-06 12:45:37.441 INFO 15276 --- [nio-7776-exec-3] c.g.b.g.service.impl.WXPayImpl : 微信支付前,准备参数等....
2022-01-06 12:45:37.441 INFO 15276 --- [nio-7776-exec-3] c.g.b.g.service.impl.WXPayImpl : 调用微信支付接口提交支付....
2022-01-06 12:45:37.442 INFO 15276 --- [nio-7776-exec-3] c.g.b.g.service.impl.WXPayImpl : 微信支付成功给用户发送消息通知用户支付成功了....
这里我们需要扩展一种新的支付方式不需要改动任何代码,遵守开闭原则,每个类单一职责。
/**
* 支付宝impl
*
* @author wentao.wu
* @date 2022/01/06
*/
@Component
@Slf4j
@Pay(mode = "ALIPAY")
public class AlipayImpl implements PayService {
@Override
public <T> void befor(PayDTO<T> payDTO) {
log.info("支付宝支付前,准备参数等....");
}
@Override
public <T> boolean invoke(PayDTO<T> payDTO) {
log.info("调用支付宝支付接口提交支付....");
return true;
}
@Override
public <T> void errorAfter(PayDTO<T> payDTO) {
log.info("支付宝支付失败记录日志....");
}
@Override
public <T> void okAfter(PayDTO<T> payDTO) {
log.info("支付宝支付成功给用户发送消息通知用户支付成功了....");
}
}
Postman调用:http://localhost:7776/pay/ALIPAY RequestBody参数为:{"param1":"参数1"} 调用结果:支付成功! 控制台打印日志:
2022-01-06 13:49:50.141 INFO 13656 --- [nio-7776-exec-2] c.g.b.g.service.impl.AlipayImpl : 支付宝支付前,准备参数等....
2022-01-06 13:49:50.141 INFO 13656 --- [nio-7776-exec-2] c.g.b.g.service.impl.AlipayImpl : 调用支付宝支付接口提交支付....
2022-01-06 13:49:50.141 INFO 13656 --- [nio-7776-exec-2] c.g.b.g.service.impl.AlipayImpl : 支付宝支付成功给用户发送消息通知用户支付成功了....
源代码地址: https://gitee.com/SimpleWu/blogs-examples/tree/master/grace-pay-case
-.-
以上是脚本宝典为你收集整理的重构聚合支付案例教你如何写出高扩展性易读的代码全部内容,希望文章能够帮你解决重构聚合支付案例教你如何写出高扩展性易读的代码所遇到的问题。
本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
如您有任何意见或建议可联系处理。小编QQ:384754419,请注明来意。