IoC全名Inversion of Control,若是中文硬要翻譯過來的話,就是「控制反轉」。初看IoC,從字面上不容易瞭解其意義,我以爲要了解IoC,要先從Dependency Inversion開始瞭解,也就是依賴關係的反轉。java
Dependency Inversion在下面這篇文章中有了清楚的解釋:http://www.objectmentor.com/publications/dip.pdf框架
簡單的說,在模組設計時,高層的抽象模組一般是與業務相關的模組,它應該具備重用性,而不依賴於低層的實做模組,例如若是低層模組原先是軟碟存取模式,而高層模組是個存檔備份的需求,若是高層模組直接叫用低層模組的函式,則就對其產生了依賴關係。this
舉個例子,例以下面這個程式:spa
#include <floppy.h> .... void save() { .... saveToFloppy() } }
因爲save()程式依賴於saveToFloppy(),若是今天要更換低層的存儲模組爲Usb碟,則這個程式沒有辦法重用,必須加以修改才行,低層模組的更動形成了高層模組也必須跟着更動,這不是一個好的設計方式,咱們但願模組都依賴於模組的抽象,這樣才能夠重用高層的業務設計。翻譯
若是以物件導向的方式來設計,依賴反轉(Dependency Inversion)的解釋變爲程式不該依賴實做,而是依賴於抽象,實做必須依賴於抽象。咱們來看看下面這個Java程式:設計
public class BusinessObject { private FloppyWriter writer = new FloppyWriter(); .... public void save() { ... writer.saveToFloppy(); } }
在這個程式中,BusinessObject的存檔依賴於實際的FloppyWriter,若是今天咱們想要將存檔改成存至Usb碟,咱們必須修改或繼承BusinessObject進行擴展,而沒法直接使用BusinessObject。code
若是透過介面的宣告,能夠改進此一狀況,例如:中間件
public interface IDeviceWriter { public void saveToDevice(); } public class BusinessObject { private IDeviceWriter writer; public void setDeviceWriter(IDeviceWriter writer) { this .writer = writer; } public void save() { .... writer.saveToDevice(); }}
這樣一來,BusinessObject就是可重用的,若是今天我有存儲至Floppy或Usb碟的需求,我只要實做IDeviceWriter便可,而不用修改BusinessObject:繼承
public class FloppyWriter implement IDeviceWriter { public void saveToDevice() { .... //實際儲存至Floppy的程式碼 }} public class UsbDiskWriter implement IDeviceWriter { public void saveToDevice() { .... //實際儲存至UsbDisk的程式碼 }}
從這個角度來看,Dependency Inversion的意思便是程式不依賴於實做,而是程式與實做都要依賴於抽象。ip
IoC的Control是控制的意思,其實其背後的意義也是一種依賴關係的轉移,若是A依賴於B,其意義便是B擁有控制權,咱們要轉移這種關係,因此依賴關係的反轉便是控制關係的反轉,藉由控制關係的轉移,咱們能夠得到元件的可重用性,在上面的Java程式中,整個控制權從實際的FloppyWriter轉移至抽象的IDeviceWriter介面上,使得BusinessObject、FloppyWriter、 UsbDiskWriter這幾個實現依賴於抽象的IDeviceWriter介面。
從容器(Container)的角度,程式的業務邏輯部份應是能夠重用的,不該受到所使用框架或容器的影響,由於咱們可能轉移整個業務邏輯至其它的框架或容器,若是業務邏輯過於依賴容器,則轉移至其它的框架或容器時,就會發生困難。
IoC在容器的角度,能夠用這麼一句好萊塢名言來表明:"Don't call me, I'll call you." 以程式的術語來講的話,就是「不要向容器要求您所須要的(物件)資源,容器會自動將這些物件給您!」。IoC要求的是容器不侵入應用程式自己,應用程式自己提供好介面,容器能夠透過這些介面將所需的資源注至程式中,應用程式不向容器主動要求資源,故而不會依賴於容器的元件,應用程式自己不會意識到正被容器使用,能夠隨時從容器中脫離轉移而不用做任何的修改,而這個特性正是一些業務邏輯中間件最須要的。