什麼是IoC 和 DI

2021-10-16 09:45:34 字數 3351 閱讀 6840

ioc 即控制反轉,di即依賴注入

簡單來說,ioc是一種思想,而di是這種思想的具體實現方式

要了解控制反轉( inversion of control ),有必要先了解軟體設計的乙個重要思想:依賴倒置原則(dependency inversion principle )。

假設我們設計一輛汽車:先設計輪子,然後根據輪子大小設計底盤,接著根據底盤設計車身,最後根據車身設計好整個汽車。這裡就出現了乙個「依賴」關係:汽車依賴車身,車身依賴底盤,底盤依賴輪子。

這樣的設計看起來沒問題,但是可維護性卻很低。假設設計完工之後,上司卻突然說根據市場需求的變動,要我們把車子的輪子設計都改大一碼。這下我們就蛋疼了:因為我們是根據輪子的尺寸設計的底盤,輪子的尺寸一改,底盤的設計就得修改;同樣因為我們是根據底盤設計的車身,那麼車身也得改,同理汽車設計也得改——整個設計幾乎都得改!

我們現在換一種思路。我們先設計汽車的大概樣子,然後根據汽車的樣子來設計車身,根據車身來設計底盤,最後根據底盤來設計輪子。這時候,依賴關係就倒置過來了:輪子依賴底盤, 底盤依賴車身, 車身依賴汽車。

這時候,上司再說要改動輪子的設計,我們就只需要改動輪子的設計,而不需要動底盤,車身,汽車的設計了。

這就是依賴倒置原則——把原本的高層建築依賴底層建築「倒置」過來,變成底層建築依賴高層建築。高層建築決定需要什麼,底層去實現這樣的需求,但是高層並不用管底層是怎麼實現的。這樣就不會出現前面的「牽一發動全身」的情況。

控制反轉(inversion of control)就是依賴倒置原則的一種**設計的思路。具體採用的方法就是所謂的依賴注入(dependency injection)。其實這些概念初次接觸都會感到雲裡霧裡的。說穿了,這幾種概念的關係大概如下:

為了理解這幾個概念,我們還是用上面汽車的例子。只不過這次換成**。我們先定義四個class,車,車身,底盤,輪胎。然後初始化這輛車,最後跑這輛車。**結構如下:

這樣,就相當於上面第乙個例子,上層建築依賴下層建築——每乙個類的建構函式都直接呼叫了底層**的建構函式。假設我們需要改動一下輪胎(tire)類,把它的尺寸變成動態的,而不是一直都是30。我們需要這樣改:

由於我們修改了輪胎的定義,為了讓整個程式正常執行,我們需要做以下改動:

由此我們可以看到,僅僅是為了修改輪胎的建構函式,這種設計卻需要修改整個上層所有類的建構函式!在軟體工程中,這樣的設計幾乎是不可維護的——在實際工程專案中,有的類可能會是幾千個類的底層,如果每次修改這個類,我們都要修改所有以它作為依賴的類,那軟體的維護成本就太高了。

所以我們需要進行控制反轉(ioc),及上層控制下層,而不是下層控制著上層。我們用依賴注入(dependency injection)這種方式來實現控制反轉。所謂依賴注入,就是把底層類作為引數傳入上層類,實現上層類對下層類的「控制」。這裡我們用構造方法傳遞的依賴注入方式重新寫車類的定義:

這裡我們再把輪胎尺寸變成動態的,同樣為了讓整個系統順利執行,我們需要做如下修改:

看到沒?這裡我只需要修改輪胎類就行了,不用修改其他任何上層類。這顯然是更容易維護的**。不僅如此,在實際的工程中,這種設計模式還有利於不同組的協同合作和單元測試:比如開發這四個類的分別是四個不同的組,那麼只要定義好了介面,四個不同的組可以同時進行開發而不相互受限制;而對於單元測試,如果我們要寫car類的單元測試,就只需要mock一下framework類傳入car就行了,而不用把framework, bottom, tire全部new一遍再來構造car。

這裡我們是採用的建構函式傳入的方式進行的依賴注入。其實還有另外兩種方法:setter傳遞和介面傳遞。這裡就不多講了,核心思路都是一樣的,都是為了實現控制反轉。

看到這裡你應該能理解什麼控制反轉和依賴注入了。那什麼是控制反轉容器(ioc container)呢?其實上面的例子中,對車類進行初始化的那段**發生的地方,就是控制反轉容器。

顯然你也應該觀察到了,因為採用了依賴注入,在初始化的過程中就不可避免的會寫大量的new。這裡ioc容器就解決了這個問題。這個容器可以自動對你的**進行初始化,你只需要維護乙個configuration(可以是xml可以是一段**),而不用每次初始化一輛車都要親手去寫那一大段初始化的**。這是引入ioc container的第乙個好處。

ioc container的第二個好處是:我們在建立例項的時候不需要了解其中的細節。在上面的例子中,我們自己手動建立乙個車instance時候,是從底層往上層new的:

這個過程中,我們需要了解整個car/framework/bottom/tire類建構函式是怎麼定義的,才能一步一步new/注入。

這裡ioc container可以直接隱藏具體的建立例項的細節,在我們來看它就像乙個工廠:

我們就像是工廠的客戶。我們只需要向工廠請求乙個car例項,然後它就給我們按照config建立了乙個car例項。我們完全不用管這個car例項是怎麼一步一步被建立出來。

實際專案中,有的service class可能是十年前寫的,有幾百個類作為它的底層。假設我們新寫的乙個api需要例項化這個service,我們總不可能回頭去搞清楚這幾百個類的建構函式吧?ioc container的這個特性就很完美的解決了這類問題——因為這個架構要求你在寫class的時候需要寫相應的config檔案,所以你要初始化很久以前的service類的時候,前人都已經寫好了config檔案,你直接在需要用的地方注入這個service就可以了。這大大增加了專案的可維護性且降低了開發難度。

Spring之到底什麼是IOC和DI?

什麼是ioc容器?ioc全名 inversion of control,翻譯過來就是控制反轉。什麼是控制反轉?這個是物件導向的一種設計原則,可以用來減低計算機 之間的耦合度 模組及模組之間資訊或引數依賴的程度 其中最常見的方式叫做依賴注入 依賴注入就是把本來應該在程式中有的依賴在外部注入到程式之中 ...

什麼是IoC和DI?什麼是依賴注入和控制反轉?

這東西,簡單一點說得清楚就對了。di dependency injection,依賴注入 依賴注入的概念就是將物件交給spring容器託管,要用的時候由spring容器注入到類中去用,spring是容器通過xml來宣告物件,另外,spring中的dao 資料訪問物件 介面 和dao.impl imp...

到底什麼是控制反轉 IOC 和依賴注入 DI

一 到底什麼是控制反轉 ioc 和依賴注入 di 1 控制反轉 2 依賴注入 3 二者關係 在程式設計中,當我們用到乙個物件時,首先需要主動建立它,但是在大型專案中,大家分工合作,也許我們要用到的物件對應的類還沒有被編寫出來,我們肯定沒法辦new出來,這個時候就有了spring框架,物件交給spri...