一.IoC的基礎知識以及原理:
1.IoC理論的背景:在采用面向對象方法設計的軟件系統中,底層實現都是由N個對象組成的,所有的對象通過彼此的合作,最終實現系統的業務邏輯。即軟件系統中對象之間的耦合,對象A和對象B之間有關聯,對象B又和對象C有依賴關系,這樣對象和對象之間有着復雜的依賴關系,所以才有了控制反轉這個理論。
2.什么是控制反轉(IoC):
(1).IoC是Inversion of Control的縮寫,有的翻譯成“控制反轉”,還有翻譯成為“控制反向”或者“控制倒置”。
(2).1996年,Michael Mattson在一篇有關探討面向對象框架的文章中,首先提出了IoC 這個概念。簡單來說就是把復雜系統分解成相互合作的對象,這些對象類通過封裝以后,內部實現對外部是透明的,從而降低了解決問題的復雜度,而且可以靈活地被重用和擴展。IoC理論提出的觀點大體是這樣的:借助於“第三方”實現具有依賴關系的對象之間的解耦,如下圖所示:
即把各個對象類封裝之后,通過IoC容器來關聯這些對象類。這樣對象與對象之間就通過IoC容器進行聯系,但對象與對象之間並沒有什么直接聯系。
如果去掉IoC容器后系統中的對象A與對象B就有了直接關系,如下圖所示:
比如好多的對象類要關聯起來的話,就會變得很復雜,如下圖所示:
所以提出IoC控制反轉是很有必要的。
(3).為什么要把這種方式叫做控制反轉呢?
— 軟件系統在沒有引入IoC容器之前,對象A依賴對象B,那么A對象在實例化或者運行到某一點的時候,自己必須主動創建對象B或者使用已經創建好的對象B,其中不管是創建還是使用已創建的對象B,控制權都在我們自己手上。
— 如果軟件系統引入了Ioc容器之后,對象A和對象B之間失去了直接聯系,所以,當對象A實例化和運行時,如果需要對象B的話,IoC容器會主動創建一個對象B注入到對象A所需要的地方。
— 通過前面的對比,可以看到對象A獲得依賴對象B的過程,由主動行為變成了被動行為,即把創建對象交給了IoC容器處理,控制權顛倒過來了,這就是控制反轉的由來!
3.IoC的別名:依賴注入(DI)
(1).2004年,Martin Fowler探討了同一個問題,既然IoC是控制反轉,那么到底是“哪些方面的控制被反轉了呢?”,經過詳細地分析和論證后,他得出了答案:“獲得依賴對象的過程被反轉了”。控制被反轉之后,獲得依賴對象的過程由自身管理對象變為由IoC容器主動注入。於是,他給“控制反轉”取了一個更合適的名字叫做“依賴注入(Dependency Injection,DI)”。他的這個答案,實際上給出了實現IoC的方法:注入。
(2).所謂依賴注入,就是由IoC容器在運行期間,動態地將某種依賴關系注入到對象之中。
(3).所以,依賴注入(DI)和控制反轉(IoC)是從不同的角度描述的同一件事情,就是指通過引入IoC容器,利用依賴關系注入的方式,實現對象之間的解耦。
4.使用IoC的好處:
(1).可維護性比較好,非常便於進行單元測試,便於調試程序和診斷故障。代碼中的每一個Class都可以單獨測試,彼此之間互不影響,只要保證自身的功能無誤即可,這就是組件之間低耦合或者無耦合帶來的好處。
(2).每個開發團隊的成員都只需要關注自己要實現的業務邏輯,完全不用去關心其他人的工作進展,因為你的任務跟別人沒有任何關系,你的任務可以單獨測試,你的任務也不用依賴於別人的組件,再也不用扯不清責任了。所以,在一個大中型項目中,團隊成員分工明確、責任明晰,很容易將一個大的任務划分為細小的任務,開發效率和產品質量必將得到大幅度的提高。
(3).可復用性好,我們可以把具有普遍性的常用組件獨立出來,反復應用到項目中的其它部分,或者是其它項目,當然這也是面向對象的基本特征。顯然,IoC更好地貫徹了這個原則,提高了模塊的可復用性。符合接口標准的實現,都可以插接到支持此標准的模塊中。
(4).IoC生成對象的方式轉為外置方式,也就是把對象生成放在配置文件里進行定義,這樣,當我們更換一個實現子類將會變得很簡單,只要修改配置文件就可以了,完全具有熱插撥的特性。
5.IoC的原理:控制反轉是Spring框架的核心。其原理是基於面向對象(OO)設計原則的The Hollywood Principle:Don't call us, we'll call you(別找我,我會來找你的)。也就是說,所有的組件都是被動的,所有的組件初始化和調用都由容器負責。組件處在一個容器當中,由容器負責管理。簡單的來講,就是由容器控制程序之間的關系,而非傳統實現中,由程序代碼直接操控,即在一個類中調用另外一個類。這也就是所謂“控制反轉”的概念所在:控制權由應用代碼中轉到了外部容器,控制權的轉移,即所謂反轉。
6.工廠模式:
(1).在Spring IoC中經常用到一個設計模式,即工廠模式。工廠模式提供創建對象的接口。
(2).工廠模式是指當應用程序中甲組件需要乙組件協助時,並不是在甲組件中直接實例化乙組件對象,而是通過乙組件的工廠獲取,即該工廠可以生成某一類型組件的實例對象。在這種模式下,甲組件無需與乙組件以硬編碼的方式耦合在一起,而只需與乙組件的工廠耦合。
(3)接下來附上一個工廠模式的例子:
首先,新建一個Java項目FactoryTest,然后新建一個接口Animal,放在com.inter包下:
Animal.java文件代碼如下:
- package com.inter;
- public interface Animal {
- void eat();//定義抽象的吃方法
- void shout();//定義抽象的叫方法
- }
然后分別新建兩個JavaBean,即Dog類和Cat類,放在com.bean包下,並都實現了Animal這個接口:
Dog.java文件代碼如下:
- package com.bean;
- import com.inter.Animal;
- public class Dog implements Animal{
- @Override
- public void eat() {
- // TODO Auto-generated method stub
- System.out.println("狗吃狗糧");
- }
- @Override
- public void shout() {
- // TODO Auto-generated method stub
- System.out.println("狗汪汪叫");
- }
- }
Cat.java文件代碼如下:
- package com.bean;
- import com.inter.Animal;
- public class Cat implements Animal{
- @Override
- public void eat() {
- // TODO Auto-generated method stub
- System.out.println("貓吃貓糧");
- }
- @Override
- public void shout() {
- // TODO Auto-generated method stub
- System.out.println("貓喵喵叫");
- }
- }
接着新建一個工廠類Factory,放在com.factory,使得Dog類和Cat類在工廠類上關聯起來,Dog類和Cat類並不直接關聯:
Factory.java文件代碼如下:
- package com.factory;
- import com.bean.Cat;
- import com.bean.Dog;
- import com.inter.Animal;
- public class Factory {
- public Animal getAnimal(String name){
- if(name.equals("dog")){
- return new Dog();
- }else if(name.equals("cat")){
- return new Cat();
- }else{
- throw new IllegalArgumentException("參數不正確!");
- }
- }
- }
最后,寫一個Test測試類,放在com.test包下,代碼如下:
- package com.test;
- import com.factory.Factory;
- import com.inter.Animal;
- public class Test {
- public static void main(String[] args){
- Animal a=null;
- a=(Animal) new Factory().getAnimal("dog");
- a.eat();
- a.shout();
- a=(Animal)new Factory().getAnimal("cat");
- a.eat();
- a.shout();
- }
- }
運行后,效果如下: