對IOC、DI本質理解

IoC: Inversion of Control,控制反轉, 控制權從應用程序轉移到框架(如IoC容器),是框架共有特性

1、爲什麼需要IoC容器
1.1、應用程序主動控制對象的實例化及依賴裝配
Java代碼 收藏代碼

A a = new AImpl();  
B b = new BImpl();  
a.setB(b);  

本質:創建對象,主動實例化,直接獲取依賴,主動裝配
缺點:更換實現需要重新編譯源代碼
很難更換實現、難於測試
耦合實例生產者和實例消費者

Java代碼 收藏代碼

A a = AFactory.createA();  
B b = BFactory.createB();  
a.setB(b);  

本質:創建對象,被動實例化,間接獲取依賴,主動裝配 (簡單工廠)
缺點:更換實現需要重新編譯源代碼
很難更換實現、難於測試

Java代碼 收藏代碼

A a = Factory.create(“a”);  
B b = Factory.create(“b”);  
a.setB(b);   

Xml代碼 收藏代碼

a=AImpl  
b=BImpl  

本質:創建對象,被動實例化,間接獲取依賴, 主動裝配
(工廠+反射+properties配置文件、
Service Locator、註冊表)
缺點:冗餘的依賴裝配邏輯

我想直接:
//返回裝配好的a
Java代碼 收藏代碼

A a = Factory.create(“a”);   

1.2、可配置通用工廠:工廠主動控制,應用程序被動接受,控制權從應用程序轉移到工廠
Java代碼 收藏代碼

//返回裝配好的a   
A a = Factory.create(“a”);  

Java代碼 收藏代碼

<bean id=“a” class=“AImpl”>  
    <property name=“b” ref=“b”/>  
</bean>  
<bean id=“b” class=“BImpl”/>  

本質:創建對象和裝配對象,
被動實例化,被動接受依賴,被動裝配
(工廠+反射+xml配置文件)
缺點:不通用

步驟:
1、讀取配置文件根據配置文件通過反射
創建AImpl
2、發現A需要一個類型爲B的屬性b
3、到工廠中找名爲b的對象,發現沒有,讀取
配置文件通過反射創建BImpl
4、將b對象裝配到a對象的b屬性上
【組件的配置與使用分離開(解耦、更改實現無需修改源代碼、易於更好實現) 】

1.3、 IoC(控制反轉)容器:容器主動控制
Java代碼 收藏代碼

//返回裝配好的a   
A a = ApplicationContext.getBean(“a”);  

Java代碼 收藏代碼

<bean id=“a” class=“AImpl”>  
    <property name=“b” ref=“b”/>  
</bean>  
<bean id=“b” class=“BImpl”/>  

本質:創建對象和裝配對象、管理對象生命週期
被動實例化,被動接受依賴,被動裝配
(工廠+反射+xml配置文件)
通用

IoC容器:實現了IoC思想的容器就是IoC容器

2、IoC容器特點
【1】無需主動new對象;而是描述對象應該如何被創建即可
IoC容器幫你創建,即被動實例化;
【2】不需要主動裝配對象之間的依賴關係,而是描述需要哪個服務(組件),
IoC容器會幫你裝配(即負責將它們關聯在一起),被動接受裝配;
【3】主動變被動,好萊塢法則:別打電話給我們,我們會打給你;
【4】迪米特法則(最少知識原則):不知道依賴的具體實現,只知道需要提供某類服務的對象(面向抽象編程),鬆散耦合,一個對象應當對其他對象有儘可能少的瞭解,不和陌生人(實現)說話
【5】IoC是一種讓服務消費者不直接依賴於服務提供者的組件設計方式,是一種減少類與類之間依賴的設計原則。

3、理解IoC容器問題關鍵:控制的哪些方面被反轉了?
1、誰控制誰?爲什麼叫反轉? —— IoC容器控制,而以前是應用程序控制,所以叫反轉
2、控制什麼? —— 控制應用程序所需要的資源(對象、文件……)
3、爲什麼控制? —— 解耦組件之間的關係
4、控制的哪些方面被反轉了? —— 程序的控制權發生了反轉:從應用程序轉移到了IoC容器。

思考:
1: IoC/DI等同於工廠嗎?
2: IoC/DI跟以前的方式有什麼不一樣?
領會:主從換位的思想

4、實現了IoC思想的容器就是輕量級容器嗎?
如果僅僅因爲使用了控制反轉就認爲這些輕量級容器與衆不同,就好象在說我的轎車與衆不同因爲它有四個輪子?

容器:提供組件運行環境,管理組件聲明週期(不管組件如何創建的以及組件之間關係如何裝配的);

IoC容器不僅僅具有容器的功能,而且還具有一些其他特性—如依賴裝配

控制反轉概念太廣泛,讓人迷惑,後來Martin Fowler 提出依賴注入概念
Martin Fowler Inversion of Control Containers and the Dependency Injection pattern
http://martinfowler.com/articles/injection.html

DI

2、什麼是DI
DI:依賴注入(Dependency Injection) :用一個單獨的對象(裝配器)來裝配對象之間的依賴關係 。

2、理解DI問題關鍵
誰依賴於誰? ——- 應用程序依賴於IoC容器
爲什麼需要依賴? ——- 應用程序依賴於IoC容器裝配類之間的關係
依賴什麼東西? ——- 依賴了IoC容器的裝配功能
誰注入於誰? ——- IoC容器注入應用程序
注入什麼東西? ——- 注入應用程序需要的資源(類之間的關係)

更能描述容器其特點的名字——“依賴注入”(Dependency Injection)
IoC容器應該具有依賴注入功能,因此也可以叫DI容器

3、DI優點
【1】幫你看清組件之間的依賴關係,只需要觀察依賴注入的機制(setter/構造器),就可以掌握整個依賴(類與類之間的關係)。
【2】組件之間的依賴關係由容器在運行期決定,形象的來說,即由容器動態的將某種依賴關係注入到組件之中。
【3】依賴注入的目標並非爲軟件系統帶來更多的功能,而是爲了提升組件重用的概率,併爲系統搭建一個靈活、可擴展的平臺。通過依賴注入機制,我們只需要通過簡單的配置,而無需任何代碼就可指定目標需要的資源,完成自身的業務邏輯,而不用關心具體的資源來自何處、由誰實現。

使用DI限制:組件和裝配器(IoC容器)之間不會有依賴關係,因此組件無法從裝配器那裏獲得更多服務,只能獲得配置信息中所提供的那些。

4、實現方式
1、構造器注入
2、setter注入
3、接口注入:在接口中定義需要注入的信息,並通過接口完成注入
@Autowired
public void prepare(MovieCatalog movieCatalog,
CustomerPreferenceDao customerPreferenceDao) {
this.movieCatalog = movieCatalog;
this.customerPreferenceDao = customerPreferenceDao;
}

使用IoC/DI容器開發需要改變的思路
1、應用程序不主動創建對象,但要描述創建它們的方式。
2、在應用程序代碼中不直接進行服務的裝配,但要配置文件中描述哪一個組件需要哪一項服務。容器負責將這些裝配在一起。

其原理是基於OO設計原則的The Hollywood Principle:Don‘t call us, we’ll call you(別找我,我會來找你的)。也就是說,所有的組件都是被動的(Passive),所有的組件初始化和裝配都由容器負責。組件處在一個容器當中,由容器負責管理。

IoC容器功能:實例化、初始化組件、裝配組件依賴關係、負責組件生命週期管理。

本質:
IoC:控制權的轉移,由應用程序轉移到框架;
IoC/DI容器:由應用程序主動實例化對象變被動等待對象(被動實例化);
DI: 由專門的裝配器裝配組件之間的關係;
IoC/DI容器:由應用程序主動裝配對象的依賴變應用程序被動接受依賴

關於IoC/DI與DIP之間的關係 詳見 http://www.iteye.com/topic/1122310?page=5#2335746

IoC/DI與迪米特法則 詳見http://www.iteye.com/topic/1122310?page=5#2335748

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章