ioc的概念和實現原理

本文旨在用語言(非代碼)說清楚IOC到底是什麼,沒有什麼高深的技術,園中的老牛、大蝦們看到這裏可以繞行了,以免浪費您寶貴的時間。IOC這個東西DebugLZQ早就想寫了,但是出於對文章權威性的考慮(不能誤人子弟- -!),本文主要內容來源於最近LZ看的一些國內外的關於IOC的博文、博問,所有引用到的文章,在參考博文中均已註明。

1.IOC的理論背景

我們知道在面向對象設計的軟件系統中,它的底層都是由N個對象構成的,各個對象之間通過相互合作,最終實現系統地業務邏輯[1]。

  圖1 軟件系統中耦合的對象

  如果我們打開機械式手錶的後蓋,就會看到與上面類似的情形,各個齒輪分別帶動時針、分針和秒針順時針旋轉,從而在錶盤上產生正確的時間。圖1中描述的就是這樣的一個齒輪組,它擁有多個獨立的齒輪,這些齒輪相互齧合在一起,協同工作,共同完成某項任務。我們可以看到,在這樣的齒輪組中,如果有一個齒輪出了問題,就可能會影響到整個齒輪組的正常運轉。

  齒輪組中齒輪之間的齧合關係,與軟件系統中對象之間的耦合關係非常相似。對象之間的耦合關係是無法避免的,也是必要的,這是協同工作的基礎。現在,伴隨着工業級應用的規模越來越龐大,對象之間的依賴關係也越來越複雜,經常會出現對象之間的多重依賴性關係,因此,架構師和設計師對於系統的分析和設計,將面臨更大的挑戰。對象之間耦合度過高的系統,必然會出現牽一髮而動全身的情形。

  圖2 對象之間的依賴關係

  耦合關係不僅會出現在對象與對象之間,也會出現在軟件系統的各模塊之間,以及軟件系統和硬件系統之間。如何降低系統之間、模塊之間和對象之間的耦合度,是軟件工程永遠追求的目標之一。爲了解決對象之間的耦合度過高的問題,軟件專家Michael Mattson 1996年提出了IOC理論,用來實現對象之間的“解耦”,目前這個理論已經被成功地應用到實踐當中。

2.什麼是IOC

  IOC是Inversion of Control的縮寫,多數書籍翻譯成“控制反轉”。

  1996年,Michael Mattson在一篇有關探討面向對象框架的文章中,首先提出了IOC 這個概念。對於面向對象設計及編程的基本思想,前面我們已經講了很多了,不再贅述,簡單來說就是把複雜系統分解成相互合作的對象,這些對象類通過封裝以後,內部實現對外部是透明的,從而降低了解決問題的複雜度,而且可以靈活地被重用和擴展。

  IOC理論提出的觀點大體是這樣的:藉助於“第三方”實現具有依賴關係的對象之間的解耦。如下圖:

圖3 IOC解耦過程

  大家看到了吧,由於引進了中間位置的“第三方”,也就是IOC容器,使得A、B、C、D這4個對象沒有了耦合關係,齒輪之間的傳動全部依靠“第三方”了,全部對象的控制權全部上繳給“第三方”IOC容器,所以,IOC容器成了整個系統的關鍵核心,它起到了一種類似“粘合劑”的作用,把系統中的所有對象粘合在一起發揮作用,如果沒有這個“粘合劑”,對象與對象之間會彼此失去聯繫,這就是有人把IOC容器比喻成“粘合劑”的由來。

  我們再來做個試驗:把上圖中間的IOC容器拿掉,然後再來看看這套系統:

圖4 拿掉IOC容器後的系統

  我們現在看到的畫面,就是我們要實現整個系統所需要完成的全部內容。這時候,A、B、C、D這4個對象之間已經沒有了耦合關係,彼此毫無聯繫,這樣的話,當你在實現A的時候,根本無須再去考慮B、C和D了,對象之間的依賴關係已經降低到了最低程度。所以,如果真能實現IOC容器,對於系統開發而言,這將是一件多麼美好的事情,參與開發的每一成員只要實現自己的類就可以了,跟別人沒有任何關係!

    我們再來看看,控制反轉(IOC)到底爲什麼要起這麼個名字?我們來對比一下:

    軟件系統在沒有引入IOC容器之前,如圖1所示,對象A依賴於對象B,那麼對象A在初始化或者運行到某一點的時候,自己必須主動去創建對象B或者使用已經創建的對象B。無論是創建還是使用對象B,控制權都在自己手上。

    軟件系統在引入IOC容器之後,這種情形就完全改變了,如圖3所示,由於IOC容器的加入,對象A與對象B之間失去了直接聯繫,所以,當對象A運行到需要對象B的時候,IOC容器會主動創建一個對象B注入到對象A需要的地方。

    通過前後的對比,我們不難看出來:對象A獲得依賴對象B的過程,由主動行爲變爲了被動行爲,控制權顛倒過來了,這就是“控制反轉”這個名稱的由來。

3.IOC也叫依賴注入(DI)

  2004年,Martin Fowler探討了同一個問題,既然IOC是控制反轉,那麼到底是“哪些方面的控制被反轉了呢?”,經過詳細地分析和論證後,他得出了答案:“獲得依賴對象的過程被反轉了”。控制被反轉之後,獲得依賴對象的過程由自身管理變爲了由IOC容器主動注入。於是,他給“控制反轉”取了一個更合適的名字叫做“依賴注入(Dependency Injection)”。他的這個答案,實際上給出了實現IOC的方法:注入。所謂依賴注入,就是由IOC容器在運行期間,動態地將某種依賴關係注入到對象之中。

  所以,依賴注入(DI)和控制反轉(IOC)是從不同的角度的描述的同一件事情,就是指通過引入IOC容器,利用依賴關係注入的方式,實現對象之間的解耦。

  學過IOC的人可能都看過Martin Fowler(老馬,2004年post)的這篇文章:Inversion of Control Containers and the Dependency Injection pattern[2]。

  博客園的園友EagleFish(邢瑜琨)的文章: 深度理解依賴注入(Dependence Injection)[3]對老馬那篇經典文章進行了解讀。

    CSDN黃忠成的Inside ObjectBuilder[4]也是,不過他應該來自臺灣省,用的是繁體,看不管繁體中文的,可以看園中的呂震宇博友的簡體中文版[轉]Object Builder Application Block[5] 。

4.IOC的優缺點

 In my experience, IoC using the Spring container brought the following advantages[6]:

  • flexibility
    • changing the implementation class for a widely used interface is simpler (e.g. replace a mock web service by the production instance)
    • changing the retrieval strategy for a given class is simpler (e.g. moving a service from the classpath to the JNDI tree)
    • adding interceptors is easy and done in a single place (e.g. adding a caching interceptor to a JDBC-based DAO)
  • readability
    • the project has one unified and consistent component model and is not littered with factories (e.g. DAO factories)
    • the code is briefer and is not littered without dependency lookup code (e.g. calls to JNDI InitialContext)
  • testability
    • dependencies are easy to replace mocks when they're exposed through a constructor or setter
    • easier testing leads to more testing
    • more testing leads to better code quality, lower coupling, higher cohesion

  使用IOC框架產品能夠給我們的開發過程帶來很大的好處,但是也要充分認識引入IOC框架的缺點,做到心中有數,杜絕濫用框架[1]。

    第一、軟件系統中由於引入了第三方IOC容器,生成對象的步驟變得有些複雜,本來是兩者之間的事情,又憑空多出一道手續,所以,我們在剛開始使用IOC框架的時候,會感覺系統變得不太直觀。所以,引入了一個全新的框架,就會增加團隊成員學習和認識的培訓成本,並且在以後的運行維護中,還得讓新加入者具備同樣的知識體系。

    第二、由於IOC容器生成對象是通過反射方式,在運行效率上有一定的損耗。如果你要追求運行效率的話,就必須對此進行權衡。

    第三、具體到IOC框架產品(比如:Spring)來講,需要進行大量的配製工作,比較繁瑣,對於一些小的項目而言,客觀上也可能加大一些工作成本。

    第四、IOC框架產品本身的成熟度需要進行評估,如果引入一個不成熟的IOC框架產品,那麼會影響到整個項目,所以這也是一個隱性的風險。

    我們大體可以得出這樣的結論:一些工作量不大的項目或者產品,不太適合使用IOC框架產品。另外,如果團隊成員的知識能力欠缺,對於IOC框架產品缺乏深入的理解,也不要貿然引入。最後,特別強調運行效率的項目或者產品,也不太適合引入IOC框架產品,像WEB2.0網站就是這種情況。

5.IOC容器的技術剖析

  IOC中最基本的技術就是“反射(Reflection)”編程,目前.Net C#、Java和PHP5等語言均支持,其中PHP5的技術書籍中,有時候也被翻譯成“映射”。有關反射的概念和用法,大家應該都很清楚,通俗來講就是根據給出的類名(字符串方式)來動態地生成對象。這種編程方式可以讓對象在生成時才決定到底是哪一種對象。反射的應用是很廣泛的,很多的成熟的框架,比如象Java中的Hibernate、Spring框架,.Net中 NHibernate、Spring.Net框架都是把“反射”做爲最基本的技術手段。

6.IOC容器的一些產品

  Sun ONE技術體系下的IOC容器有:輕量級的有Spring、Guice、Pico Container、Avalon、HiveMind;重量級的有EJB;不輕不重的有JBoss,Jdon等等。Spring框架作爲Java開發中SSH(Struts、Spring、Hibernate)三劍客之一,大中小項目中都有使用,非常成熟,應用廣泛,EJB在關鍵性的工業級項目中也被使用,比如某些電信業務。

    .Net技術體系下的IOC容器有:Spring.Net、Castle等等。Spring.Net是從Java的Spring移植過來的IOC容器,Castle的IOC容器就是Windsor部分。它們均是輕量級的框架,比較成熟,其中Spring.Net已經被廣泛應用於各種項目中。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章