用語言 (非程式碼) 說清楚 IoC 到底是什麼

leienshu發表於2019-01-23

看了很多寫IOC的文章,都是一上來就是程式碼,看得人腦袋發暈,不過作為新手,我覺得更適合大家的還是圖形。下面給大家轉一篇博文,對Laravel的新手我覺得很有幫助:
作者:DebugLZQ

本文旨在用語言(非程式碼)說清楚IOC到底是什麼,沒有什麼高深的技術,園中的老牛、大蝦們看到這裡可以繞行了,以免浪費您寶貴的時間。IOC這個東西DebugLZQ早就想寫了,但是出於對文章權威性的考慮(不能誤人子弟- -!),本文主要內容來源於最近樓主看的一些國內外的關於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已經被廣泛應用於各種專案中。

總之就是很多很多,不甚列舉.....

7.參考博文

[1] 架構師之路(39)---IoC框架 ,王澤賓,CSDN, 2009.

[2] Inversion of Control Containers and the Dependency Injection pattern ,Martin Fowler,2004.

[3] 深度理解依賴注入(Dependence Injection),EagleFish(邢瑜琨), 部落格園, 2007.

[4]Inside ObjectBuilder ,黃忠成, CSDN, 2006.

[5][轉]Object Builder Application Block ,呂震宇,部落格園, 2006.

[6]link

題外話:
看過的東西寫整理一下寫下來,可以分享給各位博友,說不定對誰就有幫助;

二可以加深自己的認識,整理的過程本來就是一種認識的加深;

三是方便將來自己可能的查閱。

希望對你有幫助~
原文連結:點這裡

求知若飢,虛心若愚!

相關文章