【轉載請註明出處】
1、介面的實現
對於介面這一概念的支援,不同語言的實現形式不同。Java中,由於不支援多重繼承,因此提供了一個Interface關鍵詞。而在C++中,通常是通過定義抽象基類的方式來實現介面定義的。
Objective-C既不支援多重繼承,也沒有使用Interface關鍵詞作為介面的實現(Interface作為類的宣告來使用),而是通過抽象基類和協議(protocol)來共同實現介面的。
2、介面的意義
物件導向程式設計中一條重要的經驗法則是:對介面程式設計,而不是對實現程式設計。即一個物件想要呼叫另一個物件的方法,往往不會直接採取直接呼叫的形式。為降低耦合度考慮,通常會在呼叫者和被呼叫者中間增加一層抽象的(通常不會變動的)中間層,介面就是中間層的最通用的形式。
3、Objective-C中的介面與協議protocol
如前所述,Objective-C中使用協議protocol作為支援介面實現的關鍵詞。
如下類A的物件想要呼叫類B的物件的方法:
Class A中:
- (void)doSth:(B *)b
{
[b doSth];
}
增加一個抽象的(通常不會變動的)中間層作為中介,如下:
定義一個protocol:
@protocol doSthDelegate
(void)doSth;
@end
Class A中:
- (void)doSth:(id<doSthDelegate>) delegate
{
if (delegate)
[delegate doSth];
}
4、Objective-C中的介面與抽象基類
協議protocol其實是足以支援介面的語法實現的,但對於需要頻繁呼叫的方法來說,未免不夠簡潔。如在NSObject協議中宣告的alloc、dealloc、retain、release和autoRelease等幾乎出現在iOS開發各個角落的方法,如果都需要
if (delegate && delegate respondsToSelector:@selector(func)
{
[delegate func];
}
那就太過麻煩了。因此NSObject Class出現了。
在NSObject中對NSObject protocol中的方法都做了基本的實現,因而保證了處於NSObject派生鏈中的子類在呼叫NSObject protocol中的方法時的可靠性。寫法上也變得極為簡潔。
5、抽象基類和協議共存
如4中所述,抽象基類相比於協議,一方面提供了一些方法的基本實現,使得子類不需要重複實現,另一方面能夠保持語法的簡潔。因此,只使用協議而不使用抽象基類,是可行的,但極不方便。
而單獨使用抽象基類支援介面的語法,是基本上不可行的。如SDK中的UIView及其子類,由於Objective-C的單繼承限制,這些已經有基類的類,就不能使用介面了。當然,開發者自行定義的類,是可以完全依靠抽象基類進行組織的。
6、抽象基類和協議如何協作
經典範例就是標題中的NSObject class和NSObject protocol。
在Cocoa Touch中,並非所有的類都派生自NSObject,如NSProxy類(它本身是一個root class)。但是,對NSProxy和NSproxy的派生類的物件的記憶體控制,仍然採用alloc、dealloc、retain、release和autoRelease是很自然的想法。在不改變NSProxy基類的情況下,就只能通過協議來支援。
在NSObject協議中,宣告瞭retain、release和autoRelease方法(alloc和dealloc在NSProxy有定義),而NSProxy實現了NSObject協議(conform to protocol NSObject),因此可以做到
[proxyObj release];
這樣的呼叫。
7、總結
在Objective-C中,介面的支援主要由協議protocol來實現,抽象基類用於簡化語法、提供通用方法的基礎實現。
參考:
【1】Objective-C程式設計之道
【2】NSObject class and protocol
http://objectmix.com/c/177917-nsobject-class-protocol.html
【3】NSProxy Class Reference
https://developer.apple.com/library/ios/documentation/Cocoa/Reference/Foundation/Classes/NSProxy_Class/Reference/Reference.html