模式简介
策略模式是一种行为型模式,它定义一系列的算法,将每一种算法封装起来并可以相互替换使用,策略模式让算法独立于使用它的客户端应用而独立变化。策略模式适合解决当程序出现多个不同分支,而且每个分支的逻辑还比较复杂的场景。
需求分析
在笔者参与的交易系统中,需要支持多种支付方式,如支付宝、微信、现金、银行卡等等,每一种支付方式的处理逻辑都不尽相同,对接的系统也不一样,所以程序中需要根据用户选择的支付方式来确定走哪一种支付方式的流程,根据需求描述就能看出,很适合用策略模式来解决这个问题,每一种支付方式就是一个策略,每个策略封装自己的支付逻辑。
详细设计
我们来看设计类图:
简单介绍一下逻辑:
- PayHandler的pay方法处理整体的支付逻辑
- 首先构建PayStrategyContext上下文对象,构建完成后,上下文会包含支付单、支付明细、抹零模型、支付请求等对象
- 上下文对象本身会作为参数传递后面的具体支付策略中,图中只列出了两个具体的策略,支付宝支付和微信支付
- 支付策略PayStrategy接口包含两个方法,一个是用于完成支付动作的pay方法,另一个是用来匹配支付方式的support的方法
- PayHandler会根据用户选择的支付方式调用selectStrategy方法在内部维护的PayStrategy集合中选择出匹配的策略设置到 PayStrategyContext中并调用PayStrategyContext的pay方法完成支付操作
- 在完成支付后,将支付结果的一些信息更新到支付单中,并发送支付结果消息
代码实现
下面我们来看代码实现:
/**
* 支付策略
*/
public interface PayStrategy {
/**
* 支付
*/
void pay(PayStrategyContext context);
/**
* 匹配支付方式
*/
boolean support(String payType);
}
/**
* 支付策略环境
*/
@Slf4j
public class PayStrategyContext {
@Getter
private PayRecord pay;
@Getter
private PayDetail detail;
@Getter
private PayDetail cutDetail;
@Getter
private PayRequest payRequest;
private PayStrategy strategy;
public PayStrategyContext(PayRecord pay, PayDetail detail, PayRequest payRequest) {
this.pay = pay;
this.detail = detail;
this.payRequest = payRequest;
this.cutDetail = ...;
// ...
}
public PayStrategyContext setStrategy(PayStrategy strategy) {
this.strategy = strategy;
return this;
}
public void pay() {
strategy.pay(this);
}
}
/**
* 支付平台支付策略
*/
@Slf4j
@Service
public class AlipayPayStrategy implements PayStrategy {
@Override
public boolean support(String payType) {
return "Alipay".equals(payType);
}
@Override
public void pay(PayStrategyContext context) {
// 调用支付宝服务...
// ...
}
}
/**
* 微信支付策略
*/
@Slf4j
@Service
public class WechatPayStrategy implements PayStrategy {
@Override
public void pay(PayStrategyContext context) {
// 对接微信支付服务...
// ...
}
@Override
public boolean support(String payType) {
return "WechatPay".equals(payType);
}
}
/**
* 支付处理
*/
@Slf4j
@Service
public class PayHandler {
@Resource
private List<PayStrategy> payStrategyList;
/**
* 支付
*/
public PayResponse pay(long payId, PayRequest request) {
PayRecord pay = fromDB(payId);
for (PayDetail detail : pay.getDetails()) {
new PayStrategyContext(pay, detail, request)
.setStrategy(selectPayStrategy(detail.getPayType()))
.pay();
}
update(pay, pay.getDetails());
sendMessages(buildMessages(pay));
return buildResponse(pay, request);
}
/**
* 根据支付方式选择支付策略
*/
private PayStrategy selectPayStrategy(String payType) {
return payStrategyList.stream()
.filter(s -> s.support(payType))
.findAny()
.orElseThrow(() -> new RuntimeException("支付方式不支持"));
}
/**
* 构建支付消息
*/
private List<Message> buildMessages(PayRecord pay) {
List<Message> list = Lists.newArrayList();
// 构建消息
return list;
}
/**
* 支付后更新支付信息
*/
private void update(Payrecord pay, List<PayDetail> details) {
// DB更新
}
}
总结
这种设计的好处在于我们统一了所有支付方式的支付流程,由PayHandler进行封装和处理,而每个支付方式之间不同的逻辑由具体的策略类来实现,中间由context环境类进行交互,这样后续再扩展其他支付方式时,不会影响其他支付方式,也不需要修改原来的支付流程,整体扩展性很好,维护起来也比较方便。