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

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

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

    無(wú)為

    無(wú)為則可為,無(wú)為則至深!

      BlogJava :: 首頁(yè) :: 聯(lián)系 :: 聚合  :: 管理
      190 Posts :: 291 Stories :: 258 Comments :: 0 Trackbacks

    也許在各位讀者眼里,依賴注入和框架Spring等同的。其實(shí)依賴注入是一個(gè)可以在容器外使用的OO開發(fā)概念。同時(shí),依賴注入(Dependency Injection)對(duì)于單元測(cè)試
    也很有用。在該篇blog中,我們可以了解到:

    • 什么是依賴注入(Dependency Injection)
    • 如何保證類和依賴注入友好性
    • 依賴注入有助于單元測(cè)試

    女士們先生們,跟我一起來(lái)暢游吧。

    一輛簡(jiǎn)單的車

    讓我們用引擎和車來(lái)構(gòu)造一個(gè)簡(jiǎn)單的例子。為了清晰我們使類和接口程序體為空。
    一輛車有引擎,而且我們希望這輛車裝配路虎所用的引擎MooseEngine。
    我們先配置引擎:

    public interface Engine {
    }
    public class SlowEngine implements Engine {
    }
    public class FastEngine implements Engine {
    }
    public class MooseEngine implements Engine {
    }

    接著我們建立車:

    public class Car {
    private MooseEngine engine;
    }

    盡管這是一輛很好的車,但它并不能有任何規(guī)格的引擎,即使市場(chǎng)上有其他品牌的
    車可以得到。我們說(shuō)車類同路虎引擎類是緊耦合的。如果我們決定裝配另一種引擎
    ,會(huì)發(fā)生什么?

    用接口編程

    你可能看到路虎引擎MooseEngine™已經(jīng)實(shí)現(xiàn)了引擎接口。其它品牌引擎也實(shí)現(xiàn)了
    相同的接口。讓我們思考一下,當(dāng)我們?cè)O(shè)計(jì)我們的車Car類時(shí),我們認(rèn)為一個(gè)
    "Car"裝配一個(gè)引擎。所以讓我們重寫一下Car類,讓它使用接口代替具體的引擎
    引用:

    public class Car {
    private Engine engine;
    }


    用接口編程在依賴注入中是一個(gè)重要的概念。你可能說(shuō)這用了一個(gè)接口,那么具體
    類在哪呢?你在哪給它賦值?若我想我的車用路虎引擎MooseEngine,我可以用以下方式給它賦值:

    public class Car {
    private Engine engine = new MooseEngine();
    }

    但是這有用么?這看起來(lái)和第一個(gè)方法沒什么不同。我們的車還是緊緊捆綁在路虎 MooseEngine引擎上,這個(gè)公司倒閉了呢?我們?nèi)ツ抢镎业轿覀兊囊妗?/p>

    介紹依賴注入(Dependency Injection)

    正如名字所示,依賴注入是關(guān)于注入依賴的,或者說(shuō)設(shè)置實(shí)例間的關(guān)系的。有些人
    引用好萊塢的格言解釋它:"不要打電話給我,我會(huì)打給你"。我喜歡叫他"強(qiáng)
    奸"原理:"我不關(guān)心你是誰(shuí),我只想你照我的要求做"。在我們第一個(gè)的例子
    中,Car類依賴于叫MooseEngine的引擎具體類。當(dāng)一個(gè)類A一來(lái)另一個(gè)類B并且B的
    實(shí)現(xiàn)直接在A中得到引用時(shí),我們說(shuō)類A緊耦合類B。正如我們?cè)诘诙嬷锌吹降?我
    們已經(jīng)決定使用Engine接口代替MooseEngine具體類使Car更具靈活性。更進(jìn)一步我
    們決定不定義引擎的具體實(shí)現(xiàn)。換句話說(shuō),我們使Car類松散耦合。Car類不再依賴
    于任何引擎的具體類。那么我們哪里定義我們用的是哪一個(gè)引擎呢?這就是依賴注
    入發(fā)揮作用的地方。我們將從外面注入具體引擎類,代替在Car類中引用具體引擎
    類。如何做到呢?繼續(xù)GO!

    1.使用基于構(gòu)造方法的注入

    建立依賴的一個(gè)方式是通過傳遞依賴的具體實(shí)現(xiàn)給構(gòu)造方法來(lái)建立依賴。我們的Car類將變
    為:

    public class Car {
    private Engine engine;

    public Car(Engine engine) {
    this.engine = engine;
    }
    }

    到那時(shí)我們能使用任何類型的引擎構(gòu)建一輛車。例如,一輛使用偉大的路虎 MooseEngine而另一輛使用劣質(zhì)的SlowEngine:

    public class Test {

    public static void main(String[] args) {
    Car myGreatCar = new Car(new MooseEngine());
    Car hisCrappyCar = new Car(new SlowEngine());
    }
    }

    2. 基于setter方法的injection

    建立依賴的另一種方法是使用setter方法。當(dāng)很多依賴需要注入時(shí),推薦使用setter方
    法。我們的Car類這時(shí)又變成了樣:

    public class Car {
    private Engine engine;

    public void setEngine(Engine engine) {
    this.engine = engine;
    }
    }

    它看起來(lái)和基于構(gòu)造方法注入長(zhǎng)得差不多。我們使用以下方式實(shí)現(xiàn)相同的Car類:

    public class Test {

    public static void main(String[] args) {
    Car myGreatCar = new Car();
    myGreatCar.setEngine(new MooseEngine());
    Car hisCrappyCar = new Car();
    hisCrappyCar.setEngine(new SlowEngine());
    }
    }

    單元測(cè)試中用依賴注入

    如果你用Car類的第一版和基于setter方法注入的比較,那么你可能認(rèn)為使用依賴注入需要使用一些額外的操作。這么說(shuō)沒錯(cuò)。你必須寫一個(gè)setter方法。但是當(dāng)你進(jìn)行測(cè)試時(shí),就會(huì)發(fā)現(xiàn)這些額外操作很有好處。若你對(duì)什么是單元測(cè)試一臉茫然的話,
    你最好看一看《Unit in Action》這本書。我們的車?yán)雍芎?jiǎn)單,所以不能看出單元
    測(cè)試的依賴注入多么有用。 我們下車,考慮一個(gè)營(yíng)火會(huì)的例子,特別是在單元測(cè)試
    中使用mock這部分。我們有一個(gè)用遠(yuǎn)程EJB注冊(cè)農(nóng)場(chǎng)動(dòng)物的的servlet類 。

    public class FarmServlet extends ActionServlet {

    public void doAction( ServletData servletData ) throws Exception {
    String species = servletData.getParameter("species");
    String buildingID = servletData.getParameter("buildingID");
    if ( Str.usable( species ) && Str.usable( buildingID ) ) {
    FarmEJBRemote remote = FarmEJBUtil.getHome().create(); remote.addAnimal( species , buildingID ); } } }


    你應(yīng)該也注意到FarmServlet是緊耦合于FarmEJBRemote實(shí)例,通過調(diào)用"FarmEJBUtil.getHome().create()"解析該實(shí)例。這樣做很難進(jìn)行測(cè)試。當(dāng)進(jìn)行單元
    測(cè)試的時(shí)候,我們不想用任何數(shù)據(jù)庫(kù)。我們也不想訪問一個(gè)EJB服務(wù)器。這使進(jìn)行
    單元測(cè)試非常難以執(zhí)行并且很慢。所以為了順利進(jìn)行FarmServlet 類的單元測(cè)試,我
    們使它成為松散耦合的。為了移除FarmServlet和FarmEJBRemote的強(qiáng)依賴 ,我們用
    基于setter方法的注入:

    public class FarmServlet extends ActionServlet {
    private FarmEJBRemote remote;

    public void setRemote(FarmEJBRemote remote) {
    this.remote = remote;
    }
    public void doAction( ServletData servletData ) throws Exception { String species = servletData.getParameter("species"); String buildingID = servletData.getParameter("buildingID"); if ( Str.usable( species ) && Str.usable( buildingID ) ) { remote.addAnimal( species , buildingID ); } } }


    在真實(shí)的部署包中,我們將確定FarmServlet的遠(yuǎn)程成員的實(shí)例通過使用
    "FarmEJBUtil.getHome().create()"已經(jīng)被注入了。在我們的單元測(cè)試中,我們生成
    一個(gè)moke類模擬FarmEJBRemote。換句話說(shuō),就是我們將用一個(gè)moke類實(shí)現(xiàn)
    FarmEJBRemote:

    class MockFarmEJBRemote implements FarmEJBRemote {

    private String species = null;
    private String buildingID = null;
    private int nbCalls = 0;

    public void addAnimal( String species , String buildingID )
    {
    this.species = species ;
    this.buildingID = buildingID ;
    this.nbCalls++;
    }

    public String getSpecies() {
    return species;
    }
    public String getBuildingID() {
    return buildingID;
    }
    public int getNbCalls() {
    return nbCalls;
    }
    }

    public class TestFarmServlet extends TestCase {

    public void testAddAnimal() throws Exception {
    // mock操作和一個(gè)FarmEJBRemote相似
    MockFarmEJBRemote mockRemote = new MockFarmEJBRemote(); // servlet,我們將mock賦值給遠(yuǎn)程依賴。 FarmServlet servlet = new FarmServlet();
    servlet.setRemote(mockRemote);
    // 另一個(gè)象ServletData的mock
    MockServletData mockServletData = new MockServletData();
    mockServletData.getParameter_returns.put("species","dog");
    mockServletData.getParameter_returns.put("buildingID","27");

    servlet.doAction( mockServletData );
    assertEquals( 1 , mockRemote.getNbCalls() );
    assertEquals( "dog" , mockRemote.getSpecies() );
    assertEquals( 27 , mockRemote.getBuildingID() );
    }
    }


    就到這吧。我們能很容易的測(cè)試FarmServlet。
    總結(jié)一下吧:

    • 使用接口代替使用具體類來(lái)說(shuō)明一個(gè)依賴。

    • 避免在類中顯式設(shè)置一個(gè)依賴的具體實(shí)現(xiàn)。

    • 賦值依賴的具體實(shí)現(xiàn)可能有多種方式,包括基于構(gòu)造方法或者setter方法的注
      入。
    • 依賴注入可以讓單元測(cè)試增加靈活性。

    以上的探討,對(duì)各位同仁有用的話請(qǐng)回復(fù)一下。




    凡是有該標(biāo)志的文章,都是該blog博主Caoer(草兒)原創(chuàng),凡是索引、收藏
    、轉(zhuǎn)載請(qǐng)注明來(lái)處和原文作者。非常感謝。

    posted on 2007-09-14 17:07 草兒 閱讀(2477) 評(píng)論(3)  編輯  收藏 所屬分類: 設(shè)計(jì)模式JAVA WEB應(yīng)用

    Feedback

    # re: 依賴注入和單元測(cè)試 2007-09-14 21:33 劉甘泉
    草兒。。好女性化的名字  回復(fù)  更多評(píng)論
      

    # re: 依賴注入和單元測(cè)試 2007-09-14 22:14 草兒
    哈哈 朋友開玩笑的稱號(hào) 自己保留下來(lái)了。  回復(fù)  更多評(píng)論
      

    # re: 依賴注入和單元測(cè)試 2007-09-15 09:39 千里冰封
    依賴注入確實(shí)是方便了許多  回復(fù)  更多評(píng)論
      

    主站蜘蛛池模板: 无码天堂亚洲国产AV| 亚洲国产一区二区视频网站| 四虎在线最新永久免费| 久久久精品免费视频| 天黑黑影院在线观看视频高清免费 | a毛片免费全部在线播放**| 成年大片免费高清在线看黄| MM1313亚洲国产精品| 国内成人精品亚洲日本语音| 看亚洲a级一级毛片| 男女交性无遮挡免费视频| 深夜免费在线视频| 人体大胆做受免费视频| 精品久久久久久国产免费了| 香蕉免费一级视频在线观看| 99re6在线视频精品免费| 久久久久久国产精品免费免费男同 | 一级毛片免费播放| 亚洲黄色免费电影| 国内精品乱码卡1卡2卡3免费| 成人午夜视频免费| 人人狠狠综合久久亚洲高清| 亚洲午夜成人精品电影在线观看| 亚洲综合色成在线播放| 亚洲gv白嫩小受在线观看| 911精品国产亚洲日本美国韩国| 亚洲成AV人综合在线观看| 亚洲熟妇无码一区二区三区| 国产亚洲精品美女久久久久| 国产成人无码精品久久久久免费 | 欧洲 亚洲 国产图片综合| 老司机福利在线免费观看| a在线观看免费网址大全| 亚洲黄色免费观看| 国产青草视频免费观看97| 久久亚洲高清综合| 亚洲欧洲日韩国产| 日韩精品亚洲专区在线影视| 中文字幕在线免费播放| 亚洲最大免费视频网| 性做久久久久免费观看|