本文轉載自知乎問題回答:Spring IoC有什麼好處? 作者: Sevenvidia
設計模式7大原則
為什麼會有人說設計模式已死呢,因為spring這些框架幫你做好了類和物件的管理,讓你寫程式碼的時候只專注於你實現的功能,而不是設計。先來看看設計模式的7大原則:
-
開放-封閉原則
-
單一職責原則
-
依賴倒轉原則
-
最小知識原則
-
介面隔離原則
-
合成/聚合複用原則
-
里氏代換原則,任何基類可以出現的地方,子類一定可以出現
依賴倒置
假設我們設計一輛汽車:先設計輪子,然後根據輪子大小設計底盤,接著根據底盤設計車身,最後根據車身設計好整個汽車。這裡就出現了一個“依賴”關係:汽車依賴車身,車身依賴底盤,底盤依賴輪子。


這時候,上司再說要改動輪子的設計,我們就只需要改動輪子的設計,而不需要動底盤,車身,汽車的設計了。這就是依賴倒置原則——把原本的高層建築依賴底層建築“倒置”過來,變成底層建築依賴高層建築。高層建築決定需要什麼,底層去實現這樣的需求,但是高層並不用管底層是怎麼實現的。這樣就不會出現前面的“牽一髮動全身”的情況。
控制反轉(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的:


IoC Container可以直接隱藏具體的建立例項的細節.
這是我看到的說控制反轉最清楚的文章,大家理解的時候不要在乎這些框架,而是這個設計本身,所以從設計模式的原則講起,下面繼續講講spring的一些實戰,以及簡單的造兩個小輪子。