上一篇博文描述了支付接口存在的问题:https://www.jianshu.com/p/0e801d1874d8。
本篇博文描述我的重构思路。
一、使用简单工厂+策略模式解耦下单接口不同商品的下单逻辑
解耦前创建订单部分代码:
if (商品类型==A) {
A商品下单逻辑,省略百来行代码
} else if (商品类型==B) {
B商品下单逻辑,省略百来行代码
}......
解耦后的uml图如下:
将不同商品的下单逻辑放到AbstractProductPayStrategy下的商品类型对应实现子类中,下单部分的重复代码例如创建订单提取到AbstractProductStrategy父类,实现代码复用。
二、使用责任链重构价格计算逻辑
2.1重构前下单接口价格计算代码:
if (使用了优惠券) {
价格 = 价格 - 优惠券面值;
}
if (参与活动A) {
价格 = 原价 - 活动抵扣金额;
}
if (参与活动B && 商品类型 == A) {
价格 = 价格 x 活动折扣;
}
if (没有使用优惠券) {
// 活动C和活动D不能和优惠券叠加,有互斥关系
if (参与活动C && 商品类型 == B) {
}
if (参与活动D && 商品类型 == C) {
}
}
可以看到价格计算代码中有大量的营销活动逻辑,多种营销活动的优惠有叠加或者互斥关系,而且有的活动只适用于某几种商品,如果全用if else表达的话可读性极差,而且后期要增减营销活动和商品类型时会大量修改以上代码。
2.2使用责任链模式重构以上逻辑后的UML图:
定义一个抽象处理器AbstractActivityHandler,责任链上的每一个活动处理器实现都集成该抽象类,next变量和setNext方法都是责任链模式原生代码,不做赘述。
AbstractActivityHandler的calcPrice用于计算活动优惠价格,所有的活动实现子类都实现calcPrice方法,内部是当前活动的优惠计算逻辑,当计算完当前活动的优惠价格后,调用next.calcPrice()方法,即可将价格计算流转到下一个活动。
当calcPrice入参PriceRequest对象走完责任链上的所有环节后,便返回给调用方,此时的PriceRequest的price属性便是计算好所有营销活动优惠后的价格。
AbstractActivityHandler的callback用于处理第三方支付回调接口的活动后续逻辑,所有的活动实现子类都实现callback方法,内部是当前活动的支付成功处理逻辑,当用户拉起微信或支付宝支付完成,回调后端接口通知支付结果时,callback接口就会调用责任链进行活动后续逻辑处理,例如增加拼团日志,增加分销记录等。
重构后下单接口调用活动责任链计算价格的代码示例如下:
// 假设我要购买课程,课程支持的活动有两个:优惠券和特价。可以将这两个活动组装到责任链中
AbstractActivityHandler c = new CouponHandler();
c.setNext(new SaleHandler());
// 组装计算责任链入参
Request request = new Request();
// 这是商品原价
request.setPrice(100);
// 得到最终需要支付的价格
Request r = c.calcPrice(request);
第一张UML图中我们用策略模式将不同商品的下单逻辑分离在各个Strategy实现类中,例如SubjectPayStrategy只组装课程适用的活动到责任链中。VipPayStrategy只组装vip适用的营销活动到责任链,实现了灵活组装营销活动和营销活动的代码复用。
上面的代码只能实现活动优惠叠加,如果责任链中的活动有互斥关系怎么办呢?
可以看到PriceRequest类中定义了几个属性:calculatedPin 、calculatedSale 、calculatedSell 、calculatedCoupon 、calculatedHelp ,记录已经计算了哪些活动的优惠,如果当前活动和已计算优惠的活动互斥,需要在活动处理器中调过当前活动的优惠计算,代码如下:
public class SaleHandler extends AbstractActivityHandler {
@Override
public Request calcPrice(PriceRequest request) {
// 如果已经计算了优惠券优惠,就不能享受特价优惠
if (request.calculatedCoupon()) {
if (next != null) {
// 直接流转到下一个活动
return next.calcPrice(request);
}
return request;
}
省略计算限时特价优惠代码......
request.setPrice(salePrice);
request.setCalculatedSale(true);
if (next != null) {
// 流转到下一个活动
return next.calcPrice(request);
}
return request;
}
}
商品对应的PayStrategy拿到计算好的价格后,直接创建订单拉起调用第三方下单接口就完成了下单接口的所有操作。下单接口部分到此结束,接下来是支付成功回调接口。
三、使用简单工厂+策略模式解耦下单接口不同商品的支付成功完成订单逻辑
订单支付完成接口和下单接口一样,存在大量的商品类型和活动类型判断代码,用来处理不同商品和不同活动的支付成功后续逻辑,此处可以和下单接口一样,用简单工厂和策略处理,UML图如下:
取到下单接口流转完责任链的PriceRequest中的calculated相关字段信息,即可知道这个订单参与了哪些活动,组装好CallbackRequest,描述参与了哪些活动,经过责任链的callback方法流转,即可执行完成所有活动的支付成功处理逻辑。
以上就是我的支付接口重构思路,如果有不足的地方或者您有更好的方法,欢迎在评论区提出。