OC中protocol、category和繼承的區別框架
利用繼承,多態是一個很好的保持「對擴展開放、對更改封閉」(OCP)的辦法,也是最多見的一種方法。Objective C還支持另外兩種語法來支持OCP:Protocol和Category。Protocol只能定義一套接口,而不能提供實現,變相的也是一種Abstract class的實現方式(oc 語法上自己不支持抽象基類)。Category能夠爲類提供額外的接口和實現。那麼到底三者(繼承, Protocol,Category)在使用上到底有什麼本質的區別呢?在我看來,protocol的做用是爲一些列類僅僅提供一套公用的接口,而徹底沒 有辦法也沒可能去提供具體的一些實現狀況;category則是爲一個已有的類提供一些額外的接口和具體實現;而繼承則基於二者之間,既能夠想 protocol同樣提供只是純粹提供接口,也能夠像Category同樣提供完整的實現,並且繼承還能對類之後的功能進行改寫,因此說繼承的力量是最強 大的。那麼具體在使用的時候各自都適合什麼樣的狀況呢?spa
. Protocol是定義行爲而無論誰去怎麼實現,這是一種比較灑脫和不負責的狀況,就好像在外包項目中的客戶同樣,他只是他須要什麼什麼東西,具體實現他不會也不能給出同樣。delegate datasource這樣的就用protocol實現比較好繼承
. Category是對一個功能完備的類的一種補充,就像是一個東西的主要基本功能都完成了,能夠用category爲這個類添加不一樣的組件,使得 這個類可以適應不一樣狀況的需求(可是這些不一樣需求最核心的需求要一致)。找個就像你已經有了一輛可以開動的汽車同樣,咱們能夠用Category爲你的汽 車添加各類以前沒有的功能,最後讓這輛汽車變成超級跑車同樣。接口
. 當某個類很是大的時候,Category能夠按不一樣的功能將類的實現分在不一樣的模塊中實現。開發
. 繼承則是均可以完成上面的工做,可是繼承有很大的代價問題,一是經過繼承來進行擴展是一種耦合很高的行爲,對父類能夠說是徹底依賴;二是繼承因爲 對父類依賴,因此開發代價相對大,要求對父類的工做流程相對熟悉;三是繼承體系若是太複雜會致使整個系統混亂,難以維護。因此在可以用上面兩種方法完成擴 展的時候,就千萬不要使用繼承。什麼狀況纔是無可奈何要使用繼承呢?那就是若是你既想提供一系列接口的定義,同時又想提供一些可是又不能提供所有的實現的 時候,這種狀況就要使用繼承了。因此這麼看來繼承是對上面兩種功能的一個黏合劑。編譯器
關於category的另一些看法:工作流
. 雖然category能夠訪問類的實例變量,去不能建立新的實例變量,若是要創新的實例變量,請使用繼承;it
. 在category中,不提倡對原有方法進行重載。緣由很是簡單,在category中進行重載,沒法對原方法進行訪問,而繼承中可使用super。若是真的須要對原方法進行重載,請考慮繼承,好比我要定義一個繼承自UIViewController的類,就不能用Category,由於,這我定義的這個類中,我要實現UIViewController中的viewDidLoad、init等方法,用了category後父UIViewController中的這些方法將沒法被調用;編譯
. 一個類能夠定義多個category,可是若是不一樣category中存在相同方法,編譯器沒法決定使用哪一個category;class
. 在定義category時,咱們能夠僅僅給出方法定義,而不須要給出具體的實現。這在程序增量開發時是很是有幫助的;
. category是能夠被繼承的。在某個父類中定義了category,那麼他全部的子類都具備該category;
. 在須要爲某個類建立私有成員方法時,也用category的方式來實現。
Category不能徹底代替子類,有如下幾個最大的缺點:
. 當在Category中覆蓋一個繼承的方法,在Category中的方法能夠經過向super類發送一個消息來調用被繼承的方法。可是,若是Category中覆蓋的那個方法已經在這個類的其它Category定義過了,則以前定義的方法將沒有機會被程序調用
. 在Category中沒法肯定其可以可靠的覆蓋某個方法,而這個方法已經在其它的Category中定義過。這個問題在使用Cocoa框架時尤爲 突出。當你想覆蓋某個框架已經定義好的方法時,該方法已經在其它Category中實現,這樣就沒法肯定哪一個定義和實現會被最早使用,帶來很大的不肯定 性。
. 若是你從新覆蓋定義了一些方法,每每會致使這個方法在整個框架中實現發生了變化。舉例來講,若是你增長了NSObject中 windowWillClose:的實現,這會致使全部的窗口調用那個新實現的方法,從而改變全部NSWindows實例的行爲。這會帶來不少不肯定性, 並頗有可能致使程序的崩潰。