一、現(xiàn)有支付接口存在什么問題
早期公司為了搶占市場快速迭代魄梯,遺留下來一屁股的技術(shù)債務(wù)桨螺,其中以支付寶、微信酿秸、平臺幣購買接口最為厲害灭翔,無數(shù)的價格計算、營銷活動(助力允扇、限時特價缠局、拼團则奥、優(yōu)惠券等等)、商品類型判斷代碼交織在一個接口中狭园,造成后期維護成本巨大读处,看不懂鲜戒、不敢改猎唁。
業(yè)務(wù)邏輯層偽代碼示意:
1.平臺幣下單:
public void coinPay() {
100行支付校驗代碼和一大堆if else
200行營銷活動判斷代碼
商品類型判斷,以及價格計算著摔,500行代碼
創(chuàng)建訂單完成訂單50行代碼
扣除平臺幣
增加流水記錄
}
2.支付寶下單
public void aliPay() {
100行支付校驗代碼和一大堆if else
200行營銷活動判斷代碼
商品類型判斷绎谦,以及價格計算管闷,500行代碼
創(chuàng)建訂單40行代碼
調(diào)用第三方支付sdk,得到預(yù)付單信息返回
}
3.微信下單:
同支付寶下單窃肠,幾乎除了調(diào)用支付sdk代碼外都是復(fù)制粘貼包个。
支付完成回調(diào)接口也和下單接口一樣,以上代碼摻雜了五六種商品類型判斷和五六種活動類型判斷冤留,活動存在互斥和共存關(guān)系碧囊,如此復(fù)雜的邏輯全用if else堆砌,后期要上手維護時纤怒,代碼的畫風(fēng)是這樣的:
// 正常購買
boolean notPinActivity = "null".equals(pinTaskId);
if (notPinActivity)
{
if (goodsInfo.getType() == CommonConstants.PRODUCT_TOPIC) // 如果是專題糯而,則添加子課程的購買關(guān)系
{
saveTopicSubjects(productId, userId);
}
if (goodsInfo.getType() == CommonConstants.PRODUCT_SUBJECT
|| goodsInfo.getType() == CommonConstants.PRODUCT_TOPIC) // 非問診訂單才添加購買關(guān)系
{
UserBuySubject userBuySubject = new UserBuySubject();
userBuySubject.setId(CommonUtil.getUuid());
userBuySubject.setUserId(userId);
userBuySubject.setSubjectId(productId);
userBuySubject.setCreateTime(new Date());
userBuySubject.save();
}
else if (goodsInfo.getType() == CommonConstants.PRODUCT_DIAGNOSIS)
{
Diagnosis diagnosis = Diagnosis.dao.findById(productId);
order.setServiceEndTime(
DateUtil.addSecond(new Date(), diagnosis.getDuration()));
}
else if (goodsInfo.getType() == CommonConstants.PRODUCT_VIP)
{
order = vipService.buyVip(order, userId, productId);
//如果購買VIP時存在分銷人,則加入分銷邏輯,ibos定時退款6-12小時內(nèi)
if(StrKit.notBlank(fromUserId) && !fromUserId.equals("null"))
{
ActivitySellRecord sellRecord = new ActivitySellRecord();
ActivitySell sell = goodsInfoService.findActivitySell(productId);
//獲取設(shè)置的返利金額
//TODO 這里是用實際支付的金額的50% 返利泊窘, 如果用后臺設(shè)置的金額熄驼,需要考慮學(xué)農(nóng)幣購買的情況
/*int sellCommision = vipService.getSellCommision(productId, sell.getFee());*/
if(null != sell && CommonConstants.DEFAULT_STATUS_ENABLE == sell.getStatus())
{
sellRecord.setSellId(sell.getId());
sellRecord.setSellUser(fromUserId);
sellRecord.setBuyUser(userId);
sellRecord.setOrderId(order.getId());
sellRecord.setStatus(CommonConstants.FALSE);
// 以前的線下分銷計算規(guī)則
// int amount = Integer.parseInt(cash_fee) / 2;//固定50%
// sellRecord.setFee(amount < 100 ? 100 : amount);
int amount = Integer.parseInt(cash_fee);
sellRecord.setFee(activityService.
calcSellFee(amount, sell.getFeeType(), sell.getFee(), order.getPayType()));
sellRecord.save();
}
}
}
}
// 拼團活動購買
else
{
log.info("拼團支付成功!進入拼團處理邏輯烘豹!userId:" + userId + ",pin_task_id:" + pinTaskId
+ ",subject_id:" + productId);
int pinProductType = activityService.getPinProductTypeByGoodsType(goodsInfo.getType());
pinTaskId = activityService.pin(userId, pinTaskId, productId,
order.getOrderNo(), source, appletFormId, pinProductType);
order.setDesc(pinTaskId);
}
以上畫風(fēng)代碼延綿五百行瓜贾。
以上代碼存在的幾個問題##:
1.可讀性差
主干邏輯不清晰,不看上個把小時不知道這幾百行代碼做了什么吴叶。
2.可擴展性差
新增一種商品或者活動阐虚,要全面修改代碼,不符合開閉原則蚌卤。
3.代碼冗余度高
同樣的代碼在每一種支付方式的接口都寫了一遍实束,修改的時候要修改三處。
二逊彭、我想要一個什么樣的支付接口
2.1 可讀性好
主干邏輯清晰咸灿,一目了然這個接口核心邏輯走了哪幾步,每一步分別做了什么侮叮。
2.2 可擴展性好
后期加入一個商品或者加入一個活動避矢,只需要新增代碼,不需要修改歷史代碼。
2.3 復(fù)用性強
公共代碼抽取出來审胸,各個支付接口復(fù)用這部分代碼亥宿,例如創(chuàng)建訂單、價格計算砂沛、營銷活動處理等烫扼。
三、重構(gòu)方案
打算采用簡單工廠碍庵、策略對不同商品映企、不同活動的下單邏輯進行解耦,獨立變化静浴。將營銷活動復(fù)雜的價格計算邏輯放到責任鏈中堰氓,支付接口代碼只需要組裝責任鏈調(diào)用就可得到最后的支付價格。
本篇先拋出目前支付接口遇到的問題苹享,下一篇博文描寫這種重構(gòu)思路的設(shè)計和實現(xiàn)双絮。