控制反轉(IOC) 和依賴注入(DI) 的理解

1.      IOC(控制反轉) inverseof control是spring容器的內核,AOP.聲明事務等功能在此基礎上開花結果。

2.      通過實例理解IOC概念:

實例:《墨攻》電影中有一個場景:當劉德華所飾演的墨者革離到達樑國都城下,城上樑國守軍問道:“來者何人?“劉德華回答道:“墨者革離”。以此場景通過一個java類爲這個“城門叩問”的場景進行編劇。

MoAttract:通過演員安排劇本

public class MoAttack {

      public voidcityuGateAsk(){

         LiuDeHualdh=newLiuDeHua();//演員直接侵入腳本

         ldh.responseAsk("墨者革離");

      }

}

在上面代碼註釋處,作爲具體角色飾演者的劉德華直接侵入到劇本中,使劇本和演員直接耦合在一起,如圖:

 

一個明智的編劇在劇情創作時應該圍繞故事的角色進行,而不應該考慮角色的具體飾演者,這樣纔可能在劇本投拍時自由地遴選任何適合的演員,而非綁定在劉德華一個人身上。

通過以上的分析,知道需要爲蓋劇本主人公革離定義一個接口:

public classMoAttack {

   public void cityuGateAsk(){

      GeLigeli=newLiuDeHua();//引入革離角色接口

      geli.responseAsk("墨者革離");//通過接口開展劇情

   }

}

 

墨攻,革離,劉德華三者的類圖關係:

 

從上圖中可以看出MoAttrack同時依賴於GeLi接口和LIuDeHua類,並沒有達到所期望的劇本依賴於角色的目的。但是角色最終必須通過具體的演員才能拍攝,如何讓LiuDeHua和劇本無關而又能完成GeLi的具體動作呢?當然是在拍攝時,導演將LiuDeHua安排在GeLi的角色上,導演將劇本、角色、飾演者裝配起來:

 

通過引入導演,劇本和具體的飾演者解耦了,對應到軟件中,導演像是一個裝配器,將具體的飾演者賦予了劇本的角色。

         現在可以反過來理解IoC的概念了。IOC(Inverseof control)的字面意思是控制反轉,它包括兩個內容:一是控制:二是反轉。到底是什麼東西的控制被反轉了呢?對應前面的例子,控制是指選擇GeLi角色扮演者的控制權;反轉是指在這種控制權從《墨攻》劇本中移除,轉交到了導演手中。對於軟件來說,既是某一接口具體實現類的選擇控制權從調用類中移除,轉交給第三方裁決。

         因爲IOC不夠開門見山,因此業界曾進行廣泛的討論,最終軟件界的泰斗人物Martin Fowler提出了DI(依賴注入:Dependency Injection)的概念用以代替IoC,即調用類對接口實現類的依賴關係由第三方(容器或者協作類)注入,已移除調用類對接口實現類的依賴。

1.      Ioc類型

從注入方法上看,主要可以劃分爲三種類型:構造函數注入、屬性注入和接口注入。

構造函數注入:

         public class MoAttack {

      private GeLigeli;

      public MoAttack(GeLi geli){ //注入革離的具體扮演者

         this.geli=geli;

      }

      public voidcityuGateAsk(){

         geli.responseAsk("墨者革離");

      }

}

         MoAttack的構造函數並不關心具體是誰扮演革離的角色,只要在構造函數中傳入扮演者按劇本要求完成角色功能即可。角色的具體扮演者由導演來安排,如下代碼:

public classDirector {

   public void direct(){

      GeLigeli=newLiuDeHua();//指定角色的扮演者

      MoAttackmoAttack=newMoAttack(geli);//注如具體扮演者到劇本中

      moAttack.cityGateAsk();

   }

}

屬性注入:

         有時,導演會發現,雖然革離是影片《墨攻》的第一主角,但是並非每一個場景都需要革離的出現,在這種情況下通過構造函數並不妥當,這是可以考慮使用屬性注入。屬性注入可以有選擇的通過setter方法完成調用類所需依賴的注入,更加靈活方便。

public classMoAttack {

   private GeLigeli;

   public void setGeli(GeLi geli) { //屬性注入

      this.geli = geli;

   }

   public void cityGateAsk(){

      geli.responseAsk("墨者革離");

   }

}

Director通過Setter方法注入革離扮演者:

public classDirector {

   public void direct(){

      GeLigeli=newLiuDeHua();

      MoAttackmoAttack=newMoAttack();

      moAttack.setGeli(geli);  //調用setter方法注入

      moAttack.cityGateAsk();

   }

}

接口注入:

         將調用類所有注入的方法抽取到一個接口中,調用類實現這一接口規定的注入方法,爲了採用接口注入的方式,聲明一個ActorArrangable接口

public interfaceActorArrangable {

   void injectGeli(GeLi geli);

}

MoAttack通過接口方法注入革離扮演者

public classMoAttack implementsActorArrangable{

   private GeLigeli;

   public void injectGeli(GeLi geli){ //實現接口方法

      this.geli=geli;

   }

   public void cityGateAsk(){

      geli.responseAsk("墨者革離");

   }

}

Director通過接口方法注入革離扮演者:

public classDirector {

   public void direct(){

      GeLigeli=newLiuDeHua();

      MoAttackmoAttack=newMoAttack();

      moAttack.injectGeli(geli);

      moAttack.cityGateAsk();

   }

}

由於接口注入需要額外聲明一個接口,增加類的數目,而且它的效果和屬性輸入並無本質區別,因此不提倡使用。

http://blog.csdn.net/alex_sym/article/details/8255106

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