简体   繁体   English

使用其他方法或继承将变量传递给方法

[英]Passing variables into a method using another method or inheritence

Hello I'm a little rusty on my Java, so please bear with me. 您好,我对Java有点生锈,所以请多多包涵。 I have been tasked with reducing the amount of duplicated code in a research project for my Professor, so I don't think I'm able to post any of the code on here. 我的任务是减少教授使用的研究项目中的重复代码,因此我认为我无法在此处发布任何代码。 But basically I have about 20 cases of generally the same method ( test method ) in different classes, and I've been trying two different ways to solve this problem but I have run into issues with each. 但是基本上我在不同的类中有大约20种情况下通常使用相同的方法( 测试方法 ),并且我一直在尝试两种不同的方法来解决此问题,但是每种方法都遇到了问题。

The first way I've found to reduce the duplication is to remove the initial variables contained in all of the test methods and place them in a separate method ( prepare method ) inside of a superclass and have it called into the test method . 我发现减少重复的第一种方法是删除所有测试方法中包含的初始变量,并将它们放在超类内部的单独方法( prepare方法 )中,并将其调用到test方法中 Isn't the problem with this solution that all of the variables declared in the prepare method will remain local and be erased as soon as the method is called inside of another method? 这种解决方案的问题不是在prepare方法中声明的所有变量都将保留在本地,并在该方法在另一个方法内部被调用时立即被擦除吗?

The second idea I had was to just make all of the variables fields of the superclass and have them be inherited by the subclasses. 我的第二个想法是只制作超类的所有变量字段,并让它们被子类继承。 This solution almost worked except for the fact that one of the variables IFile importedFile = importFile(file); 该解决方案几乎可以用,除了以下事实外,其中一个变量IFile importedFile = importFile(file); which is necessary for creating many of these variables has to have whatever it is contained in throw an Exception, which I do not believe you can do with a class. 创建许多这些变量所必需的东西必须具有引发异常的所有内容,我不认为您可以对类进行处理。

I was hoping someone could point me in the right direction with one of these solutions or possibly suggest another solution I have been unable to find. 我希望有人可以通过这些解决方案之一为我指明正确的方向,或者可能建议我找不到的另一个解决方案。

Something I forgot to mention is that besides the initial variables, each test method slightly varies in how their test method is written. 我忘记提及的是,除了初始变量外,每种测试方法的编写方式也略有不同。 Edit: If not for this I would have just pulled up the method into a superclass and been done with it. 编辑:如果不这样做,我将方法拉入一个超类并完成。

Edit: Here's the test method and the parts of the superclass I am using, 编辑:这是测试方法以及我正在使用的超类的各个部分,

// 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
    }
}

Why the field approach isn't so cool: you are introducing sequential coupling. 为什么现场方法不那么酷:您正在引入顺序耦合。 Whoever comes next won't readily know that method test will fail without calling method prepare. 紧随其后的人不会不知道方法测试如果不调用方法prepare就会失败。 Also if a class extend another or the structure changes you might end up calling prepare twice and having hard to trace errors 另外,如果一个类扩展了另一个类或结构发生了变化,那么您可能最终会调用两次prepare,并且很难跟踪错误

Pattern 1) move all variables into a state object 模式1)将所有变量移至状态对象

Group variables into a new object - not the superclass 将变量分组为新对象-不是超类

Create a builder object so the class that you can easily initialize what variable you need into this object 创建一个构建器对象,以便您可以轻松地在该对象中初始化所需变量的类

Change test method to accept this object and work from its data 更改测试方法以接受该对象并根据其数据进行工作

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);
   }
}

Pattern 2) inversion of control 模式2)控制反转

Create a class for your test method, make the variable parts field of this new class. 为您的测试方法创建一个类,使这个新类的变量部分成为字段。 Set up variables during this class constructor - add static getInstanceForXxxx methods and hardcode the magic values you need for each of these static getters - into each getInstanceForXxxx you create a new instance passing in whatever initializarion value client needs 在该类构造函数期间设置变量-添加静态getInstanceForXxxx方法并将这些静态getter中的每一个所需的魔术值硬编码-在每个getInstanceForXxxx中,您创建一个新实例,并传入客户端需要的任何初始化值

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();
   }
}

Pattern 3) encapsulate behaviour in strategy 模式3)将行为封装在策略中

Create a base class. 创建一个基类。 Each point of the duplicate code which is different, refactor in a private method. 重复代码的每个不同点都可以通过私有方法进行重构。 Create a class and override each method with the specialized code you need. 创建一个类,并使用所需的专用代码覆盖每个方法。 Instanciate the right class for each client and call the public test method 为每个客户实例化正确的类并调用公共测试方法

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();
   }
}

I like this last because it gets rid for a flag (flag1) and encapsulate properly behaviours (specific SomeClass test only has doA() call) 我喜欢这最后一个,因为它摆脱了标志(flag1)并正确封装了行为(特定的SomeClass测试仅具有doA()调用)

Defining the variables as fields is a good way, I think. 我认为将变量定义为字段是一种好方法。 But you should initialize them a little bit later. 但是您应该稍后再对其进行初始化。 Just use a constructor to init the variables, and there you can catch Exceptions! 只需使用构造函数来初始化变量,就可以捕获异常!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM