原文地址:https://zhanglei.blog.csdn.net/article/details/121376500
前言
有段時間沒寫技術文章了,一是因為作業太忙,再者因為本人文筆實在一般,最近終于閑下來,本著分享的目的將一些組件設計上的心得與大家分享,
本篇文章是基于原有一篇關于支付文章的進一步優化設計,所以在閱讀本篇文章前還是建議先移步到那篇文章,
文章地址: 微信、支付寶、銀聯、Paypal 支付組件封裝
描述
在封裝支付介面時,需要面臨各支付平臺不同SDK集成的問題,有的支付第三方平臺只通過sdk組件就可完成支付,像支付寶,但大部分的支付第三方平臺需要先去呼叫服務端API介面獲取支付需要的資訊,拿到這些支付資訊后,再去呼叫sdk組件完成支付,這類第三方有銀聯(需要獲取tn交易流水號),微信(需要獲取prepayData
)等,
為了以后的支付功能復用,想要設計一個支付組件,該組件整合并統一了這些第三方支付sdk的介面,以便給客戶端快速集成,在設計支付組件的程序中就遇到上面提到的問題, 如何解決某些第三方需要請求一些資料后,再進行支付的問題 ? 試想一下如果將這些請求hardcode到組件中,顯然能滿足當前的功能,局限性也非常明顯,只能適用當前的支付業務, 此時的支付組件會和網路組件藕合,不利于擴展及復用,
設計
如何解藕? 如何能讓這些需要請求API的第三方不污染組件? 解藕的思想就是“抽離變化,并封裝”
, 我們需要把不穩定的部分抽離出來,使其獨自變化,不影響穩定的部分, 找到了方向, 如何抽離? 這里我們可以使用面向協議的編程的思想,將請求API的行為進行抽象,
偽代碼:
//抽像一個協議, 協議定義一個獲取支付資訊的方法,呼叫介面是異步操作,所以回傳的資料使用block回傳
@protocol PayDataPrepareProtocol <NSObject>
@required
- (void)getPayData:(void(^)(id result, NSError *error))block;
@end
微信支付偽代碼:
@interface WXPayPrepareData : NSObject <PayDataPrepareProtocol>
@property (nonatomic,strong) NSDictionary *requestParams;
@end
@implementation WXPayPrepareData
- (void)getPayData:(void(^)(id result, NSError *error))block {
//根據請求引數,使用網路層組件呼叫API,并回傳預支付資訊
block(result,nil);
}
@end
銀聯支付偽代碼:
@interface UnionPayPrepareData : NSObject <PayDataPrepareProtocol>
@property (nonatomic,strong) NSDictionary *requestParams;
@end
@implementation UnionPayPrepareData
- (void)getPayData:(void(^)(id result, NSError *error))block {
//根據請求引數,使用網路層組件呼叫API,并回傳預支付資訊
block(result,nil);
}
@end
如何能將支付型別與預支付實作類之間建立聯系呢?我們需要設計一個配置類來管理這種支付型別與預支付實作類的對應關系 ,
支付配置的偽代碼:
typedef NS_Enum(NSInteger, PayType) {
PayTypeForAlipay, //支付寶支付
PayTypeForWXPay, //微信支付
PayTypeForUPPay, //銀聯支付
}
@interface PayConfig: NSObject
//單例物件
+ (instancetype)config;
//添加獲取預支付資訊對應的策略類, 沒有傳遞實體物件,避免未使用而造成的記憶體浪費
- (void)appendPrepayDataStrategy:(Class)strategyClass withPayType:(PayType)payType;
//判斷是否存在指定型別對應的實作策略
- (BOOL)containsPrepayDataStrategyWithPayType:(PayType)payType;
//根據支付的列舉型別,獲取預支付資訊處理物件
- (id<PayDataPrepareProtocol>)getPrepayDataStrategyWithPayType:(PayType)payType;
@end
@interface PayConfig ()
@property (nonatomic,strong) NSMutableDictionary *strategyMap;
@end
@implementation PayConfig
//單例物件
+ (instancetype)config {
static PayConfig *_instance;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
if (!_instance) {
_instance = [[PayConfig alloc] init];
}
});
return _instance;
}
//添加獲取預支付資訊對應的策略類, 沒有傳遞實體物件,避免未使用而造成的記憶體浪費
- (void)appendPrepayDataStrategy:(Class)strategyClass withPayType:(PayType)payType {
if (!strategyClass) {
return;
}
//判斷是否實作了協議
if (![strategyClass conformsToProtocol:@protocol(PayDataPrepareProtocol)]) {
return;
}
NSString *payTypeKey = [Utils convertPayTypeToString:payType]; //將列舉轉成字串
[self.strategyMap setObject:strategyClass forKey:payTypeKey];
}
//判斷是否存在指定型別對應的實作策略
- (BOOL)containsPrepayDataStrategyWithPayType:(PayType)payType {
NSString *payTypeKey = [Utils convertPayTypeToString:payType]; //將列舉轉成字串
return !self.strategyMap[payTypeKey];
}
//根據支付的列舉型別,獲取預支付資訊處理物件
- (id<PayDataPrepareProtocol>)getPrepayDataStrategyWithPayType:(PayType)payType {
if (![self containsPrepayDataStrategyWithPayType:payType]) {
return nil;
}
NSString *payTypeKey = [Utils convertPayTypeToString:payType]; //將列舉轉成字串
Class cls = self.strategyMap[payTypeKey];
return [[cls alloc] init]; //在需要時才回傳創建的物件
}
//懶加載,需要時創建
- (NSMutableDictionary *)strategyMap {
if (!_strategyMap) {
_strategyMap = @{}.mutableCopy;
}
return _strategyMap;
}
@end
通過上面的支付配置(單例)物件,我們將以支付型別為key
, 以對應的獲取預支付資訊的類為value
, 使用字典來管理, 將配置類設計成單例
,這樣就可以在支付組件中訪問,并使用其中的配置資訊,
支付組件的偽代碼:
#import "PayConfig.h"
@interface PayManager :NSObject
//呼叫預支付資訊API介面,用到的請求引數
@property (nonatomic,strong) NSDictionary *requestParams;
//支付第三方型別
@property (nonatomic,assign) PayType payType;
//開始支付
- (void)startPay;
@end
@implementation PayManager
//開始支付
- (void)startPay {
//1. 根據支付型別,判斷支付配置中是否有需要請求服務API的處理類
if ([[PayConfig config] containsPrepayDataStrategyWithPayType:self.payType]) {
id strategy = [[PayConfig config] getPrepayDataStrategyWithPayType:self.payType];
//利用KVC向請求API介面的策略類傳遞請求引數
[strategy setValue:self.requestParams forKey:@“requestParams”];
//準備好請求資料后,開始呼叫介面API獲取所需要的預支付資訊
[strategy getPayData:^(id result, NSError *error ) {
//拿到需要的預支付資訊后,再調起第三方支付組件
}];
}else {
// 調起第三方支付組件
}
}
@end
總結
通過我們的進一步設計,支付組件已完全不依賴于網路組件來完成對預支付資訊的獲取,而且擴展性更強了, 如果以后有新的支付第三方加入進來,且需要獲取預支付資訊的, 我們只需要實作PayDataPrepareProtocol
協議, 并將其加入到 PayConfig
中就可以了, 通過少量的修改我們就可以完成擴展,也遵循了“開閉原則( 對擴展開放,對修改關閉)” ,
完整的支付組件代碼請前往:RZPayManager
在README.md檔案中有該組件的使用詳解,如果喜歡,點關注支持一下,
后記
如果本文對你有一點幫助的話,歡迎收藏、點贊,感謝,文中如有不對之處,也歡迎大家在評論區指出,共勉,
本文來自博客園,作者:reyzhang,轉載請注明原文鏈接:https://www.cnblogs.com/reyzhang/p/17498798.html
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/555851.html
標籤:其他
下一篇:返回列表