關(guān)于IoC控制反轉(zhuǎn)的設(shè)計原則
2010-09-04
靜態(tài)類的使用是一個有爭議的話題,,有人甚至提倡不要在類的名稱上使用作用域限定符,。關(guān)于靜態(tài)特性爭論的焦點在于一個被稱為IoC控制反轉(zhuǎn)的設(shè)計原則。
IoC這個設(shè)計原則試圖在面向?qū)ο缶幊讨腥サ羲邢嗷ヒ蕾嚨默F(xiàn)象,。這個原則對于復(fù)雜的系統(tǒng)來說是很重要的,。它使得對象具有更好的多態(tài)性和封裝性。相互依賴的現(xiàn)象越少,,就越容易單獨測試某個組件,。
靜態(tài)類與IoC之間的問題在于靜態(tài)訪問特性,這個特性從本質(zhì)上來說,,定義了兩個類之間的綁定關(guān)系,,因為類的名稱是硬編碼的。這就意味著在單獨測試某個類的時候,,這個類不容易被模擬,。
就是說,靜態(tài)類的使用會導(dǎo)致IoC設(shè)計原則受到限制,。這是因為靜態(tài)類的使用會導(dǎo)致類之間通過名稱綁定在一起,,這使得單獨測試某個組件變得更加困難。
IoC的概念介紹
控制反轉(zhuǎn)(IOC)模式(又稱DI:Dependency Injection)就是Inversion of Control,,控制反轉(zhuǎn),。在Java開發(fā)中,,IoC意 味著將你設(shè)計好的類交給系統(tǒng)去控制,而不是在你的類內(nèi)部控制,。這稱為控制反轉(zhuǎn),。
IoC(Inversion of Control)是近年來興起的一種思想,不僅僅是編程思想,。主要是協(xié)調(diào)各組件間相互的依賴關(guān)系,,同時大大提高了組件的可移植性,組件的重用機(jī)會也變得更多,。在傳統(tǒng)的實現(xiàn)中,,由程序內(nèi)部代碼來控制程序之間的關(guān)系。我們經(jīng)常使用new關(guān)鍵字來實現(xiàn)兩組鍵間關(guān)系的組合,,這種實現(xiàn)的方式會造成組件之間耦合(一個好的設(shè)計,,不但要實現(xiàn)代碼重用,還要將組件間關(guān)系解耦),。IoC很好的解決了該問題,,它將實現(xiàn)組件間關(guān)系從程序內(nèi)部提到外部容器來管理。也就是說由容器在運行期將組件間的某種依賴關(guān)系動態(tài)的注入組件中,??刂瞥绦蜷g關(guān)系的實現(xiàn)交給了外部的容器來完成。即常說的好萊塢原則“Don't call us, we'll call you”,。
Ioc也有稱為DI(Dependecy Injection 依賴注射),,由Martin Fowler的一篇《Inversion of Control Containers and the Dependency Injection pattern》提出。
分離關(guān)注(Separation of Concerns : SOC)是Ioc模式和AOP產(chǎn)生最原始動力,,通過功能分解可得到關(guān)注點,,這些關(guān)注可以是組件Components,方面Aspects或服務(wù)Services,。
從GOF設(shè)計模式中,,我們已經(jīng)習(xí)慣一種思維編程方式:Interface Driven Design 接口驅(qū)動,接口驅(qū)動有很多好處,,可以提供不同靈活的子類實現(xiàn),,增加代碼穩(wěn)定和健壯性等等,但是接口一定是需要實現(xiàn)的,,也就是如下語句遲早要執(zhí)行:
1 | AInterface a = new AInterfaceImp(); |
AInterfaceImp是接口AInterface的一個子類,,Ioc模式可以延緩接口的實現(xiàn),根據(jù)需要實現(xiàn),,有個比喻:接口如同空的模型套,,在必要時,需要向模型套注射石膏,,這樣才能成為一個模型實體,,因此,,我們將人為控制接口的實現(xiàn)成為“注射”。
Ioc英文為 Inversion of Control,,即反轉(zhuǎn)模式,,這里有著名的好萊塢理論:你呆著別動,到時我會找你,。
其實Ioc模式也是解決調(diào)用者和被調(diào)用者之間的一種關(guān)系,,上述 AInterface實現(xiàn)語句表明當(dāng)前是在調(diào)用被調(diào)用者AInterfaceImp,由于被調(diào)用者名稱寫入了調(diào)用者的代碼中,,這產(chǎn)生了一個接口實現(xiàn)的原 罪:彼此聯(lián)系,,調(diào)用者和被調(diào)用者有緊密聯(lián)系,在UML中是用依賴 Dependency 表示,。
但是這種依賴在分離關(guān)注的思維下是不可忍耐的,,必須切割,實現(xiàn)調(diào)用者和被調(diào)用者解耦,,新的Ioc模式 Dependency Injection 模式由此產(chǎn)生了,, Dependency Injection模式是依賴注射的意思,也就是將依賴先剝離,,然后在適當(dāng)時候再注射進(jìn)入,。
一個IoC的例子
假設(shè)我們要設(shè)計一個Girl和一個Boy類,其中Girl有kiss方法,,即Girl想要Kiss一個Boy。那么,,我們的問題是,,Girl如何能夠認(rèn)識這個Boy?
在我們中國,,常見的MM與GG的認(rèn)識方式有以下幾種:1,、青梅竹馬;2,、親友介紹,;3、父母包辦
那么哪一種才是最好呢,?
青梅竹馬:Girl從小就知道自己的Boy,。
1 | public class Girl { |
2 | void kiss(){ |
3 | Boy boy = new Boy(); |
4 | } |
5 | } |
然而從開始就創(chuàng)建的Boy缺點就是無法在更換。并且要負(fù)責(zé)Boy的整個生命周期,。如果我們的Girl想要換一個怎么辦,?(筆者嚴(yán)重不支持Girl經(jīng)常更換Boy)
親友介紹:由中間人負(fù)責(zé)提供Boy來見面。
1 | public class Girl { |
2 | void kiss(){ |
3 | Boy boy = BoyFactory.createBoy(); |
4 | } |
5 | } |
親友介紹,,固然是好,。如果不滿意,,盡管另外換一個好了。但是,,親友BoyFactory經(jīng)常是以Singleton的形式出現(xiàn),,不然就是,存在于Globals,,無處不在,,無處不能。實在是太繁瑣了一點,,不夠靈活,。我為什么一定要這個親友摻和進(jìn)來呢?為什么一定要付給她介紹費呢,?萬一最好的朋友愛上了我的男朋友呢,?
父母包辦:一切交給父母,自己不用費吹灰之力,,只需要等著Kiss就好了,。
1 | public class Girl { |
2 | void kiss(Boy boy){ |
3 | // kiss boy |
4 | boy.kiss(); |
5 | } |
6 | } |
Well,這是對Girl最好的方法,,只要想辦法賄賂了Girl的父母,,并把Boy交給他。那么我們就可以輕松的和Girl來Kiss了,??磥韼浊陚鹘y(tǒng)的父母之命還真是有用哦。至少Boy和Girl不用自己瞎忙乎了,。
這就是IOC,,將對象的創(chuàng)建和獲取提取到外部。由外部容器提供需要的組件,。