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

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

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

    kapok

    垃圾桶,嘿嘿,我藏的這么深你們還能找到啊,真牛!

      BlogJava :: 首頁 :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理 ::
      455 隨筆 :: 0 文章 :: 76 評論 :: 0 Trackbacks

    http://www.c-view.org/journal/006/pattern_gigix.htm

     

    模式羅漢拳:Composite模式與自動化測試框架的實現(xiàn)

    透明
    梗概

    Composite模式將相似的對象以樹型結(jié)構(gòu)的方式組合在一起,使開發(fā)者可以創(chuàng)建復雜的對象。另外,Composite模式要求樹中的對象都有共同的超類(或者說:接口),因此可以用同樣的方式來處理樹中的對象。

    場景

    講到Composite模式,總會涉及“文檔格式化”這個例子,我也繼續(xù)用這個例子。假設你正在設計一個文檔格式化程序,這個程序的作用就是把字(character)格式化為行(line of text),很多行就組織成欄(column),欄再組織成頁(page)。一篇文檔(document)還可能包括其他的元素,例如圖片(image)之類的。欄和頁中還可以有框(frame),框中可以再容納欄。欄、框和行都可以包含圖片。從上面的描述,你可以得到這樣的一個設計:


    圖1:文檔結(jié)構(gòu)

    這些不同的關聯(lián)使得系統(tǒng)的復雜度變得巨大。你可以想象,維護這樣的一個系統(tǒng)會有多困難!如果使用Composite模式,系統(tǒng)的復雜度會大大降低(如圖2所示)。


    圖2:使用Composite模式,系統(tǒng)變得清晰

    約束
    • 你手上有一個復雜的對象,希望將它分解成一個“由部分組成整體”的類體系。
    • 你希望盡量減少這個類體系的復雜度。為了達到這個目的,應該讓繼承樹中的每個子對象都盡量少去了解其他子對象。
    解決方案

    使用Composite模式。所有類都派生自共同的基類(在上面的例子中就是DocumentElement);然后,可以包容其他元素的類派生自CompositeDocumentElement類(這個類也派生自DocumentElement類)。Composite模式的一般結(jié)構(gòu)如圖3所示,具體的實現(xiàn)細節(jié)我們將在下面講到。


    圖3:Composite模式的結(jié)構(gòu)

    效果
    • 樹型結(jié)構(gòu)的組合對象可以把其中包含的所有對象都當作AbstractComponent類的實例來處理,不管這些對象實際上是簡單對象還是組合對象。
    • 客戶可以把組合對象也當作AbstractComponent類的實例來處理,而不必再去了解子類的實現(xiàn)細節(jié)。
    • 如果客戶在AbstractComposite派生類的對象上調(diào)用了AbstractComponent類的方法,該對象就會把調(diào)用轉(zhuǎn)發(fā)給其中包含的AbstractComponent對象。
    • 如果客戶調(diào)用方法的對象是AbstractComponent的派生對象、而不是AbstractComposite的派生對象,并且這個方法還需要與場景相關的信息,那么AbstractComponent對象就會把請求轉(zhuǎn)發(fā)給自己的父對象(也就是包容自己的對象)。
    • Composite模式允許任何AbstractComponent派生對象成為任何AbstractComposite派生對象的子對象(也就是被容納的對象)。如果你需要更多的限制,就必須為AbstractComposite及其子類加上類型判別代碼,這就會使Composite模式的價值打折扣。
    • 被容納的對象可能會有特有的方法。你可以在AbstractComponent類中聲明這個方法,并給它一個空的實現(xiàn),這樣就可以在組合對象中使用這個方法,而且不需要引入類型判別代碼。
    實現(xiàn)
    • 如果被包容的對象需要向包容對象轉(zhuǎn)發(fā)請求,那么你可以讓被包容對象保存一個指向包容對象的指針,這樣轉(zhuǎn)發(fā)會更簡單。
    • 如果要讓被包容對象保存包容對象的指針,那么就必須有某種機制來保證兩者關聯(lián)的一致性。最好是在Add()方法(或其他功能相似的方法)中添加相關的設置。
    • 出于效率的考慮,對象可以把父對象轉(zhuǎn)發(fā)過來的方法調(diào)用的結(jié)果暫存(cache)起來。
    • 如果子對象暫存了方法調(diào)用的結(jié)果,當結(jié)果不再正確的時候,父對象就必須提醒子對象。
    實現(xiàn)一個自動化測試框架

    第一個問題:什么是“自動化測試框架”?顧名思義,自動化測試框架(automated testing framework)就是可以自動對代碼進行單元測試的框架。在傳統(tǒng)的軟件開發(fā)流程中,計劃、設計、編碼和測試都有各自獨立的階段,階段之間不回溯,所以測試是不是自動化并不重要——反正有的是時間來慢慢測試。但是,在新的軟件開發(fā)流程中,迭代周期變短,要求對代碼進行頻繁地重構(gòu)。而這就要求單元測試必須能夠自動、簡便、高速地運行,否則重構(gòu)就是不現(xiàn)實的[1]。

    OK,我假設你已經(jīng)明白了測試框架的作用,現(xiàn)在我們來看看它的需求。別忘了,這可是“自動化”的測試框架,它應該簡單到開發(fā)者按一個按鈕就能完成所有測試的程度。所以,我們必須以某種方式將測試用例(test case)組織成一個測試套件(suite),然后才能很方便地自動運行它;此外,還必須能很簡單地向套件中添加新的測試用例,添加多少都可以,而且還不影響套件的正常運行;而且,測試套件還應該可以隨意組合,也就是說:一個套件應該可以包含其他的套件。

    看看這些需求,想到了什么?很明顯,這就是一個Composite模式。簡單的結(jié)構(gòu)如圖4:


    圖4:CUnit的核心框架

    在《Refactoring》中,Martin Fowler介紹了Java的自動化測試框架JUnit。參考JUnit的結(jié)構(gòu),我用C++寫了一個測試框架CUnit,圖4就是CUnit的結(jié)構(gòu)。這是一個典型的Composite模式:TestSuite可以容納任何派生自Test的對象;當調(diào)用TestSuite對象的run()方法時,它會遍歷自己容納的對象,逐個調(diào)用它們的run()方法;客戶無須關心自己拿到的究竟是TestCase還是TestSuite,他(它)只管調(diào)用對象的run()方法,然后分析run()方法返回的結(jié)果就行了[2]。

    代碼示例

    下面,我們來看看CUnit的一些關鍵代碼。首先是Test類,它定義了一個公用的接口:

    class Test
    {
    public:
        virtual void run() = 0;
    };
    
    然后,TestCase類繼承了Test類,加入了兩個新方法setUp()和tearDown()(關于這兩個方法的用途,請參見《Refactoring》一書的相關章節(jié))。TestCase不實現(xiàn)run()方法,所以它也是一個抽象類。用戶需要從TestCase類派生出自己的測試用例類,并根據(jù)自己的需要來實現(xiàn)run()方法。另外,用戶可能想自己實現(xiàn)setUp()和tearDown()這兩個方法,也有可能不做任何實現(xiàn),所以這兩個方法應該是虛方法,但不能是純虛方法。
    class TestCase : public Test
    {
    protected:
        virtual void setUp(){ };
        virtual void tearDown(){ };
    };
    
    TestSuite類也繼承了Test類。由于TestSuite是一個Composite類,所以它能夠容納其他Test類型的對象(用addTest()方法添加);而TestSuite::run()則遍歷這些被包容的對象,逐個調(diào)用它們的run()方法。
    class TestSuite : public Test
    {
    public:
    	void addTest(Test * test){
    	m_Compositee.push_back(test);
    };
    	virtual void run(){
    		for(int i=0; irun();
    };
    private:
        vector m_Compositee;
    };
    
    以上就是CUnit的主要代碼。當然,要實現(xiàn)自動化的單元測試,僅靠這個類體系是遠遠不夠的,還需要其他很多的技巧。我把CUnit的全部代碼上傳到了http://gigix.topcool.net/download/03.zip,歡迎有興趣的讀者與我一起討論。
    相關模式
    • Chain of Responsibility模式
      添加相應的父對象連接,就可以把Chain of Responsibility模式和Composite模式組合起來。這樣,子對象就可以從某個祖先那里得到信息,而不必知道究竟從哪個祖先得到信息。

    • Visitor模式
      Visitor模式可以把Composite模式中散布在多個類中的操作封裝在一個類中。
    注釋

    [1] 關于重構(gòu)和自動化測試框架的概念,參見Martin Fowler的《Refactoring》。此外,《程序員》雜志2001年第12期技術專題“代碼重構(gòu)”也有關于重構(gòu)的知識。

    [2] 實際上我的CUnit與JUnit還有一定的差異,因為我的主要目的是為了闡述Composite模式的應用,而非設計真正實用的測試框架。在Source Forge上有一個叫CppUnit的項目,其結(jié)構(gòu)與JUnit幾乎毫無二致,而且也更加完善。

    posted on 2005-05-09 15:46 笨笨 閱讀(521) 評論(0)  編輯  收藏 所屬分類: J2EEALL
    主站蜘蛛池模板: 日产亚洲一区二区三区| 亚洲中文字幕无码av| 国产v精品成人免费视频400条| 亚洲AV无码一区二区乱子仑| 亚洲日产无码中文字幕| 两性刺激生活片免费视频| 美女视频黄a视频全免费网站一区| 亚洲精品国产精品乱码在线观看| 台湾一级毛片永久免费| 久久精品成人免费观看97| 亚洲成人网在线播放| 亚洲精品国产自在久久 | 久久午夜夜伦鲁鲁片免费无码影视 | 97在线视频免费播放| 亚洲国产精品无码久久98| 亚洲中文字幕无码日韩| 国产一卡2卡3卡4卡无卡免费视频 国产一卡二卡3卡四卡免费 | 国产91色综合久久免费分享| 男人免费视频一区二区在线观看| 亚洲成人动漫在线| 午夜亚洲av永久无码精品| 99re免费视频| 一级毛片免费毛片毛片| 亚洲中文久久精品无码1| 亚洲中文字幕日产乱码高清app| 中文字幕无码成人免费视频| 国产免费无码一区二区| 国产综合成人亚洲区| 亚洲毛片在线免费观看| 中文字幕亚洲天堂| 国产精品无码一二区免费 | 一级做a爰片久久毛片免费陪 | 一区二区三区免费视频观看| 色老板亚洲视频免在线观| 亚洲日产韩国一二三四区| 亚洲 综合 国产 欧洲 丝袜| aa级一级天堂片免费观看| 无码人妻一区二区三区免费n鬼沢 无码人妻一区二区三区免费看 | 中文在线观看永久免费| 国产亚洲视频在线| 一本色道久久88亚洲精品综合 |