wonderer's program

          everything will be better
          posts - 19, comments - 6, trackbacks - 0, articles - 0
            BlogJava :: 首頁 :: 新隨筆 :: 聯系 :: 聚合  :: 管理

          轉:什么是IOC

          Posted on 2007-10-28 16:50 wonderer 閱讀(690) 評論(0)  編輯  收藏 所屬分類: java

          什么是IOC呢,在網上搜到了一非常有意思的講解。
          IoC就是Inversion of Control,控制反轉。在Java開發中,IoC意味著將你設計好的類交給系統去控制,而不是在你的類內部控制。這稱為控制反轉。

          下面我們以幾個例子來說明什么是IoC

          假設我們要設計一個Girl和一個Boy類,其中Girl有kiss方法,即Girl想要Kiss一個Boy。那么,我們的問題是,Girl如何能夠認識這個Boy?

          在我們中國,常見的MM與GG的認識方式有以下幾種
          1 青梅竹馬; 2 親友介紹; 3 父母包辦
          那么哪一種才是最好呢?

          青梅竹馬:Girl從小就知道自己的Boy。

             1: public class Girl { 
             2:     void kiss(){ 
             3:     Boy boy = new Boy(); 
             4:     } 
             5: }

          然而從開始就創建的Boy缺點就是無法在更換。并且要負責Boy的整個生命周期。如果我們的Girl想要換一個怎么辦?(嚴重不支持Girl經常更換Boy,#_#)

          親友介紹:由中間人負責提供Boy來見面

             1: public class Girl { 
             2:     void kiss(){ 
             3:         Boy boy = BoyFactory.createBoy(); 
             4:     } 
             5: }

          親友介紹,固然是好。如果不滿意,盡管另外換一個好了。但是,親友BoyFactory經常是以Singleton的形式出現,不然就是,存在于Globals,無處不在,無處不能。實在是太繁瑣了一點,不夠靈活。我為什么一定要這個親友摻和進來呢?為什么一定要付給她介紹費呢?萬一最好的朋友愛上了我的男朋友呢?

          父母包辦:一切交給父母,自己不用費吹灰之力,只需要等著Kiss就好了。

             1: public class Girl { 
             2:     void kiss(Boy boy){ 
             3:         // kiss boy 
             4:         boy.kiss(); 
             5:     } 
             6: }

          Well,這是對Girl最好的方法,只要想辦法賄賂了Girl的父母,并把Boy交給他。那么我們就可以輕松的和Girl來Kiss了。看來幾千年傳統的父母之命還真是有用哦。至少Boy和Girl不用自己瞎忙乎了。

          這就是IOC,將對象的創建和獲取提取到外部。由外部容器提供需要的組件。

          我們知道好萊塢原則:“Do not call us, we will call you.” 意思就是,You, girlie, do not call the boy. We will feed you a boy。

          我們還應該知道依賴倒轉原則即 Dependence Inversion Princinple,DIP

          Eric Gamma說,要面向抽象編程。面向接口編程是面向對象的核心。

          組件應該分為兩部分,即 Service, 所提供功能的聲明 Implementation, Service的實現

          好處是:多實現可以任意切換,防止 “everything depends on everything” 問題.即具體依賴于具體。

          所以,我們的Boy應該是實現Kissable接口。這樣一旦Girl不想kiss可惡的Boy的話,還可以kiss可愛的kitten和慈祥的grandmother。
          二、IOC的type

          IoC的Type指的是Girl得到Boy的幾種不同方式。我們逐一來說明。

          IOC type 0:不用IOC

             1: public class Girl implements Servicable { 
             2:     private Kissable kissable; 
             3:     public Girl() { 
             4:         kissable = new Boy(); 
             5:     } 
             6:     public void kissYourKissable() { 
             7:         kissable.kiss(); 
             8:     } 
             9: }

          Girl自己建立自己的Boy,很難更換,很難共享給別人,只能單獨使用,并負責完全的生命周期。

          IOC type 1,先看代碼:代碼

             1: public class Girl implements Servicable { 
             2:  
             3:     Kissable kissable; 
             4:  
             5:     public void service(ServiceManager mgr) { 
             6:         kissable = (Kissable) mgr.lookup(“kissable”); 
             7:     } 
             8:  
             9:     public void kissYourKissable() { 
            10:         kissable.kiss(); 
            11:     } 
            12: }

          這種情況出現于Avalon Framework。一個組件實現了Servicable接口,就必須實現service方法,并傳入一個ServiceManager。其中會含有需要的其它組件。只需要在service方法中初始化需要的Boy。

          另外,J2EE中從Context取得對象也屬于type 1。它依賴于配置文件。

          IOC type 2:

             1: public class Girl { 
             2:  
             3:     private Kissable kissable; 
             4:  
             5:     public void setKissable(Kissable kissable) { 
             6:         this.kissable = kissable; 
             7:     } 
             8:  
             9:     public void kissYourKissable() { 
            10:         kissable.kiss(); 
            11:     } 
            12: }

          Type 2出現于Spring Framework,是通過JavaBean的set方法來將需要的Boy傳遞給Girl。它必須依賴于配置文件。

          IOC type 3:

             1: public class Girl { 
             2:  
             3:     private Kissable kissable; 
             4:  
             5:     public Girl(Kissable kissable) { 
             6:         this.kissable = kissable; 
             7:     } 
             8:  
             9:     public void kissYourKissable() { 
            10:         kissable.kiss(); 
            11:     } 
            12: }
            13:  

          這就是PicoContainer的組件 。通過構造函數傳遞Boy給Girl

          PicoContainer container = new DefaultPicoContainer();
          container.registerComponentImplementation(Boy.class);
          container.registerComponentImplementation(Girl.class);
          Girl girl = (Girl) container.getComponentInstance(Girl.class);
          girl.kissYourKissable();

          參考資料

          1 http://www.picocontainer.org/presentations/JavaPolis2003.ppt
          http://www.picocontainer.org/presentations/JavaPolis2003.pdf

          2 DIP, Robert C Martin, Bob大叔的優秀論文
          http://www.objectmentor.com/resources/articles/dip.pdf

          3 Dependency Injection 依賴注射,Matrin Fowler對DIP的擴展
          http://www.martinfowler.com/articles/injection.html

          4 IOC框架

          PicoContainer 優秀的IOC框架
          http://picocontainer.org/

          Avalon
          http://avalon.apache.org/

          Spring Framework
          http://www.springframework.org/

          HiveMind
          http://jakarta.apache.org/commons/hivemind

          這篇短文基本上是改編自Martin Fowler的Inversion of Control Containers and the Dependency Injection pattern,目的呢,是讓讀者能夠在最短時間內了解IoC的概念。這也是我一貫的“風格”:最短的文字、最精要的內容、最清晰的說明。希望我能做到,自勉^_^


          在J2EE應用開發中,經常遇到的問題就是:如何將不同的組件組裝成為一個內聚的應用程序?IoC模式可以解決這個問題,其目標是將組件的配置與使用分離開。

          IoC,Inversion of Control,控制反轉[1],其原理是基于OO設計原則的The Hollywood Principle:Don't call us, we'll call you。也就是說,所有的組件[2]都是被動的(Passive),所有的組件初始化和調用都由容器負責。組件處在一個容器當中,由容器負責管理。

          要說明IoC模式最好的方法是使用代碼。下邊是一段正常的代碼。

             1: class ClassA...
             2:  
             3:  public String aMethod(String arg){
             4:  
             5:     String result = instanceOfClassB.bMethod();
             6:  
             7:     do something;
             8:  
             9:     return result;
            10:  
            11:  }

          在上邊的代碼里,我們要解決的問題是:ClassA如何獲得ClassB的實例?一個最直接的方法是在aMethod里聲明:

          IClassB instanceOfClassB = new ClassB();

          這里使用了一個接口IClassB。

          問題是,如果出現這樣的情況:繼續使用ClassA,但要求用IClassB的另一個實現ClassB2代替ClassB呢?更概括一點說:ClassA怎樣才能找到IClassB的具體實現?很明顯,上述代碼增加ClassA和ClassB的耦合度,以致于無法在不修改ClassA的情況下變更IClassB的具體實現。

          IoC模式就是用于解決這樣的問題。當然,還有其他的方法,比如Service Locator模式,但現在我們只關注IoC。如前所述,IoC容器負責初始化組件(如IClassB),并將實例交給使用者。使用代碼或配置文件以聲明的方式將接口與實例關聯起來,IoC容器負責進行實際的調用處理。對于調用者,只需要關注接口就行了。

          根據實例傳入方式的不同,IoC分為type 1 IoC(接口注入[3])、type 2 IoC(設值方法注入)和type 3 IoC(構造子注入)。分別用代碼說明如下:

          type 1 IoC(接口注入)

             1: public interface GetClassB {
             2:  
             3:  void getClassB(IClassB instanceOfClassB);
             4:  
             5: }
             6:  
             7: class ClassA implements GetClassB…
             8:  
             9:  IClassB instanceOfClassB;
            10:  
            11:  void getClassB(IClassB instanceOfClassB) {
            12:  
            13: this.instanceOfClassB = instanceOfClassB;
            14:  
            15:  }

          type 2 IoC(設值方法注入)

             1: class ClassA...
             2:  
             3:  IClassB instanceOfClassB;
             4:  
             5:  public void setFinder(IClassB instanceOfClassB) {
             6:  
             7:     this.instanceOfClassB = instanceOfClassB;
             8:  
             9:  }

          type 3 IoC(構造子注入)

             1: class ClassA…
             2:  
             3: ClassB instanceOfClassB;
             4:  
             5:  public classA(IClassB instanceOfClassB) {
             6:  
             7:     this. instanceOfClassB = instanceOfClassB;
             8:  
             9:  }

            Spring使用的是type 2 IoC。


          [1] 在Martin Fowler的Inversion of Control Containers and the Dependency Injection pattern一文中,作者提出本模式更準確的名稱應該是Dependency Injection??紤]到使用上的習慣,在本文檔中我們將繼續使用IoC的概念。

          [2] 同一篇文章中,Martin Fowler還提出了Componet(組件)與Service(服務)的區別問題。我個人認為“組件”更有助于幫助我們理解IoC的概念,所以在本文檔中使用“組件”來代表“組件或服務”

          [3] 如上所述,注入是另一種說法,此處只用于輔助說明。

          主站蜘蛛池模板: 颍上县| 神农架林区| 镇康县| 灵川县| 休宁县| 斗六市| 什邡市| 句容市| 淅川县| 茂名市| 彰武县| 宁安市| 内乡县| 龙口市| 崇州市| 德令哈市| 阿荣旗| 剑阁县| 柳州市| 乐安县| 绥滨县| 屏东县| 双江| 苍溪县| 分宜县| 长宁区| 满洲里市| 板桥市| 增城市| 抚顺市| 巫溪县| 永定县| 滦南县| 泸定县| 德令哈市| 枝江市| 澄城县| 永宁县| 阳高县| 宿州市| 大田县|