2014-06-20 45 views
1

你好我的Java有點生疏,所以請耐心等待。我的任務是減少研究項目中重複代碼的數量,因此我認爲我無法在此處發佈任何代碼。但基本上,我有大約20個不同類別的大致相同的方法(測試方法),我一直在嘗試兩種不同的方法來解決這個問題,但我遇到了每個問題。將變量傳遞到使用其他方法或繼承的方法

我發現,以減少重複第一種方式是,以除去包含在所有的試驗方法初始變量並將其放置在一個單獨的方法(製備方法)類的超類的內部和具有它稱爲測試方法。這個解決方案的問題不是在準備方法中聲明的所有變量將保持本地狀態,並且一旦在另一個方法中調用該方法時就會被擦除?

我的第二個想法是讓超類的所有變量字段,並讓它們被子類繼承。這個解決方案几乎可以工作,除了其中一個變量IFile importedFile = importFile(file);是創建這些變量所必需的變量之一,它必須包含拋出異常所包含的任何內容,我不相信你可以用類來完成。

我一直希望有人能夠用這些解決方案之一指出我正確的方向,或者可能會提出另一個我一直無法找到的解決方案。

我忘了提及的一點是,除了初始變量之外,每種測試方法在寫入測試方法時略有不同。 編輯:如果不是這樣的話,我會把這個方法拉進超類,並且完成它。

編輯:下面是測試方法,我使用了超類的部分,

// method inside of the subclass  
public void test() throws Exception { 
      // variables removed and placed in AbstractTest 
      for (int i = 0; i < expectedExitNodeCount; i++) { 
       if (markerFields.peekFirst().equalsIgnoreCase("EXPOSED_EXIT")) { 
        expectedExitNodes.add(new CTrueExitNode()); 
       } else { 
        fromLine = Integer.parseInt(markerFields.removeFirst().trim()); 
        fromCol = Integer.parseInt(markerFields.removeFirst().trim()); 
        toLine = Integer.parseInt(markerFields.removeFirst().trim()); 
        toCol = Integer.parseInt(markerFields.removeFirst().trim()); 
        length = length(ast, fromLine, fromCol, toLine, toCol); 
        assertTrue(length > 0); 
        ICFlowNode expectedExit = findNode(ast, ICFlowNode.class, fromLine, fromCol, length); 
        assertNotNull(expectedExit); 
        expectedExitNodes.add(expectedExit); 
       } 
      } 
       // additional code omitted from method 
      } 

// Superclass the variables have been placed in. 
public abstract class AbstractTestCase extends WorkTest { 
    protected File file; 
    protected String markerText; 

    public AbstractTestCase(String name, VPG< ? , ? , ? > vpg) { 
     super(name, vpg); 
    } 

    protected void prepare() throws Exception { 
     // Variables used in the test method 
      IFile importedFile = importFile(file); 

     project.refreshLocal(IResource.DEPTH_INFINITE, new NullProgressMonitor()); 
     CVPG.getInstance().ensureVPGIsUpToDate(); 

     CTranslationUnit ast = CVPG.getInstance().acquireTransientAST(
      ResourceUtil.getFilenameForIFile(importedFile)); 

     LinkedList<String> markerFields = MarkerUtil.parseMarker(markerText); 

     int fromLine = Integer.parseInt(markerFields.removeFirst().trim()); 
     int fromCol = Integer.parseInt(markerFields.removeFirst().trim()); 
     int toLine = Integer.parseInt(markerFields.removeFirst().trim()); 
     int toCol = Integer.parseInt(markerFields.removeFirst().trim()); 
     int length = length(ast, fromLine, fromCol, toLine, toCol); 
     assertTrue(length > 0); 
     IASTNode node = findNode(ast, IASTNode.class, fromLine, fromCol, length); 
     assertNotNull(node); 

     Integer expectedExitNodeCount = Integer.parseInt(markerFields.removeFirst().trim()); 
     Set<ICFlowNode> expectedExitNodes = new HashSet<ICFlowNode>(); 
    } 

    protected void test() throws Exception { 
     //Considered making test a inherited method 
    } 
} 
+0

你面臨的例外是什麼? –

+2

這將很難幫助刪除無代碼的輕微差異的重複。請求權限發佈它或提出一個遵循相同模式的假示例。 –

+0

「每種測試方法略有不同」...有時[Template method pattern](http://en.wikipedia.org/wiki/Template_method)可以處理這種性質的重複。 – ajb

回答

0

定義變量作爲字段是一個很好的方式,我想。但是你應該稍後初始化它們。只需使用一個構造函數來初始化變量,然後就可以捕獲異常!

1

爲什麼現場方法並不那麼酷:您正在引入順序耦合。接下來誰不會知道,如果沒有調用方法準備,方法測試將失敗。此外,如果一個類擴展另一個或結構的變化,你可能最終調用準備的兩倍,並具有難以跟蹤誤差

模式1)將所有的變量進入狀態對象

組變量進入一個新的對象 - 而不是超類

創建一個生成器對象,這樣就可以輕鬆地初始化類,你需要什麼變量到這個對象

更改測試方法來接受這個對象和工作從其數據

public class TestParameters { 
    public boolean flag1; 
    public int someNumber; 
} 

public class Tester { 

    public static void test(TestParameters p) { 
     for (int i=0; int i<p.someNumber;i++) { 
      if (p.flag1) doA(); 
      else doB(); 
     } 
    } 
} 

public class Builder { 
    TestParameters p = new TestParameters(); 

    new Builder() { 
    } 

    public Builder setFlag(boolean f) { 
     p.flag1 = f; 
    } 

    public Builder setNumber(int n) { 
     p.someNumber = n; 
    } 
    public TestParameters build() { 
     return p; 
    } 
} 

public class SomeClass { 

    public void doSomething() { 
     TestParameters p = new Builder().setFlag(true).setNumber(10).build(); 
     Tester.test(p); 
    } 
} 

模式2)控制

反轉爲您的測試方法的類,使這個新類的可變部分領域。這個類的構造函數中設置變量 - 添加靜態getInstanceForXxxx方法和硬編碼你需要爲每個靜態干將的魔法值 - 到每個getInstanceForXxxx您創建一個新的實例傳遞任何initializarion價值客戶需要

public class Tester { 
    public boolean flag1; 
    public int someNumber; 

    private Tester() {}; 

    //feel free to be more descriptive if each initialization apply for more than one class 
    public static Tester testForClassSomeClass() { 
     Tester t = new Tester(); 
     t.flag1=false; 
     t.int=2; 
     return t; 
    } 

    public void test() { 
     for (int i=0; int i<someNumber;i++) { 
      if (flag1) doA(); 
      else doB(); 
     } 
    } 

} 


public class SomeClass { 

    public void doSomething() { 
     Tester t = Tester.testForClassSomeClass(); 
     t.test(); 
    } 
} 

模式3 )在策略中封裝行爲

創建一個基類。重複代碼中的每個點都不同,重構爲一個私有方法。創建一個類並用你需要的專門代碼覆蓋每個方法。實例化正確類爲每個客戶端,並呼籲公衆測試方法

public abstract class Tester { 


    private Tester() {}; 

    public boolean getFlag(); 
    public int getNumber(); 
    public int someLogic(); 

    public void test() {...} 

} 
public class SomeClassTester { 


    private Tester() {}; 


    public int getNumber() { 
     return false; 
    } 
    public int someLogic() { 
     doA(); 
    } 

    public static void test() { 
     for (int i=0; int i<getNumber();i++) { 
      doA(); 
     } 
    } 

} 


public class SomeClass { 

    public void doSomething() { 
     Tester t = new SomeClassTester(); 
     t.test(); 
    } 
} 

我喜歡這最後的,因爲它擺脫了標誌(FLAG1)和封裝正確的行爲(具體SomeClass的測試只有DOA()調用)