J2EE之巔

           

          依賴(lài)注入(Dependency Injection)模式的特點(diǎn)分析與實(shí)現(xiàn)

          依賴(lài)注入(Dependency Injection模式的特點(diǎn)分析與實(shí)現(xiàn)

          ――構(gòu)造子注入Constructor Injection模式的分析與實(shí)現(xiàn)

           

           

           

          chaocai2001@yahoo.com.cn

           

          摘要:本文對(duì)IoC模式、依賴(lài)注入(Dependency Injection) 模式做了簡(jiǎn)要介紹,文中分析構(gòu)造子注入模式與其他模式相比較的優(yōu)勢(shì)和特點(diǎn),并給出了在JAVA中實(shí)現(xiàn)該模式的方法。

           

           

          1         引言

          IoCInversion of Control)模式以被目前的輕量級(jí)容器所廣泛應(yīng)用,通過(guò)IoC模式這些容器幫助開(kāi)發(fā)者將來(lái)自不同項(xiàng)目的組件裝配成一個(gè)內(nèi)聚的應(yīng)用程序。輕量級(jí)的IoC容器(如Springpico-container)雖然為我們的開(kāi)發(fā)提供了很大的便利,但是在很多情況下這些輕量級(jí)容器所提供的功能并不一定非常適合我們的需要,也許這些容器的功能過(guò)于龐大了,或者所提供的功能缺乏對(duì)特定應(yīng)用的針對(duì)性,或者我們需要更高的運(yùn)行效率,這時(shí)我們可以在了解IoC的原理的基礎(chǔ)上利用JAVA的反射機(jī)制自己實(shí)現(xiàn)靈活的、可擴(kuò)展的組件機(jī)制。

          2         IoC與依賴(lài)注入(Dependency Injection)模式簡(jiǎn)介

          GoF的設(shè)計(jì)模式相同,IoC模式同樣是關(guān)注重用性,但與GoF模式不同的是IoC模式更加關(guān)注二進(jìn)制級(jí)的重用性和可擴(kuò)展性,即可以直接通過(guò)二進(jìn)制級(jí)進(jìn)行擴(kuò)充,復(fù)用的模塊通常被稱(chēng)為組件或者插件,組件和插件都是在運(yùn)行時(shí)進(jìn)行裝載的。

          GoF的設(shè)計(jì)模式中我們大量看到的是面向接口編程:Interface Driven Design 接口驅(qū)動(dòng),接口驅(qū)動(dòng)有很多好處,可以提供不同靈活的子類(lèi)實(shí)現(xiàn),增加代碼穩(wěn)定和健壯性等等,但是接口一定是需要實(shí)現(xiàn)的,也就是如下語(yǔ)句遲早要執(zhí)行:

          AInterface a = new AInterfaceImp();

          由于以上的代碼被寫(xiě)入了調(diào)用者程序中,同時(shí)象AinterfaceImp這樣的接口的實(shí)現(xiàn)類(lèi)是在編譯時(shí)被裝載的,如果以后想加入新的接口實(shí)現(xiàn)類(lèi)則必須修改調(diào)用者的代碼。

          IoC模式與以上情況不同,接口的實(shí)現(xiàn)類(lèi)是在運(yùn)行時(shí)被裝載的,這樣即使以后新添加了接口實(shí)現(xiàn)類(lèi)是也不需修改調(diào)用者的代碼(可以通過(guò)特定的方式來(lái)定位新增的實(shí)現(xiàn)類(lèi),如配置文件指定)。IoC英文為 Inversion of Control,即反轉(zhuǎn)模式,這里有著名的好萊塢理論:你呆著別動(dòng),到時(shí)我會(huì)找你。

          IoC模式可以延緩接口的實(shí)現(xiàn),根據(jù)需要實(shí)現(xiàn),有個(gè)比喻:接口如同空的模型套,在必要時(shí),需要向模型套注射石膏,這樣才能成為一個(gè)模型實(shí)體,因此,對(duì)于這些新生的容器,它們反轉(zhuǎn)的是“如何定位插件的具體實(shí)現(xiàn)”。因此, Martin Fowler 給這種模式起了一個(gè)形象的名稱(chēng)“依賴(lài)注入”Dependency Injection

          圖表 1 采用Dependency Injection前后的依賴(lài)關(guān)系變化

          依賴(lài)注入的形式主要有三種,分別將它們叫做構(gòu)造子注入(Constructor Injection)、設(shè)值方法注入(Setter Injection)和接口注入(Interface Injection)。

          這三種方式在Martin Fowler的《Inversion of Control Containers and the Dependency Injection pattern》中都給出了詳細(xì)的定義及說(shuō)明,本文就不再贅述了,下面的內(nèi)容將著重介紹構(gòu)造子注入模式的特點(diǎn)及實(shí)現(xiàn)方法。

          3         構(gòu)造子注入模式的特點(diǎn)及實(shí)現(xiàn)

          3.1      構(gòu)造子注入模式的特點(diǎn)

          通常情況下設(shè)方法注入和接口注入較易于被開(kāi)發(fā)人員接受,而構(gòu)造子注入則應(yīng)用較少,實(shí)際上構(gòu)造子注入具有很多其他兩者所不具有的優(yōu)勢(shì):

          1 構(gòu)造子注入形成了一種更強(qiáng)的依賴(lài)契約

          2 可以獲得更加簡(jiǎn)明的代碼

          3 更加簡(jiǎn)明的依賴(lài)聲明機(jī)制,無(wú)須定義XML配置文件或設(shè)方法

          4 更加符合接口與實(shí)現(xiàn)分離的組件特征,組件接口表明能夠向其它組件提供的服務(wù),而實(shí)現(xiàn)則應(yīng)該是所提供服務(wù)的實(shí)現(xiàn)應(yīng)該與服務(wù)契約無(wú)關(guān)(即不應(yīng)包含用于獲得依賴(lài)的設(shè)值方法等)。

          5 不會(huì)出現(xiàn)不確定的狀態(tài)。在設(shè)值方法注入中,由于并不是所有的設(shè)值方法(setter)都一定會(huì)被調(diào)用的,所以會(huì)有不確定狀態(tài)。

          從以上幾點(diǎn)我們還可以分析出構(gòu)造子注入對(duì)于組件代碼的入侵性遠(yuǎn)小于其它兩種模式(接口注入使得組件必須實(shí)現(xiàn)特定接口,設(shè)值方法同樣要求組件提供特定的setter方法),代碼更加易于維護(hù)

          圖表 2 示例中類(lèi)的關(guān)系

          Client的實(shí)現(xiàn)依賴(lài)于接口ABC的實(shí)現(xiàn),但是為了提供系統(tǒng)更好的靈活性和可擴(kuò)展性,各接口的實(shí)現(xiàn)以組件的方式利用java的反射機(jī)制進(jìn)行運(yùn)行時(shí)裝載,注意到組件間可能會(huì)存在某種依賴(lài)關(guān)系,例如組件AX依賴(lài)與接口B的實(shí)現(xiàn)類(lèi),而這中依賴(lài)關(guān)系必須在運(yùn)行時(shí)動(dòng)態(tài)注入,組件為了告訴組件的調(diào)用者這種依賴(lài)關(guān)系以便注入,可以使用上文提到的各種模式:

          1 使用接口注入模式

          public interface InjectB{

                 public void injectB(B bImp);

          }

          public interface InjectC{

                 public void injectC(C cImp);

          }

          public class AImp implements A,InjectB,InjectC{

                

                 public void injectB(B bImp);

                 public void injectC(C cImp);

                

          }

          2 使用設(shè)值注入模式

          public class AImp implements A {

                

                 public void setB(B bImp);

                 public void setC(C cImp);

                

          }

           

          3 使用構(gòu)造子注入模式

          public class AImp implements A {

                

                 public AImp(B bImp, C cImp){

                       

                 }

                

          }

          由以上實(shí)例可以清楚的看出采用構(gòu)造子注入模式的實(shí)現(xiàn)組件代碼最為簡(jiǎn)單,且所受的入侵性最小。

          3.2      JAVA中實(shí)現(xiàn)構(gòu)造子注入模式

          java.NET這樣具有反射功能的語(yǔ)言中實(shí)現(xiàn)類(lèi)型的運(yùn)行時(shí)載入并不復(fù)雜,只要通過(guò)Class.forName或生成自己的ClassLoader就可以實(shí)現(xiàn)。

          同樣我們可以通過(guò)反射機(jī)制獲取組件構(gòu)造函數(shù)的參數(shù),注入相應(yīng)接口的實(shí)現(xiàn),作者將此過(guò)程進(jìn)行了封裝,以下是代碼:

          public class RefectHelper {

                   public Object ConstructorHelper(String className,ConstructorParamDeal pd) throws Exception{

                             try{

                                      //獲取類(lèi)中的構(gòu)造函數(shù)

          Constructor[] constructs=Class.forName(className).getConstructors();              //實(shí)現(xiàn)中默認(rèn)使用第一個(gè)構(gòu)造函數(shù)類(lèi)創(chuàng)建實(shí)例      

                                      Class [] classes=constructs[0].getParameterTypes();                  

                                        //獲取要注入的參數(shù)實(shí)例

                                      Object []obj=pd.dealParam(classes);

                                      //創(chuàng)建實(shí)例

                                      return constructs[0].newInstance(obj);

                             }catch(Exception e){

                                      throw e;

                             }

                            

                            

                   }

          }

          /**

          *構(gòu)造函數(shù)參數(shù)注入

          **/

          public interface ConstructorParamDeal {

                   /**

                   *根據(jù)構(gòu)造函數(shù)中參數(shù)的類(lèi)型注入,相應(yīng)的實(shí)現(xiàn)

                   @param classes 構(gòu)造函數(shù)的參數(shù)類(lèi)型

                   return 注入構(gòu)造函數(shù)的參數(shù)實(shí)現(xiàn)

                   **/

                   public Object [] dealParam(Class [] classes);

          }

          public class ParamDeal implements ConstructorParamDeal{

           

                   /* (non-Javadoc)

                    * @see com.topsec.tsm.agent.helper.ConstructorParamDeal#dealParam(java.lang.Class[])

                    */

                   public Object [] dealParam(Class[] classes) {

                             Object [] obj=new Object[classes.length];

                             for (int i=0;i<obj.length;i++){

                                      //為不同類(lèi)型注入選擇不同實(shí)例

                                      if (classes[i].equals(String.class)){

                                               obj[i]=”Hello World”;                                       

                                      }

                             }

                             return obj;

                   }

           

          }

          上面的程序中ConstructorHelper用于利用反射機(jī)制枚舉出載入類(lèi)的構(gòu)造函數(shù)及構(gòu)造函數(shù)的參數(shù)的類(lèi)型,至于不同類(lèi)型注入什么樣的實(shí)例則由ContructorParamDeal的實(shí)現(xiàn)者來(lái)決定,ContructorParamDeal的實(shí)現(xiàn)者同樣可以以組件的形式在運(yùn)行時(shí)動(dòng)態(tài)載入。由于組件間的依賴(lài)關(guān)系的制約,所以組件實(shí)例化的順序需要特別考慮。

          4         結(jié)束語(yǔ)

          三種依賴(lài)注入模式各有其特點(diǎn)和優(yōu)勢(shì),只有充分理解這些模式間的不同,才能為自己的應(yīng)用選擇正確的依賴(lài)注入模式,文中介紹的構(gòu)造子注入模式實(shí)現(xiàn)方法,在使用其他具有反射功能的語(yǔ)言(如:.NET)時(shí)同樣可以參考。

           

           

           

           [參考文獻(xiàn)]

          1 Martin Fowler,Inversion of Control Containers and the Dependency Injection pattern,http://www.martinfowler.com/articles/injection.html,2004

          2 Erich Gamma,Design Patterns,Addison Wesley,1999

          3 http://www.picocontainer.org/

          4 彭晨陽(yáng),Ioc模式, http://www.jdon.com,2004

          posted on 2006-03-12 15:50 超越巔峰 閱讀(367) 評(píng)論(0)  編輯  收藏 所屬分類(lèi): Design Pattern


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


          網(wǎng)站導(dǎo)航:
           

          導(dǎo)航

          統(tǒng)計(jì)

          常用鏈接

          留言簿(12)

          隨筆分類(lèi)(54)

          隨筆檔案(59)

          文章分類(lèi)(2)

          文章檔案(1)

          相冊(cè)

          搜索

          積分與排名

          最新評(píng)論

          閱讀排行榜

          評(píng)論排行榜

          主站蜘蛛池模板: 凤山县| 会理县| 敖汉旗| 琼结县| 简阳市| 闸北区| 南乐县| 托克逊县| 襄城县| 左权县| 临沂市| 四会市| 石楼县| 九台市| 安化县| 琼结县| 中山市| 广南县| 桑日县| 资兴市| 长汀县| 齐河县| 华安县| 明水县| 唐海县| 平凉市| 弥渡县| 宁陵县| 准格尔旗| 紫云| 蕉岭县| 大化| 金乡县| 盐山县| 商丘市| 海晏县| 洪洞县| 江西省| 德安县| 辉县市| 绥江县|