支付功能实战(3):基于Token+策略+工厂模式+反射实现支付类型选择以及支付信息提交

一、理论基础

1.1、为什么要使用策略模式

策略+工厂+反射 :实现解决if else多重判断问题

1.2、什么是策略模式

策略模式是对算法的包装,是把使用算法的责任和算法本身分割开来,委派给不同的对象管理。常把一个系列的算法包装到一系列的策略类里面,作为一个抽象策略类的子类。

详细介绍参考:什么是策略模式

1.3、什么时候选择策略模式

(1)如果一个系统有很多类,他们的区别仅仅在于他们的行为,可以使用策略模式动态地让一个对象在许多行为中选择一种行为;

(2)如果不用策略模式只能用多重选择模式的场景;

1.3、支付服务角色的划分(有点类似模板方法的抽象模板和具体模板,多了个环境角色)

这个模式涉及到三个角色:

环境(Context)角色:负责具体运作。持有一个Strategy的引用。

● 抽象策略(Strategy)角色:相当于接口层。这是一个抽象角色,通常由一个接口抽象类实现。此角色给出所有的具体策略类所需的接口。

● 具体策略(ConcreteStrategy)角色:相当于具体实现类。包装了相关的算法或行为。

 

比如下图:

payStrategy有大体的基本算法的骨架给定义好,它下面的子类各有各的算法,但是各子类的返回类型是相同的

 

支付大体流程说明:

一般用户点下单点击支付后都会跳转到支付页面——>选择支付类型(微信/支付宝/银联等)——>选择每个支付类型他们的支付表单可能都不同,这里用策略模式选哪个返回哪个的提交参数,输入密码点击确认——>就到支付回调了,支付成功与否在回调里判断。

1.4、不适用多个if判断而使用策略模式原因

  • 聚合支付平台对接多个不同的支付接口,但是支付接口大体实现思路都是相同的,唯一实现接口不同;
  • 可以重构聚提交参数,根据不同渠道(支付接口)去获取不同支付接口它需要提交的表单参数。

1.5、根据不同渠道生成不同方案——摆脱if else

根据不同的渠道(支付接口),返回不同的form表单提交参数。它的大体流程都是提交表单

(1)通过渠道ID channelId,去表里找到class name

(2) 使用payToken获取支付参数

(3)通过反射机制拿到接口

(4)执行具体的支付渠道的算法获取html表单数据 策略设计模式 使用java反射机制 执行具体方法

1.6、骨架图

 

二、用户支付订单具体实现(支付后的回调请看:异步回调

 

2.1、策略模式——接口和环境角色Context

用户选择支付类型时调用接口:传入渠道ID和支付Token:

注意!注意!注意!策略模式最大卖点是返回值类型都相同

/**
 * @description: 根据不同的渠道id(支付方式) 返回不同的支付提交表单
 */
public interface PayContextService {
	@GetMapping("/toPayHtml")
	public BaseResponse<JSONObject> toPayHtml(String channelId, String payToken);

}

以下接口实现所做的事情:

  • (1)使用Token,从Redis中获取支付参数;
  • (2)使用工厂模式,使用Java的反射机制初始化子类,进而初始化对象,把初始化对象放ConcurrentHashMap集合里面;
  • (3)使用策略模式,抽象策略,和具体策略(具体支付实现)
@RestController
public class PayContextServiceImpl extends BaseApiService<JSONObject> implements PayContextService {
	@Autowired
	private PaymentChannelMapper paymentChannelMapper;
	@Autowired
	private PayMentTransacInfoService payMentTransacInfoService;

	@Override
	public BaseResponse<JSONObject> toPayHtml(String channelId, String payToken) {

		// 1.使用渠道id获取渠道信息 classAddres
		PaymentChannelEntity pymentChannel = paymentChannelMapper.selectBychannelId(channelId);
		if (pymentChannel == null) {
			return setResultError("没有查询到该渠道信息");
		}
		// 2.使用payToken获取支付参数
		BaseResponse<PayMentTransacDTO> tokenByPayMentTransac = payMentTransacInfoService
				.tokenByPayMentTransac(payToken);
		if (!isSuccess(tokenByPayMentTransac)) {
			return setResultError(tokenByPayMentTransac.getMsg());
		}
//3.通过反射机制拿到接口
		PayMentTransacDTO payMentTransacDTO = tokenByPayMentTransac.getData();
		// 4.执行具体的支付渠道的算法获取html表单数据 策略设计模式 使用java反射机制 执行具体方法
		String classAddres = pymentChannel.getClassAddres();
		PayStrategy payStrategy = StrategyFactory.getPayStrategy(classAddres);
//5.直接执行子类执行方法
		String payHtml = payStrategy.toPayHtml(pymentChannel, payMentTransacDTO);
		// 4.直接返回html
		JSONObject data = new JSONObject();
		data.put("payHtml", payHtml);
		return setResultSuccess(data);
	}

}

支付接口共同实现行为方法:

工厂设计模式的使用:

在基类中定义创建对象的一个接口,让子类决定实例化哪个类。工厂方法让一个类的实例化延迟到子类中进行

参考:工厂方法模式

//初始化不同的策略行为
public class StrategyFactory {
	private static Map<String, PayStrategy> strategyBean = new ConcurrentHashMap<String, PayStrategy>();
	// 使用java反射机制初始化类
	public static PayStrategy getPayStrategy(String classAddres) {
		try {
			if (StringUtils.isEmpty(classAddres)) {
				return null;
			}
			PayStrategy beanPayStrategy = strategyBean.get(classAddres);
			if (beanPayStrategy != null) {
				return beanPayStrategy;
			}
			// 1.使用Java的反射机制初始化子类
			Class<?> forName = Class.forName(classAddres);
			// 2.反射机制初始化对象
			PayStrategy payStrategy = (PayStrategy) forName.newInstance();
			strategyBean.put(classAddres, payStrategy);
			return payStrategy;
		} catch (Exception e) {
			return null;
		}
	}
}

2.2、抽象策略——通常是接口或者抽象类

它的子类就是什么银联支付、支付宝支付、微信支付等,每个子类就是一种策略实现,

根据渠道ID不同选择不同的策略实现

public interface PayStrategy {

	/**
	 * @param paymentChannel
	 *            渠道<br>
	 * @param payToken
	 *            支付令牌<br>
	 * @return
	 */
	String toPayHtml(PaymentChannelEntity paymentChannel, PayMentTransacDTO payMentTransacDTO);

 

2.3、具体策略

比如支付宝支付、微信支付、银联支付。每一个都是具体策略

这里以银联支付为例:

@Slf4j
@Component
public class UnionPayStrategy implements PayStrategy {
	@Override
	public String toPayHtml(PaymentChannelEntity paymentChannel, PayMentTransacDTO payMentTransacDTO) {
		log.info(">>>>>>>>银联支付组装参数开始<<<<<<<<<<<<");
........

}

 

 

  上一篇: 支付功能-分布式事务介绍/单例模式介绍

  下一篇: 支付功能-模板+多线程+MQ实现支付异步回调

若对你有帮助,欢迎关注!!点赞!!评论!!

  • 3
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值