了解依賴注入
依賴注入產(chǎn)生的背景:
隨著面向?qū)ο蠓治雠c設(shè)計(jì)的發(fā)展桦卒,一個良好的設(shè)計(jì)蒋困,核心原則之一就是將變化隔離翻擒,使得變化部分發(fā)生變化時政恍,不變部分不受影響(這也是OCP的目的)汪拥。為了做到這一點(diǎn),要利用面向?qū)ο笾械亩鄳B(tài)性篙耗,使用多態(tài)性后迫筑,客戶類不再直接依賴服務(wù)類,而是依賴于一個抽象的接口宗弯,這樣脯燃,客戶類就不能在內(nèi)部直接實(shí)例化具體的服務(wù)類。但是蒙保,客戶類在運(yùn)作中又客觀需要具體的服務(wù)類提供服務(wù)辕棚,因?yàn)榻涌谑遣荒軐?shí)例化去提供服務(wù)的。就產(chǎn)生了“客戶類不準(zhǔn)實(shí)例化具體服務(wù)類”和“客戶類需要具體服務(wù)類”這樣一對矛盾追他。為了解決這個矛盾坟募,開發(fā)人員提出了一種模式:客戶類定義一個注入點(diǎn)岛蚤,用于服務(wù)類的注入邑狸,而客戶類的客戶類(Program,即測試代碼)負(fù)責(zé)根據(jù)情況涤妒,實(shí)例化服務(wù)類单雾,注入到客戶類中,從而解決了這個矛盾她紫。
依賴注入的正式定義:
依賴注入(Dependency Injection)硅堆,是這樣一個過程:由于某客戶類只依賴于服務(wù)類的一個接口,而不依賴于具體服務(wù)類贿讹,所以客戶類只定義一個注入點(diǎn)渐逃。在程序運(yùn)行過程中,客戶類不直接實(shí)例化具體服務(wù)類實(shí)例民褂,而是客戶類的運(yùn)行上下文環(huán)境或?qū)iT組件負(fù)責(zé)實(shí)例化服務(wù)類茄菊,然后將其注入到客戶類中,保證客戶類的正常運(yùn)行赊堪。
依賴注入的類別
(1)Setter注入
Setter注入(Setter Injection)是指在客戶類中面殖,設(shè)置一個服務(wù)類接口類型的數(shù)據(jù)成員,并設(shè)置一個Set方法作為注入點(diǎn)哭廉,這個Set方法接受一個具體的服務(wù)類實(shí)例為參數(shù)脊僚,并將它賦給服務(wù)類接口類型的數(shù)據(jù)成員。
(2)構(gòu)造注入
在客戶類中遵绰,設(shè)置一個服務(wù)類接口類型的數(shù)據(jù)成員辽幌,并以構(gòu)造函數(shù)為注入點(diǎn)增淹,這個構(gòu)造函數(shù)接受一個具體的服務(wù)類實(shí)例為參數(shù),并將它賦給服務(wù)類接口類型的數(shù)據(jù)成員乌企。
與Setter注入很類似埠通,只是注入點(diǎn)由Setter方法變成了構(gòu)造方法。這里要注意逛犹,由于構(gòu)造注入只能在實(shí)例化客戶類時注入一次端辱,所以一點(diǎn)注入,程序運(yùn)行期間是沒法改變一個客戶類對象內(nèi)的服務(wù)類實(shí)例的虽画。由于構(gòu)造注入和Setter注入的IServiceClass舞蔽,ServiceClassA和ServiceClassB是一樣的,不同的ClientClass類码撰。
(3)依賴獲取
上面提到的注入方式渗柿,都是客戶類被動接受所依賴的服務(wù)類,這也符合“注入”這個詞脖岛。不過還有一種方法朵栖,可以和依賴注入達(dá)到相同的目的,就是依賴獲取柴梆。
依賴獲仍山Α(Dependency Locate)是指在系統(tǒng)中提供一個獲取點(diǎn),客戶類仍然依賴服務(wù)類的接口绍在。當(dāng)客戶類需要服務(wù)類時门扇,從獲取點(diǎn)主動取得指定的服務(wù)類,具體的服務(wù)類類型由獲取點(diǎn)的配置決定偿渡。
可以看到臼寄,這種方法變被動為主動,使得客戶類在需要時主動獲取服務(wù)類溜宽,而將多態(tài)性的實(shí)現(xiàn)封裝到獲取點(diǎn)里面吉拳。獲取點(diǎn)可以有很多種實(shí)現(xiàn),也許最容易想到的就是建立一個Simple Factory作為獲取點(diǎn)适揉,客戶類傳入一個指定字符串留攒,以獲取相應(yīng)服務(wù)類實(shí)例。如果所依賴的服務(wù)類是一系列類涡扼,那么依賴獲取一般利用Abstract Factory模式構(gòu)建獲取點(diǎn)稼跳,然后,將服務(wù)類多態(tài)性轉(zhuǎn)移到工廠的多態(tài)性上吃沪,而工廠的類型依賴一個外部配置汤善,如XML文件。
不過,不論使用Simple Factory還是Abstract Factory红淡,都避免不了判斷服務(wù)類類型或工廠類型不狮,這樣系統(tǒng)中總要有一個地方存在不符合OCP的if…else或switch…case結(jié)構(gòu),這種缺陷是Simple Factory和Abstract Factory以及依賴獲取本身無法消除的在旱,而在某些支持反射的語言中(如C#)摇零,通過將反射機(jī)制的引入徹底解決了這個問題。
? ??