通过传递泛型方法进行重构

时间:2017-02-16 14:12:27

标签: java generics reflection refactoring

我已将代码简化为:

static private String waitForString(String expected, int attempts) {
  String actual = null;
   for (int i = 0; i < attempts; i++){
      actual = getString();
      if (validateString(actual, expected)) {
         return actual;
      }
   }
   return null;
}

static private int waitForInt(int expected, int attempts) {
   int actual = 0;
   for (int i = 0; i < attempts; i++){
      actual = getInt();
      if (validateInt(actual, expected)) {
         return actual;
      }
   }
   return 0;
}

由于我使用相同的循环(并且由于我有多个具有多个相应的&#34; getter&#34;方法和验证方法的类),我想重构它。我试过这个:

static <T> T helperMethod(Method getMethod, Method validator,T expected, int attempts) {
   T actual = null;
   for (int i = 0; i < attempts; i++){
      actual = method.invoke(null);
      if (validator.invoke(null, actual, expected)) {
         return actual;
      }
   }
   return null;
}

但是我遇到了以下错误:

actual = method.invoke(null);
error: incompatible types: Object cannot be converted to T 

validator.invoke(null, actual, expected)
error: incompatible types: Object cannot be converted to boolean 

我可以在函数声明中指定只接受具有正确返回类型的方法吗?如果是这样,怎么样? 其他重构方法的想法将不胜感激。

EDITED 为了说清楚,我没有问如何反映方法的返回类型。 谢谢VGR的解决方案。

3 个答案:

答案 0 :(得分:2)

不要使用反射。

对于开发人员(包括您自己)而言,反射速度较慢,难以遵循,并且编译器无法检查正确的参数和返回类型。

在Java中完成等效“指向方法的指针”的正确方法是将各种方法调用包装在一个公共接口中。从Java 8开始,正如Markus Benko指出的那样,你应该使用供应商和谓词:

static <T> T waitForValue(Supplier<T> getMethod, BiPredicate<T, T> validator, T expected, int attempts) {
   T actual = null;
   for (int i = 0; i < attempts; i++){
      actual = getMethod.get();
      if (validator.test(actual, expected)) {
         return actual;
      }
   }
   return null;
}

private static String waitForString(String expected, int attempts) {
    return waitForValue(ThisClass::getString, ThisClass::validateString, expected, attempts);
}

private static int waitForInt(int expected, int attempts) {
    return waitForValue(ThisClass::getInt, ThisClass::validateInt, expected, attempts);
}

如果你使用的是旧版本的Java,你可以做更多相同的工作:

private interface Getter<T> {
    T get();
}

private interface Validator<T> {
    boolean test(T actual, T expected);
}

static <T> T waitForValue(Getter<T> getMethod, Validator<T> validator, T expected, int attempts) {
   T actual = null;
   for (int i = 0; i < attempts; i++){
      actual = getMethod.get();
      if (validator.test(actual, expected)) {
         return actual;
      }
   }
   return null;
}

private static String waitForString(String expected, int attempts) {
    Getter<String> getter = new Getter<String>() {
        @Override
        public String get() {
            return getString();
        }
    };
    Validator<String> validator = new Validator<String>() {
        @Override
        public boolean test(String actual, String expected) {
            return validateString(actual, expected);
        }
    };
    return waitForValue(getter, validator, expected, attempts);
}

private static int waitForInt(int expected, int attempts) {
    Getter<Integer> getter = new Getter<Integer>() {
        @Override
        public Integer get() {
            return getInt();
        }
    };
    Validator<Integer> validator = new Validator<Integer>() {
        @Override
        public boolean test(Integer actual, Integer expected) {
            return validateInt(actual, expected);
        }
    };
    return waitForValue(getter, validator, expected, attempts);
}

答案 1 :(得分:1)

出于不同的原因避免使用反射:JVM优化松散,代码编译但在运行时爆炸,代码很难调试。

您可以尝试创建一个接口,其中包含您需要验证的每种类型的实现。

类似的东西:

<强>接口

public interface InputHandler<T> {
  Boolean wait(T expected);
}

<强>实现:

输入字符串的处理程序实现:

public class StringHandler implements InputHandler<String> {
    @Override
    public Boolean wait(String expected) {
        String actual = getString();
        return validateString(actual, expected);
    }

    private String getString() {
        // ...
        return null;
    }

    private boolean validateString(String actual, String expected) {
        // ...
        return false;
    }
}

输入Integer的处理程序实现:

public class IntegerHandler implements InputHandler<Integer> {
    @Override
    public Boolean wait(Integer expected) {
        Integer actual = getInt();
        return validateInt(actual, expected);
    }

    private boolean validateInt(Integer actual, Integer expected) {
        // ...
        return false;
    }

    private Integer getInt() {
        // ...
        return null;
    }
}

您可以添加和删除所有&#34;处理程序&#34;你需要非常快。

运行示例的应用

public class Test {

    public static void main(String[] args) {
        waitForValidInput(new StringHandler(), "a", 3);
        waitForValidInput(new IntegerHandler(), 5, 3);
    }

    static private <T> T waitForValidInput(InputHandler<T> validator, T expected, int attempts) {
        for (int i = 0; i < attempts; i++) {
            if(validator.wait(expected)) {
                return expected;
            }
        }
        return null;
    }

}

答案 2 :(得分:0)

试试这个:

static <T> T helperMethod(Method method, Method validator, T expected, int attempts) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException {
    T actual = null;
    for (int i = 0; i < attempts; i++) {
        actual = (T)method.invoke(null);
        if ((Boolean)validator.invoke(null, actual, expected)) {
            return actual;
        }
    }
    return null;
}

(还在签名中添加了例外,并在参数中将getMehod更改为method