摘要:我們的客戶端網絡框架至少要解決三個問題實現通信協議賬戶系統簡化服務端接口調用。賬戶系統簡而言之就是實現注冊登陸注銷等功能,并維護登陸狀態等。這樣客戶代碼就可以通過這一單一接口使用網絡框架了。
我們的客戶端網絡框架至少要解決三個問題:實現通信協議、賬戶系統、簡化服務端接口調用。
實現通信協議 根據與服務端制定的通信協議,實現請求的組裝,序列化,發送,以及響應的接收和解析等。
賬戶系統 簡而言之就是實現注冊、登陸、注銷等功能,并維護登陸狀態等。
簡化服務端接口調用 客戶代碼只需要提供業務參數和回調函數就可以實現與服務器通信,網絡框架負責封裝掉其余所有細節。
我想對架構比較敏感的讀者會立刻有這樣的共鳴,首先上述的賬戶系統顯然是一個獨立的模塊,最好多帶帶設計實現。另一方面,賬戶系統的功能又是以服務端接口調用為基礎的,在形式上登陸操作也是調用服務端接口,那么把登陸相關操作與其他服務端接口調用實現于一處就是自然的。如果再作一些考慮,我們還會想到的一個問題是,網絡框架暴露給客戶代碼的接口應當盡可能單一,如果我們用一個類維護賬戶系統,用另一個類做服務端業務接口調用,會嫌不夠簡潔。達成這幾點共識之后,我們就可以繼續探討一些設計細節了。先看下面的代碼。
//SFClient.h @interface SFClient @property (nonatomic,readonly) NSString* account; @property (nonatomic,readonly) NSString* password; @property (nonatomic,readonly) BOOL isLoggedIn; @property (nonatomic,readonly) BOOL pendingLogin; @property (nonatomic,readonly) NSString* sessionId; -(NSURLSessionTask*)loginWithAccount:(NSString*)account password:(NSString*)password; -(NSURLSessionTask*)logout; -(NSURLSessionTask*)someNetworkingTaskWithCompletionHandler:(SFNetworkingTaskCompletionHandler)completionHandler; //... @end
有的同行習慣于為每一個后端接口多帶帶開一個類,這當然也不失為一種設計風格,筆者也曾嘗試過,個人感覺嫌繁。
這里的SFClient類作為賬戶系統,又兼具服務端業務接口調用功能,實現了使接口盡可能簡潔的設計目標,卻違背了賬戶系統應當多帶帶實現的架構設計直覺。
如何解決這一矛盾呢?可以采用dynamic proxy設計模式。
定義一個protocol假設叫SFBackendInterfaces,和一個實現類假設叫SFBackendInterfacesImpl。讓SFClient和SFBackendInterfacesImpl都實現這個協議。
@protocol SFBackendInterfaces-(NSURLSessionTask*)loginWithAccount:(NSString*)account password:(NSString*)password completionHandler:(SFNetworkingTaskCompletionHandler); -(NSURLSessionTask*)someNetworkingTaskWithCompletionHandler:(SFNetworkingTaskCompletionHandler)completionHandler; @end @interface SFClient:NSObject @interface SFBackendInterfacesImpl:NSObject
這樣做的目的是什么呢,就是讓SFClient類繼續提供服務端接口調用功能,同時把這些接口調用的實現代碼交給SFBackendInterfacesImpl。這樣就既滿足網絡框架接口簡潔的需求,又保持了SFClient類作為賬戶系統的純凈,-(NSURLSessionTask*)someNetworkingTaskWithCompletionHandler:(SFNetworkingTaskCompletionHandler)completionHandler;這行代碼可以從SFClient的interface中拿掉了,并且相關代碼也不需要出現在它的implementation文件里了。我們來看implementation。
@implementation SFClient -(void)forwardInvocation:(NSInvocation *)anInvocation { if([self.backendInterfacesImpl respondsToSelector:anInvocation.selector]){ [anInvocation invokeWithTarget:self.backendInterfacesImpl]; }else{ [super forwardInvocation:anInvocation]; } } -(void)loginWithAccount:(NSString*)account password:(NSString*)password { NSURLSessionTask* task=[self loginWithAccount:account password:(NSString*)password completionHandler:^(SFResponse* response){ [[NSNotificationCenter defaultCenter] postNotificationNamed:SFLoginCompletionNotification object:response]; _pendingLogin=NO; if(response.status==SFResponseStatusSuccess){ _loggedIn=YES; } }]; [task resume]; _pendingLogin=YES; } @end @implementation SFBackendInterfacesImpl -(NSURLSessionTask*)loginWithAccount:(NSString*)account password:(NSString*)password completionHandler:(SFNetworkingTaskCompletionHandler) { //... } -(NSURLSessionTask*)someNetworkingTaskWithCompletionHandler:(SFNetworkingTaskCompletionHandler)completionHandler { //... } @end
這樣客戶代碼就可以通過SFClient這一單一接口使用網絡框架了。
[[SFClient sharedClient] loginWithAccount:xxxx password:xxxx]; //... NSURLSessionTask* task=[[SFClient sharedClient] someNetworkingTaskWithPara::param completionHandler:^(SFResponse* response){ //... }]; [task resume];
而在框架內部實現上,賬戶系統和業務接口調用的實現仍然是分離的。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/11728.html
閱讀 937·2021-09-07 09:58
閱讀 1487·2021-09-07 09:58
閱讀 2881·2021-09-04 16:40
閱讀 2503·2019-08-30 15:55
閱讀 2411·2019-08-30 15:54
閱讀 1368·2019-08-30 15:52
閱讀 429·2019-08-30 10:49
閱讀 2604·2019-08-29 13:21