前言
曾經(jīng)做java開發(fā)時朴艰,接觸到很多編程思想观蓄、設(shè)計模式,后來轉(zhuǎn)向iOS后祠墅,常常會思考如何將這些知識融入到iOS開發(fā)當(dāng)中侮穿。今天想分享的就是在java當(dāng)中無處不在,但是在OC中卻很少被提及到的概念——面向接口編程毁嗦。
什么是接口
接口的特征為:只聲明方法亲茅,不實現(xiàn)方法。簡單來說,接口是某些行為的抽象表達(dá)克锣,也是一組協(xié)議或約定茵肃,我們不關(guān)心某個具體類,而只關(guān)心這個類是否遵守并實現(xiàn)了這些約定袭祟。例如飛機和鳥验残,都有共同的一種行為:飛。因為飛機和鳥并沒有相同的父類可以繼承(關(guān)于抽象類和接口區(qū)別以及使用場景巾乳,有興趣的小伙伴可以google一下胚膊,很多文章分析的很透徹了,這里我就不在贅述想鹰。),因此我們就可以抽象出一個接口類IFly药版,與java不同的是辑舷,iOS使用protocol關(guān)鍵字來定義接口。
@protocol IFly <NSObject>
- (void)fly;
@end
飛機的實現(xiàn)類
Plane.h
@interface Plane : NSObject <IFly>
@end
Plane.m
@implementation Plane
- (void)fly
{
NSLog(@"飛機飛");
}
@end
鳥的實現(xiàn)類
Bird.h
@interface Bird : NSObject <IFly>
@end
Bird.m
@implementation Bird
- (void)fly
{
NSLog(@"小鳥飛");
}
@end
使用方法:
id<IFly> flyBehaviour = [Plane new];
[flyBehaviour fly];
flyBehaviour = [Bird new];
[flyBehaviour fly];
控制臺打硬燮:
IOPDemo[20101:1939006] 飛機飛
IOPDemo[20101:1939006] 小鳥飛
只要將flyBehaviour指向不同的實現(xiàn)了IFly接口的對象何缓,就能體現(xiàn)出不同的具體行為,這也是多態(tài)的表現(xiàn)形式还栓。
面向接口編程的好處
設(shè)計模式原則中有一點:依賴倒置原則碌廓。即
- 高層模塊不應(yīng)該依賴低層模塊,兩者都應(yīng)該依賴其抽象剩盒;
- 抽象不應(yīng)該依賴細(xì)節(jié)谷婆;
- 細(xì)節(jié)應(yīng)該依賴抽象;
面向接口編程可以很好地遵守這個設(shè)計模式原則辽聊。以上例子中纪挎,抽象就是指IFly類,細(xì)節(jié)就是指Plane或Bird這樣的具體類跟匆。這樣做的好處是可以降低類與類之間的耦合异袄,易于程序擴展,可以在不破壞上層代碼的情況下修改甚至替換整個底層代碼玛臂。面向接口編程還有其他好處:
- 可以在代碼運行期間烤蜕,動態(tài)地修改類的行為。在不同的條件下迹冤,由高層模塊決定使用哪個具體類讽营。
- 并行開發(fā)。在定義接口之后叁巨,業(yè)務(wù)開發(fā)人員只需調(diào)用接口方法而不用關(guān)心這些方法是否已經(jīng)實現(xiàn)斑匪,而底層開發(fā)人員則可以根據(jù)需求逐步完善具體類的代碼。
- 便于單元測試。封裝性越好的代碼蚀瘸,越容易測試狡蝶。面向接口編程可以很好的將業(yè)務(wù)代碼模塊化,從而針對不同的邏輯進行測試贮勃。
- 有更多的好處贪惹,希望大家可以在使用過程當(dāng)中去感受。
再舉個簡單的例子寂嘉。當(dāng)移動端和服務(wù)端協(xié)商了網(wǎng)絡(luò)請求以及返回值的參數(shù)奏瞬,即使服務(wù)端的接口并沒有完成,也不影響移動端的開發(fā)人員進行開發(fā)泉孩,同時移動端開發(fā)人員也并不關(guān)心后臺邏輯如何變化硼端,只需保證入?yún)⒓俺鰠⒌恼_性即可。
iOS編程中使用接口
首先看一下項目大致結(jié)構(gòu):
service是ViewController中的一個接口屬性寓搬,InterfaceService是實現(xiàn)了InterfaceProtocol協(xié)議的實現(xiàn)類珍昨。在頁面調(diào)用service的方法時,實際是調(diào)用了InterfaceService這個實現(xiàn)類的方法句喷,在實現(xiàn)類中可以使用很多第三方的網(wǎng)絡(luò)請求框架镣典,如HYB,YTK等等。這些第三方庫是基于AF進行了二次封裝唾琼,優(yōu)點是可以將請求的邏輯統(tǒng)一兄春,減少上層的代碼量,甚至替換掉底層AF锡溯,更換其他框架赶舆。最后AF請求服務(wù)器,并將數(shù)據(jù)一層一層向上傳遞直至ViewController趾唱。
那么相比于直接在ViewController中調(diào)用HYB或者YTK的網(wǎng)絡(luò)請求涌乳,中間多的一層InterfaceService優(yōu)點是什么呢?
在我們公司目前有很多業(yè)務(wù)模塊如任務(wù)模塊甜癞,商城模塊等等夕晓。不同的業(yè)務(wù)模塊有不同的服務(wù)器地址,不同的服務(wù)器請求參數(shù)形式也都不一樣悠咱。如果在VC層中直接調(diào)用第三方網(wǎng)絡(luò)請求蒸辆,那么就會造成很多的重復(fù)判斷代碼。因此增加的InterfaceService又稱為業(yè)務(wù)請求層析既,在這一層的代碼中躬贡,我可以針對不同的服務(wù)器統(tǒng)一管理域名,請求配置或請求方式眼坏,編寫VC的業(yè)務(wù)開發(fā)人員只需傳遞業(yè)務(wù)所需要的關(guān)鍵參數(shù)如id拂玻,分頁參數(shù)等等,同時通過回調(diào)拿到網(wǎng)絡(luò)請求的返回值,而不用關(guān)心底層如何實現(xiàn)檐蚜,并行開發(fā)提高開發(fā)效率魄懂,也利于編寫業(yè)務(wù)請求層的開發(fā)人員進行單元測試。
下面是主要類的截圖
接口文件 InterfaceProtocol.h
@protocol InterfaceProtocol <NSObject>
@optional
/**
獲取首頁數(shù)據(jù)
@param param 請求參數(shù)
@param complete 成功回調(diào)
@param failed 失敗回調(diào)
*/
- (void)fetchData:(NSDictionary *)param complete:(void (^)(NSDictionary *response))complete failed:(void (^)(NSString *error))failed;
@end
接口實現(xiàn)類 InterfaceService.h
@interface InterfaceService : NSObject <InterfaceProtocol>
@end
接口實現(xiàn)類 InterfaceService.m
#import "InterfaceService.h"
@implementation InterfaceService
- (void)fetchData:(NSDictionary *)param complete:(void (^)(NSDictionary *response))complete failed:(void (^)(NSString *error))failed
{
if (param[@"id"]) {
//模擬網(wǎng)絡(luò)請求返回成功
complete(@{@"status":@"success"});
} else {
//模擬網(wǎng)絡(luò)請求返回失敗
failed(@"error");
}
}
@end
ViewController中的代碼
#import "ViewController.h"
#import "InterfaceProtocol.h"
#import "InterfaceService.h"
@interface ViewController ()
@property (nonatomic, strong) id<InterfaceProtocol> service;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
//接口指向一個實現(xiàn)類
//其實這邊可以使用DI注入
self.service = [InterfaceService new];
//發(fā)起一個請求
[self.service fetchData:@{@"id":@"1"} complete:^(NSDictionary *response) {
NSLog(@"do sth...");
} failed:^(NSString *error) {
NSLog(@"%@",error);
}];
}
@end
結(jié)束語
在今后的學(xué)習(xí)過程當(dāng)中闯第,我會繼續(xù)嘗試在項目里結(jié)合更多的元素市栗,設(shè)計出更好的代碼。
小伙伴們?nèi)绻泻玫南敕梢砸黄鹩懻摽榷蹋陨嫌胁蛔慊蛘咤e誤的地方填帽,歡迎提出,我會認(rèn)真回復(fù)咙好。