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

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

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

    kapok

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

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

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

     

    模式羅漢拳:Composite模式與自動化測試框架的實現

    透明
    梗概

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

    場景

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


    圖1:文檔結構

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


    圖2:使用Composite模式,系統變得清晰

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

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


    圖3:Composite模式的結構

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

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

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

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


    圖4:CUnit的核心框架

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

    代碼示例

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

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

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

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

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

    posted on 2005-05-09 15:46 笨笨 閱讀(521) 評論(0)  編輯  收藏 所屬分類: J2EEALL
    主站蜘蛛池模板: 在线观看亚洲精品福利片| 日产乱码一卡二卡三免费| 亚洲精品美女久久久久99| 精品在线免费视频| 国产一精品一aⅴ一免费| 美女羞羞视频免费网站| 免费一级黄色毛片| caoporn成人免费公开| 久久久久亚洲精品男人的天堂| 二级毛片免费观看全程| 亚洲乱码国产一区网址| 久久国产乱子伦精品免费午夜| 亚洲精品无码av人在线观看| 国产在线精品免费aaa片| 亚洲一区二区三区高清| 皇色在线视频免费网站| 亚洲精品久久无码av片俺去也| 午夜毛片不卡免费观看视频| 另类小说亚洲色图| 国产亚洲av人片在线观看| 国产精品免费AV片在线观看| 亚洲无砖砖区免费| 四虎影院免费视频| 日本激情猛烈在线看免费观看| 亚洲欧洲无码AV电影在线观看| 59pao成国产成视频永久免费 | 久久亚洲高清综合| 免费国产99久久久香蕉| 亚洲二区在线视频| 免费夜色污私人影院在线观看| 久久免费精品一区二区| 亚洲不卡中文字幕| 亚洲男女内射在线播放| 日韩精品无码免费一区二区三区| 亚洲中文无码永久免费| 久久亚洲AV无码西西人体| 久草免费在线观看视频| 一区二区免费国产在线观看| 777亚洲精品乱码久久久久久 | 亚洲av中文无码字幕色不卡| 综合亚洲伊人午夜网|