最近在对项目中支付模块的重构,经过三个月的努力,让项目的支付焕然一新。过程是艰辛的,结果是完美的,哈哈。接下来分享一下在重构支付整个流程设计和实现。
为什么要独立模块?随时公司业务不断的发展,项目需要对接不同的支付方式和支付渠道,随着时间的推移,对接的支付方式不断增加,同时支付模块的代码量不断的增加, 很多相同的代码。更严重的是每新增一种支付方式或者支付渠道,工作量也随之在增加。同时业务需求也在变化,老的支付模块就不能适应需求, 即使通过改造去适应都需要花费很多时间。最后经过小组开会讨论,准备对支付中心进行重构,要求不同的支付方式必须独立成模块,能独立运行,不同的支付方式可以随机组合。讨论了一周,也确定了重构的方案。接下来就是开始动手干。
设计思路:创建一个支付中心, 所有终端发起支付,必须先经过支付中心, 支付中心接收到支付请求后, 对发起支付前的基本参数进行检查, 参数检查通过后, 根据不同的支付方式,使用arouter进行路由分发到对应的支付sdk, 具体的支付sdk负责执行支付操作。支付的结果通过回调的方式返还给发起支付的终端。 支付中心提供一个默认的(包含所有的支付方式)支付路由分发器。当然接入支付中心的终端,可以通过配置文件实现自己的支付路由分发。
具体实现
通之前集成的支付方式不难发现,不同的支付方式之间,支付参数和支付成功返回的数据差别不大或者说基本相同。所以首先我们需要对支付请求参数和支付返回的数据进行封装
/**
* 支付必须的参数
*/
public class PayCenterPayParams implements Serializable {
/**
* 支付来源类型
*/
@PaySourceType.IntDef
private int paySourceType = PaySourceType.DEFAULT;
/**
* 支付方式
*/
@PaySupportType.IntDef
private int payType;
/**
* 支付、退款、刷新
* 默认是支付
*/
@PayIntention.IntDef
private int payIntention = PayIntention.PAY;
/**
* 业务模块与支付模块协商【实际支付信息都存在这个json数据中】
*/
private String parameterJson;
/**
* 是否是重试
*/
private boolean isRetry;
}
//-----------------------------------------------------------------------------
/**
* 支付结果
*/
public class PayResults {
@PaySourceType.IntDef
private int paySourceType;
/**
* 业务模块与支付模块协商【实际返回的支付数据】
*/
private String resultJson;
private boolean needPrint;
/**
* 记录服务器返回的失败原因
*/
private String reasonStr;
/**
* 是否是重试
*/
private boolean isRetry;
/**
* 分步支付时,各模块已经支付的金额,用于回调时来判断是否支付完成,
* 若为null,则认为支付完成
*/
private BigDecimal payedAmount;
}
从代码中可以看出, 支付请求和支付结果中的实际参数我们使用String类型的json字符串代表,通过json字符串在不同模块之间进行传输。至于json字符串包含什么数据, 这个只需要和服务器端约定好即可。
接下来需要为支付结果定义一个回调接口,将支付的结果返回给调用者
/**
* 支付通用回调
*/
public interface PayCallBack {
/**
* 支付结果回调
* @param code {@link PayCenterConstants}
* @param results {@link PayResults}
*/
void onPayCallBack(@PayCenterConstants.PayIntDef int code, PayResults results);
}
约定好支付请求和支付结果数据,接下来我们需要定义支付的公共接口。所有的支付方式都需要实现该公共接口中的方法。接口定义了支付所需要的行为,当然我们肯定也会为该公共接口提供默认的实现或者抽象类, 进步进行封装。
/**
* 支持中心提供的方法,包括发起读取支付范本,调取支付面板,具体支付实现由各模块自己实现
* 流程为:
* 1.各业务模块向支付中心发起读取支付范本的请求,支付中心回传结果;
</>
* 2.业务模块可向支付中心请求调起支付面板,也可自己实现
</>
* 3.业务模块向支付中心指定支付方式并发起支付
* 4.对开发票及抹零操作由各模块自己实现
*/
public interface IPayCenter extends IProvider {
/**
* 发起支付
*
* @param activity 调起的页面
* @param payParams 支付参数
* @param payCallBack 支付回调
*/
void pay(Activity activity, PayCenterPayParams payParams, PayCallBack payCallBack);
/**
* 添加支付代理操作,用于在{@link IPayCenter#pay(Activity, PayCenterPayParams, PayCallBack)}执行前和执行后的操作
*
* @param proxy 代理器{@link IProxy}
*/
void setPayProxy(IPayProxy proxy);
/**
* 添加的除支付外的其他操作,用于业务与底层的交互
*
* @param context 调起者
* @param operateParams {@link PayCenterPayParams}参数封装
* @param operateCallback {@link OperateCallBack}
*/
void operate(Context context, PayCenterPayParams operateParams, OperateCallBack operateCallback);
/**
* 做一些销毁操作
*/
void destroy();
interface IPayProxy extends IProxy {
}
}
定义一个抽象的类, 对公共接口进行实现,将接口定义的行为隐藏起来。不同的支付方式只需要实现该抽象类中的抽象方法即可
/**
* 支付基础操作
*/
public abstract class BasePayProvider implements IPayCenter {
protected PayCallBack payCallBack;
protected PayCenterPayParams payParams;
@Override
public void pay(Activity activity, PayCenterPayParams payParams, PayCallBack payCallBack) {
this.payParams = payParams;
this.payCallBack = payCallBack;
checkPayParams();
pay(activity, payParams);
}
@Override
public void init(Context context) {
//TODO:若需要初始化操作,子类重写即可
}
@Override
public void operate(Context context, PayCenterPayParams operateParams, O