1. 程式人生 > >IoC控制反轉理解

IoC控制反轉理解

IoC(Inverse of Control),即控制反轉,也叫做依賴注入。是面向物件設計的一個重要的概念。它提出了將被呼叫物件的控制權由呼叫者轉移到第三方控制器上。這樣以滿足軟體開發中的依賴倒置(DI)原則。 一個電影為例: 《墨攻》中一片段:守城士兵問劉德華扮演的墨者革離“來者何人?”,革離回答說“墨者革離”。現在考慮這樣一個劇本:
class Action{
    public void gateAsk(){
        //演員直接侵入劇本
        LiuDeHua ldh=new LiuDeHua();
        ldh.responseAsk();
    }
}

可以看到,演員直接侵入了劇本之中,這樣假設不再由劉德華扮演革離,那麼劇本將不再適用。為此,我們實現一個革離的介面,通過介面展開劇情:
class Action{
    public void gateAsk(){
        //引入介面展開劇情
        GeLi geli=new LiuDeHua();
        geli.responseAsk();
    }
}
這樣的Action、LiuDeHua、GeLi關係如下: 但是我們可以看到,LiuDeHua還是出現在劇本之中,指令碼最終還是依賴於具體的扮演者。那麼如何才能讓Action指令碼與具體的扮演者無關呢?這時候我們可以考慮一個導演,讓他來控制GeLi的扮演者,即由導演決定GeLi的具體實現。如下:
此時,我們在不經意間,已經完成了控制反轉:原本在指令碼(呼叫者)之中就要給定具體的演員(被呼叫者),此時,我們將演員的決定權交由導演(第三方控制器)決定。以上便是控制反轉的介紹。在實踐中,我們通常有三種方式實現控制反轉:
  1. 建構函式注入
  2. 屬性注入
  3. 依賴注入
1.建構函式注入:     在建構函式中將 介面的實現類以引數的方式傳入。例如:
class Action{
    private GeLi geli;
    public Action(GeLi geli){
        this.geli=geli;
    }
    public void gateAsk(){
        //引入介面展開劇情
        GeLi geli=new LiuDeHua();
        geli.responseAsk();
    }
}

public class Director{
    GeLi geli=new LiuDeHua();
    Action action=new Action(geli);
    action.gateAsk();
}
但是存在一個弊端就是,演員劉德華在指令碼開始拍攝時就一直在場。這顯然是不可取的(因為這會佔用計算機的記憶體)。所以一個好的方法是讓演員在有戲的地方出現: 2.屬性注入:     其實就是通過一個getter和一個setter完成對相關介面的實現類的傳入:

class Action{
    private GeLi geli;
    public Action(){}
    //屬性注入
    public void setGeLi(GeLi geli){
        this.geli=geli;
    }
    public void gateAsk(){
        //引入介面展開劇情
        GeLi geli=new LiuDeHua();
        geli.responseAsk();
    }
}

public class Director{
    GeLi geli=new LiuDeHua();
    Action action=new Action();
    action.setGeLi(geli);
    action.gateAsk();
}
3.介面注入:     其實就是就是將所有依賴注入的方法集合到一個介面中,然後通過實現介面方法來實現介面實現類的傳入。
/**
 * ActorArrange介面
 */
public interface ActorArrange {
   public void setGeLi(GeLi geli);
}

class Action implements ActorArrange{
    private GeLi geli;
    public Action(){}
    //屬性注入
    public void setGeLi(GeLi geli){
        this.geli=geli;
    }
    public void gateAsk(){
        //引入介面展開劇情
        GeLi geli=new LiuDeHua();
        geli.responseAsk();
    }
}

public class Director{
    GeLi geli=new LiuDeHua();
    Action action=new Action();
    action.setGeLi(geli);
    action.gateAsk();
}
    這樣,我們成功地將控制權轉移到了Director上,使得Action只專注於拍攝。但是總得工作量並沒有減少啊!如何實現這些演員分配工作的自動化呢?由此,我們引入了第三方容器。它幫助完成類的初始化與裝配工作,讓開發者從這些底層實現類的例項化、依賴關係裝配等工作中脫離出來,專注於更有意義的業務邏輯開發工作。

    本文轉自http://stamen.iteye.com/blog/1489223/,在此感謝原著作者。