一、理论基础
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(">>>>>>>>银联支付组装参数开始<<<<<<<<<<<<");
........
}
上一篇: 支付功能-分布式事务介绍/单例模式介绍
若对你有帮助,欢迎关注!!点赞!!评论!!