<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    飛翔的起點(diǎn)

    從這里出發(fā)

    導(dǎo)航

    <2025年5月>
    27282930123
    45678910
    11121314151617
    18192021222324
    25262728293031
    1234567

    統(tǒng)計(jì)

    常用鏈接

    留言簿(5)

    隨筆分類

    隨筆檔案

    文章分類

    文章檔案

    搜索

    最新評(píng)論

    閱讀排行榜

    評(píng)論排行榜

    控制反轉(zhuǎn)(IOC)模式

     

     控制反轉(zhuǎn)(IOC)模式(又稱DI:Dependency Injection)就是Inversion of Control,控制反轉(zhuǎn)。在Java開(kāi)發(fā)中,IoC意味著將你設(shè)計(jì)好的類交給系統(tǒng)去控制,而不是在你的類內(nèi)部控制。這稱為控制反轉(zhuǎn)。

            IoC(Inversion of Control)是近年來(lái)興起的一種思想,不僅僅是編程思想。主要是協(xié)調(diào)各組件間相互的依賴關(guān)系,同時(shí)大大提高了組件的可移植性,組件的重用機(jī)會(huì)也變得更多。在傳統(tǒng)的實(shí)現(xiàn)中,由程序內(nèi)部代碼來(lái)控制程序之間的關(guān)系。我們經(jīng)常使用new關(guān)鍵字來(lái)實(shí)現(xiàn)兩組鍵間關(guān)系的組合,這種實(shí)現(xiàn)的方式會(huì)造成組件之間耦合(一個(gè)好的設(shè)計(jì),不但要實(shí)現(xiàn)代碼重用,還要將組件間關(guān)系解耦)。IoC很好的解決了該問(wèn)題,它將實(shí)現(xiàn)組件間關(guān)系從程序內(nèi)部提到外部容器來(lái)管理。也就是說(shuō)由容器在運(yùn)行期將組件間的某種依賴關(guān)系動(dòng)態(tài)的注入組件中。控制程序間關(guān)系的實(shí)現(xiàn)交給了外部的容器來(lái)完成。即常說(shuō)的好萊塢原則“Don't call us, we'll call you”。

          Ioc也有稱為DI(Dependecy Injection 依賴注射),由Martin Fowler的一篇《Inversion of Control Containers and the Dependency Injection pattern》提出。


      分離關(guān)注( Separation of Concerns : SOC)是Ioc模式和AOP產(chǎn)生最原始動(dòng)力,通過(guò)功能分解可得到關(guān)注點(diǎn),這些關(guān)注可以是 組件Components, 方面Aspects或服務(wù)Services。

      從GOF設(shè)計(jì)模式中,我們已經(jīng)習(xí)慣一種思維編程方式:Interface Driven Design 接口驅(qū)動(dòng),接口驅(qū)動(dòng)有很多好處,可以提供不同靈活的子類實(shí)現(xiàn),增加代碼穩(wěn)定和健壯性等等,但是接口一定是需要實(shí)現(xiàn)的,也就是如下語(yǔ)句遲早要執(zhí)行:

      AInterface a = new AInterfaceImp();

      AInterfaceImp是接口AInterface的一個(gè)子類,Ioc模式可以延緩接口的實(shí)現(xiàn),根據(jù)需要實(shí)現(xiàn),有個(gè)比喻:接口如同空的模型套,在必要時(shí),需要向模型套注射石膏,這樣才能成為一個(gè)模型實(shí)體,因此,我們將人為控制接口的實(shí)現(xiàn)成為“注射”。

      Ioc英文為 Inversion of Control,即反轉(zhuǎn)模式,這里有著名的好萊塢理論:你呆著別動(dòng),到時(shí)我會(huì)找你。

      其實(shí)Ioc模式也是解決調(diào)用者和被調(diào)用者之間的一種關(guān)系,上述AInterface實(shí)現(xiàn)語(yǔ)句表明當(dāng)前是在調(diào)用被調(diào)用者AInterfaceImp,由于被調(diào)用者名稱寫(xiě)入了調(diào)用者的代碼中,這產(chǎn)生了一個(gè)接口實(shí)現(xiàn)的原罪:彼此聯(lián)系,調(diào)用者和被調(diào)用者有緊密聯(lián)系,在UML中是用依賴 Dependency 表示。

      但是這種依賴在分離關(guān)注的思維下是不可忍耐的,必須切割,實(shí)現(xiàn)調(diào)用者和被調(diào)用者解耦,新的Ioc模式 Dependency Injection 模式由此產(chǎn)生了, Dependency Injection模式是依賴注射的意思,也就是將依賴先剝離,然后在適當(dāng)時(shí)候再注射進(jìn)入。

    一、Ioc模式(Dependency Injection模式)有三種:

          第一種類型 從JNDI或ServiceManager等獲得被調(diào)用者,這里類似ServiceLocator模式。 1.EJB/j2ee 2. Avalon(Apache的一個(gè)復(fù)雜使用不多的項(xiàng)目) 
          第二種類型 使用JavaBeans的setter方法 1. Spring Framework,2.WebWork/XWork 
          第三種類型 在構(gòu)造方法中實(shí)現(xiàn)依賴 1. PicoContainer,2. HiveMind

      有過(guò)EJB開(kāi)發(fā)經(jīng)驗(yàn)的人都知道,每個(gè)EJB的調(diào)用都需要通過(guò)JNDI尋找到工廠性質(zhì)的Home接口,在我的教程EJB是什么章節(jié)中,我也是從依賴和工廠模式角度來(lái)闡述EJB的使用。

      在通常傳統(tǒng)情況下,為了實(shí)現(xiàn)調(diào)用者和被調(diào)用者解耦,分離,一般是通過(guò)工廠模式實(shí)現(xiàn)的,下面將通過(guò)比較工廠模式和Ioc模式不同,加深理解Ioc模式。

    二、工廠模式和Ioc

      假設(shè)有兩個(gè)類B 和 C:B作為調(diào)用者,C是被調(diào)用者,在B代碼中存在對(duì)C的調(diào)用:

     

    java 代碼
    1. public class B{   
    2.    private C comp;    
    3.   ......   
    4. }   

     

      實(shí)現(xiàn)comp實(shí)例有兩種途徑:?jiǎn)螒B(tài)工廠模式和Ioc。

    工廠模式實(shí)現(xiàn)如下:

    java 代碼
    1. public class B{   
    2.    private C comp;    
    3.   private final static MyFactory myFactory = MyFactory.getInstance();   
    4.   
    5.   public B(){   
    6.     this.comp = myFactory.createInstanceOfC();   
    7.   
    8.   }   
    9.    public void someMethod(){   
    10.     this.comp.sayHello();   
    11.   }    
    12.   ......   
    13. }   

     

    特點(diǎn):

    每次運(yùn)行時(shí),MyFactory可根據(jù)XML配置文件中定義的C子類實(shí)現(xiàn),通過(guò)createInstanceOfC()生成C的具體實(shí)例。 
    使用Ioc依賴性注射( Dependency Injection )實(shí)現(xiàn)Picocontainer如下,B類如同通常POJO類,如下:

    java 代碼
    1. public class B{   
    2.    private C comp;    
    3.   public B(C comp){   
    4.     this.comp = comp;   
    5.    }   
    6.    public void someMethod(){   
    7.     this.comp.sayHello();   
    8.    }   
    9.   ......   
    10. }   


     

    假設(shè)C接口/類有有一個(gè)具體實(shí)現(xiàn)CImp類。當(dāng)客戶端調(diào)用B時(shí),使用下列代碼:

    java 代碼
    1. public class client{   
    2.    public static void main( String[] args ) {   
    3.     DefaultPicoContainer container = new DefaultPicoContainer();   
    4.     container.registerComponentImplementation(CImp.class);   
    5.     container.registerComponentImplementation(B.class);   
    6.     B b = (B) container.getComponentInstance(B.class);   
    7.     b.someMethod();   
    8.    }   
    9. }   


     

      因此,當(dāng)客戶端調(diào)用B時(shí),分別使用工廠模式和Ioc有不同的特點(diǎn)和區(qū)別:

      主要區(qū)別體現(xiàn)在B類的代碼,如果使用Ioc,在B類代碼中將不需要嵌入任何工廠模式等的代碼,因?yàn)檫@些工廠模式其實(shí)還是與C有些間接的聯(lián)系,這樣,使用Ioc徹底解耦了B和C之間的聯(lián)系。

      使用Ioc帶來(lái)的代價(jià)是:需要在客戶端或其它某處進(jìn)行B和C之間聯(lián)系的組裝。

      所以,Ioc并沒(méi)有消除B和C之間這樣的聯(lián)系,只是轉(zhuǎn)移了這種聯(lián)系。
      這種聯(lián)系轉(zhuǎn)移實(shí)際也是一種分離關(guān)注,它的影響巨大,它提供了AOP實(shí)現(xiàn)的可能。

    Ioc和AOP
      AOP我們已經(jīng)知道是一種面向切面的編程方式,由于Ioc解放自由了B類,而且可以向B類實(shí)現(xiàn)注射C類具體實(shí)現(xiàn),如果把B類想像成運(yùn)行時(shí)的橫向動(dòng)作,無(wú)疑注入C類子類就是AOP中的一種Advice,如下圖:

     

      通過(guò)下列代碼說(shuō)明如何使用Picocontainer實(shí)現(xiàn)AOP,該例程主要實(shí)現(xiàn)是記錄logger功能,通過(guò)Picocontainer可以使用簡(jiǎn)單一行,使所有的應(yīng)用類的記錄功能激活。

    首先編制一個(gè)記錄接口:

    java 代碼
    1. public interface Logging {   
    2.   
    3.   public void enableLogging(Log log);   
    4.   
    5. }  


     

    有一個(gè)LogSwitcher類,主要用來(lái)激活具體應(yīng)用中的記錄功能:

    java 代碼
    1. import org.apache.commons.logging.Log;   
    2. public class LogSwitcher   
    3. {   
    4.   protected Log m_log;   
    5.   public void enableLogging(Log log) {   
    6.     m_log = log;   
    7.     m_log.info("Logging Enabled");   
    8.   }   
    9. }   

    一般的普通應(yīng)用JavaBeans都可以繼承這個(gè)類,假設(shè)PicoUserManager是一個(gè)用戶管理類,代碼如下:

    java 代碼
    1. public class PicoUserManager extends LogSwitcher   
    2. {    
    3.   ..... //用戶管理功能   
    4. }   
    5. public class PicoXXXX1Manager extends LogSwitcher   
    6. {    
    7.   
    8.   ..... //業(yè)務(wù)功能   
    9. }   
    10. public class PicoXXXX2Manager extends LogSwitcher   
    11. {    
    12.   
    13.   ..... //業(yè)務(wù)功能   
    14. }  


     

    注意LogSwitcher中Log實(shí)例是由外界賦予的,也就是說(shuō)即將被外界注射進(jìn)入,下面看看使用Picocontainer是如何注射Log的具體實(shí)例的。


    java 代碼
    1. DefaultPicoContainer container = new DefaultPicoContainer();   
    2. container.registerComponentImplementation(PicoUserManager.class);   
    3. container.registerComponentImplementation(PicoXXXX1Manager.class);    
    4. container.registerComponentImplementation(PicoXXXX2Manager.class);   
    5. .....    
    6.   
    7. Logging logging = (Logging) container.getComponentMulticaster();   
    8.   
    9. logging.enableLogging(new SimpleLog("pico"));//激活log  


     

      由上代碼可見(jiàn),通過(guò)使用簡(jiǎn)單一行l(wèi)ogging.enableLogging()方法使所有的應(yīng)用類的記錄功能激活。這是不是類似AOP的advice實(shí)現(xiàn)?

      總之,使用Ioc模式,可以不管將來(lái)具體實(shí)現(xiàn),完全在一個(gè)抽象層次進(jìn)行描述和技術(shù)架構(gòu),因此,Ioc模式可以為容器、框架之類的軟件實(shí)現(xiàn)提供了具體的實(shí)現(xiàn)手段,屬于架構(gòu)技術(shù)中一種重要的模式應(yīng)用。J道的JdonSD框架也使用了Ioc模式。

    參考資料:

    Inversion of Control Containers and the Dependency Injection pattern
    A Brief Introduction to IoC 
    Ioc容器的革命性優(yōu)點(diǎn)
    Java企業(yè)系統(tǒng)架構(gòu)選擇考量
    IOC模式的思考和疑問(wèn)

    三、IoC的幾種實(shí)現(xiàn)類型

    (1)Type1接口注入

    通常做法是利用接口將調(diào)用者與實(shí)現(xiàn)者分離。

    java 代碼
    1. public class Sport {   
    2. private InterfaceBall ball; //InterfaceBall是定義的接口   
    3. public void init() {   
    4. //Basketball實(shí)現(xiàn)了InterfaceBall接口   
    5. ball = (InterfaceBall) Class.forName("Basketball").newInstance();   
    6. }   
    7. }  


    Sport類在編譯期依賴于InterfaceBall的實(shí)現(xiàn),為了將調(diào)用者與實(shí)現(xiàn)者分離,我們動(dòng)態(tài)生成Basketball類并通了強(qiáng)制類型轉(zhuǎn)換為InterfaceBall。Apache Avalon是一個(gè)典型的Type1型IoC容器。

    (2)setter方法注入

    在類中暴露setter方法來(lái)實(shí)現(xiàn)依賴關(guān)系。

    java 代碼
    1. public class Sport {   
    2. private InterfaceBall ball;   
    3. public void setBall(InterfaceBall arg) {   
    4. ball = arg;   
    5. }   
    6. }  


    這種方式對(duì)已經(jīng)習(xí)慣了JavaBean的程序員而言,更顯直觀。Spring就是實(shí)現(xiàn)了該類型的輕量級(jí)容器。

    (3)Type3構(gòu)造子注入

    即通過(guò)構(gòu)造方法完成依賴關(guān)系。

    java 代碼
    1. public class Sport {   
    2. private InterfaceBall ball;   
    3. public Sport(InterfaceBall arg) {   
    4. ball = arg;   
    5. }   
    6. }  


    可以看到,通過(guò)類的構(gòu)造方法建立依賴關(guān)系。由于Type3在構(gòu)造期就形成了對(duì)象的依賴關(guān)系,即存對(duì)象的重用變的困難。有些框架需要組件提供一個(gè)默認(rèn)的構(gòu)造方法,此時(shí)就體現(xiàn)了Type3的局限性。通常所有的參數(shù)都是通過(guò)構(gòu)造方法注入的,當(dāng)對(duì)象間的依賴關(guān)系較多時(shí),構(gòu)造方法就顯的比較復(fù)雜,不利于單元測(cè)試。PicoContainer就是實(shí)現(xiàn)了Type3依賴注入模式的輕量級(jí)容器。

    posted on 2009-04-09 16:40 forgood 閱讀(311) 評(píng)論(0)  編輯  收藏 所屬分類: spring


    只有注冊(cè)用戶登錄后才能發(fā)表評(píng)論。


    網(wǎng)站導(dǎo)航:
     
    主站蜘蛛池模板: 亚洲色偷拍另类无码专区| 精品无码无人网站免费视频| 精品国产亚洲AV麻豆| 亚洲人成人网毛片在线播放| 91亚洲性爱在线视频| jlzzjlzz亚洲jzjzjz| 亚洲av无码专区在线| 亚洲一级黄色大片| 麻豆狠色伊人亚洲综合网站| 亚洲国产熟亚洲女视频| 亚洲中文字幕乱码AV波多JI| 亚洲日韩久久综合中文字幕| 亚洲日本va一区二区三区| 亚洲avav天堂av在线网毛片| 国产区图片区小说区亚洲区| 午夜在线亚洲男人午在线| 国产亚洲精品成人久久网站| 成人a毛片视频免费看| GOGOGO高清免费看韩国| 国产成人免费视频| 免费观看美女用震蛋喷水的视频| 成人免费午夜无码视频| 四虎影视大全免费入口| 亚洲av无码国产精品色在线看不卡| 亚洲国产日韩成人综合天堂 | 九九久久国产精品免费热6| 一个人晚上在线观看的免费视频 | 色费女人18女人毛片免费视频 | 亚洲国产夜色在线观看| 亚洲另类自拍丝袜第五页 | 亚洲人成网男女大片在线播放| 亚洲精品无码av中文字幕| 亚洲AV无码男人的天堂| av电影在线免费看| 久久成人免费播放网站| 国产在线国偷精品产拍免费| 日韩亚洲国产二区| 亚洲av无码潮喷在线观看| 2019亚洲午夜无码天堂| 人人爽人人爽人人片av免费 | 亚洲AV香蕉一区区二区三区|