類比Spring架構來實現OC中的依賴注入,springoc
如果你之前使用過JavaEE開發中的Spring架構的話,那麼你一定對依賴注入並不陌生。依賴注入(DI: Dependency Injection)是控制反轉(IoC: Inversion of Control)的實現方式之一,另外一種是依賴尋找(DL: Dependency Lookup)。當然在Spring架構中主要使用到了控制反轉中的依賴注入這種方式。當然在Spring架構中除了依賴注入外,還有一個重要的概念那就是面向切面編程(AOP)。
簡單的說,依賴注入負責往類中注入依賴對象,而面向切面編程則負責往裡添加程式碼片段的。本篇部落格我們主要聊的就是依賴注入,關於AOP和依賴尋找的內容,如果以後有機會,會在後邊的部落格進行介紹。
本篇部落格不是使用Java語言實現的,而是使用Objective-C來實現的。實現依賴注入的具體方式就是使用反射機制來實現的,本篇部落格,我們就使用OC的反射機制來看一下iOS開發中的依賴注入的實現方式。當然在Java的Spring架構中是在XML檔案中配置的JavaBean,入鄉隨俗,本篇部落格我們就使用iOS開發中常用的PList檔案來儲存類似於JavaBean的東西,也就是數本篇部落格我們使用PList檔案來代替XML檔案。廢話少說,進入我們的主題。
一、依賴注入的實現機制
依賴注入,聽起來特別高大上,其實真正理解其工作原理後,也沒什麼東西。本篇部落格採用的代碼執行個體與之前我們聊“策略模式”的樣本一致。關於之前的策略模式的部落格,請移步於《“穿越火線”中的“策略模式”(Strategy Pattern)》。當然我們之前的樣本是使用的Swift來實現的,本篇部落格使用的是OC, 雖然語言不通,但是思想是一致的。在“策略模式”中我們通過策略模式為不通的軍官提供不同的武器策略。而本篇部落格,我們依然採用這個思路,不過我們是依照“依賴注入”的方式來為不同的軍官提供不同的武器策略。
下方就是我們本篇部落格使用樣本的類圖。WeaponType是所有武器的父類,在其中扮演者“武器介面”的角色。所有的武器都繼承自WeaponType。而Character角色類依賴於WeaponType武器介面類,所有Character與WeaponType存在依賴關係。
“依賴注入”從字面上看,就是注入依賴。也就是將依賴關係的對象注入到相應的類中。而在上述樣本中,Character依賴於WeaponType介面,如果使用“依賴注入”來解決這層依賴關係的話,就是通過反射機制(“Runtime”)動態將WeaponType的子類的對象注入到Character對應的相依性屬性中去。而反射時需要的依賴關係資訊,我們就從PList檔案中進行讀取,當然Java中是從XML中進行配置的,這就是“依賴注入”。
本篇部落格我們就來根據上述類圖的依賴關係,來完整的實現這個執行個體。當然在真正實現時,我們用到的主要核心內容是“面向介面編程”、“物件導向的多態性”、“反射機制”、“PList檔案的讀取與操作”。下方會一一介紹。
二、樣本工程的目錄結構
接下來我們就來概述一下本篇部落格所使用到的執行個體的工程結構,也就是先整體的瞭解一下本篇部落格所涉及的樣本工程。下方這個工程目錄結構就是我們本篇部落格所涉及的樣本的目錄結構。Weapon檔案夾中存放的就是武器策略所涉及的武器介面與武器類。Character檔案夾中存放的就是武器使用者所對應的目錄。PList檔案則儲存的是Character類依賴WeaponType介面的具體類的依賴資訊。Relation類則是負責讀取PList檔案中的依賴資訊,根據這些依賴資訊將依賴對象通過“反射機制”注入到相應的類中。
三、PList檔案中的內容
本篇部落格中的PList檔案的作用就類似於Spring架構中用來配置JavaBean的XML。當然我們本篇部落格的PList檔案的儲存內容的結構與形式與Spring中的XML有所不同,但是其作用都是一樣的,都是用來描述類之間的依賴關係的。
下方就是本篇樣本所涉及的PList檔案中的內容。從下方檔案中,我們可以看出其中儲存了三個類的資訊,一個是Lieutenant(中尉)類,一個是Captain(上尉)類,最後一個就是Soldier(士兵)類。每個類也就是Java中常說的JavaBean,Relation類可以根據反射機制根據這些類在PList檔案中提供的資訊來執行個體化相應的類的對象。
我們就以Lieutenant為例。在PList檔案中,其實Lieutenant就對應這一個類,從Lieutenant對應的資訊來看,Lieutenant的對象由Character類執行個體化,但是在執行個體化時需要給Character的對象相依性屬性weapon賦一個HK48Weapon類的對象。當然這一系列執行個體化以及賦值的動作都是由反射機制完成。稍後我們會給出具體實現。
四、通過PList檔案建立類
Relation類就是賦值載入相應的PList檔案內容,然後根據其載入的內容利用反射機制產生相應的類的對象。下方程式碼片段就是Relation類載入上述的PList檔案內容,讓後給據這些內容產生相應的類的對象的。下方這個程式碼片段根據Relation提供的上下文分別建立了Lieutenant對象、Captain對象以及Soldier的對象。具體如下所示。
根據上下文建立完對象後,都會調用fire方法,因為每個對象對應的上下文不同,也就是注入的依賴對象不同,所以fire方法執行的結果也不同。下方是上述代碼的運行結果,如下所示:
五、使用反射機制注入依賴對象
接下來我們就要來看一下如何使用反射機制來注入依賴對象的,也就是Relation類的具體實現。
1.通過初始化方法提供plist檔案
下方是Relation類的構造器,構造器中有個參數plistFileName, 該參數就是用來儲存依賴上下文資訊的plist檔案。Relation類在執行個體化對象時,收到該檔案後,會載入該檔案中的上下文資訊,也就是我們plist檔案中的內容。具體代碼如下所示。
下方程式碼片段就是本篇部落格的核心代碼,根據PList檔案中提供的上下文資訊,產生相應的對象,並給對象相應的屬性注入依賴對象。當然下方是通過Setter方法來設定依賴對象的。設定完畢後,返回該注入好依賴的對象。具體如下所示。
今天部落格就先到這兒吧,以後我們找個合適的時間再聊聊依賴尋找和面向切面編程的東西。下方的github連結是本篇部落格所涉及Demo的源碼分享連結,如下所示。
源碼的github分享連結:https://github.com/lizelu/DependencyInjectionForiOS