C# 控制反轉

2006年多部賀歲大片以讓人目不暇接的頻率紛至沓來,其中張之亮的《墨攻》算是比較出彩的一部,講述了戰國時期墨家人革離幫助梁html

國反抗趙國侵略的我的英雄主義故事,恢宏壯闊,渾雄凝重的歷史場面至關震撼。其中有一個場景:當劉德華所飾的墨者革離到達梁國都城java

下,城上樑國守軍問:「來者何人?」,劉德華回答:「墨者革離!」,咱們不妨用C#(原文是java,我修改)對這段「城門問對」的場景進行編劇並藉由這個例子來理解IoC的內涵。函數

劇本和飾演者耦合this

MoAttack表明《墨攻》的劇本,cityGetAsk()表明「城門問對」這段劇情,LiuDeHua是具體飾演者劉德華:3d

代碼清單1htm

public class MoAttack {blog

     public MoAttack() {}接口

     public void cityGateAsk(){ci

        LiuDeHua ldh = new LiuDeHua(); ① 演員直接侵入劇本it

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

   }

}

咱們會發現以上劇本在①處,做爲具體飾演者的劉德華直接侵入到劇本中,使劇本和演員直接耦合在一塊兒:

圖(1)劇本與演員直接耦合

一個明智的編劇在劇情創做時應圍繞故事的角色進行,而不該考慮角色的具體飾演者,這樣纔可能在劇本投拍時自由地選擇任何適合的演員,而非綁定在劉德華一人身上。經過以上的分析,咱們知道須要爲該劇本主人公革離定義一個接口,以角色進行劇情安排,飾演者實現角色的接口:

代碼清單2 MoAttack:引入劇本角色

public class MoAttack{

    public MoAttack() {}

    public void cityGateAsk()

    {

         GeLi geli = new LiuDeHua(); ① 引入革離角色接口

         geli.responseAsk("墨者革離!"); ② 經過接口開展劇情

     }

}

在①處引入了劇本的角色——革離,劇本的情節經過角色展開,在拍攝時角色的事蹟由演員表現,如②處所示。所以劇本、革離、劉德華三者的類圖關係如圖2所示:

圖2劇本、革離、劉德華三者的類圖關係

咱們但願劇本和演員無關,但是,在圖2中,咱們看到MoAttack同時依賴於GeLi接口和LiuDeHua類,並無達到咱們所指望的劇本僅依賴於角色的目的。但是角色最終又必須經過具體的演員才能完成拍攝,如何將讓LiuDeHua和劇本無關而又能完成GeLi的具體動做呢?固然是在影片投拍時,導演將LiuDeHua安排在GeLi的角色上,經過導演之手將劇本、角色、飾演者裝配起來。

圖3劇本和飾演者解耦了

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

如今咱們能夠反過來說解IOC的概念了。IOC(Inverse of Control)的字面意思是控制反轉,它包括兩個層面的內容:其一是「控制」,其二是「反轉」,究竟是什麼東西的控制被反轉了呢?對應到前面的例子, 「控制」是指GeLi角色扮演者的選擇控制權,「反轉」是指這種選擇控制權從《墨攻》劇本中移除,轉交到導演的手中。對於程序來講,便是某一接口具體實現類的選擇控制權從客戶類中移除,轉交給第三方來肯定,客戶類不知道是哪一個具體的實現類,它經過接口方法對實現類進行調用。

由於IOC確實不夠開門見山,所以業界曾進行了普遍的討論,最終軟件界的泰斗級人物Martin Fowler提出了DI(依賴注入:Dependency Injection)的概念,即將客戶類對接口實現類的依賴關係由第三方(容器或協做類)注入,以移除客戶類對具體接口實現類的依賴。「依賴注入」的概念顯然比「控制反轉」直接達意,易於理解。

IOC的三種類型

從注入方法上看,主要能夠劃分爲三種的注入類型,分別是構造函數注入、屬性注入和接口注入,Spring.Net支持構造函數注入和屬性注入。下面咱們繼續使用以上的例子說明這三種注入方法的區別。

構造函數注入

咱們經過客戶類的構造函數,將接口實現類經過接口變量傳入,如代碼清單3所示:

代碼清單3 MoAttack:經過構造函數注入革離扮演者

public class MoAttack{

    public MoAttack(){}

    private GeLi geli;

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

        this.geli = geli;

     }

     public void cityGateAsk()

     {

        geli.responseAsk(「墨者革離!」);

    }

}

MoAttack的構造函數不關心具體是誰扮演革離這個角色,只要在①處傳入的扮演者按劇本要求完成角色功能便可。

角色的具體扮演者由導演來安排,如代碼清單4所示:

代碼清單 4 Director:經過構造函數注入革離扮演者

public class Director {

     public void direct(){

        GeLi geli = new LiuDeHua(); ① 指定角色的扮演者

        MoAttack moAttack = new MoAttack(geli); ② 注入具體扮演者到劇本中

        moAttack.cityGateAsk();

    }

}

屬性注入

有時,導演會發現,雖然革離是影片《墨攻》的第一主人公,但並不是每場戲都須要革離的出現,經過構造函數方式注入顯得很不穩當,在這種狀況下,可使用屬性注入進行改造。屬性注入經過通.Net 屬性完成客戶類所需依賴的注入,更靈活,更方便。

代碼清單5 MoAttack:通.Net 屬性器注入革離扮演者

public class MoAttack{

     private GeLi gelii;

    public GeLi Gelii{ ① 屬性注入方法

         set{ gelii = value; }

    }

    public void cityGateAsk() ...{

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

    }

}

MoAttack在①處爲geli 字段提供一個屬性,以便讓導演在拍須要革離的戲時纔將注入geli的具體扮演者,而不須要劉德華從頭至尾跟着墨攻劇組跑。

代碼清單 6 Director:經過屬性注入革離扮演者

public class Director{

    public void direct(){

        GeLi geli = new LiuDeHua();

         MoAttack moAttack = new MoAttack();

        moAttack.Gelii = geli; ① 調用屬性注入

        moAttack.cityGateAsk();

    }

}

和經過構造函數注入革離扮演者不一樣,在實例化MoAttack時,並未指定任何扮演者,而是在實例化MoAttack後,調用其屬性注入扮演者。按照相似的方式,咱們還能夠爲劇本中其餘如巷淹中,梁王等角色分別提供注入的屬性,導演便可以根據所拍劇段的不一樣,注入所須要的角色了。

接口注入

將客戶類全部注入的方法抽取到一個接口中,客戶類經過實現這一接口提供注入的方法。爲了採起接口注入的方式,須要聲明一個額外的接口:

public interface IActorArrangable{

     void injectGeli(GeLi geli);

}

而後,MoAttack實現這個接口並實現接口中的方法:

代碼清單7 MoAttack:經過接口方法注入革離扮演者

public class MoAttack : IActorArrangable{

    private GeLi geli;

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

        this.geli = geli;

    }

     public void cityGateAsk() ...{

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

     }

}

Director經過IActorArrangable接口的injectGeli()方法完成扮演者的注入工做。

代碼清單 8 Director:經過接口方法注入革離扮演者

public class Director{

     public void direct(){

        GeLi geli = new LiuDeHua();

        MoAttack moAttack = new MoAttack();

        moAttack.injectGeli (geli);

        moAttack.cityGateAsk();

    }

}

因爲經過接口注入須要額外聲明一個接口,增長了類的數目,並且它的效果和屬性注入並沒有本質區別,所以咱們不提倡這種方式。

經過容器完成依賴關係的創建

雖然MoAttack和LiuDeHua實現瞭解耦,無需關注實現類的實例化工做,但這些工做在代碼中依然存在,只是轉移到Director中而已,致使導演的權力很是大,潛規則不斷滋生。假設某一製片人想改變這一局面,在相中某個劇本後,經過一個「海選」或者第三公正中介來選擇導演、演員,讓他們各司其職,那劇本、導演、演員就都實現解耦了。

所謂媒體「海選」和中介機構在程序領域便是一個第三方容器,它幫助咱們完成類的初始化和裝配工做,讓咱們從這些底層的實現類實例化,依賴關係的裝配中脫離出來,專一於更有意思的業務代碼的編寫工做,那確實是挺愜意的事情。Spring.Net就是這樣一個容器,它經過配置文件描述類之間的依賴關係,下面是Spring.Net配置文件的對以上實例進行配置的樣式代碼:

<objects>

    <object id="geli" type="com.baobaotao.LiuDeHua"></object>

    <object id="moAttack" type=" com.baobaotao.MoAttack">

        <property name="geli"><ref="geli"/></property>

    </object>

</objects>

 

轉自https://www.cnblogs.com/zhangchenliang/archive/2013/01/08/2850975.html

相關文章
相關標籤/搜索