2017-02-16 79 views
1

我简化了我的代码如下:重构通过传递泛型方法

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

由于我使用的是同一回路(因为我有不止一个相应的“吸气剂”的方法不止一个类和验证方法)我想重构它。我尝试这样做:

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的解决方案。

+0

可能重复的[如何在JAVA中找到返回类型的方法?](http://stackoverflow.com/questions/14730223/how-to-find-return-type-of-a-method-in -java) –

+0

@DmytroGrynets这与OP问题意味着什么? –

+0

他可以在他的方法中找到方法的返回类型并检查它 –

回答

2

不要使用反射。

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

在Java中完成“指向方法的指针”的正确方法是将各种方法调用包装在通用接口中。从Java 8中,作为本克马库斯指出,你应该使用供应商和谓词:如果您使用的是Java的旧版本

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

,你可以做同样的事情多一点的工作:

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

(在签名中还增加了异常,并在参数改变getMehodmethod

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

的输入整数的处理程序实现:

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

您可以添加和删除所有的“处理程序”,你需要非常快。

应用程序运行示例:

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

} 
+0

用布尔代替布尔代数是什么? 'wait'可以从'InputHandler'中移除,而'private'方法'public'。可能'get'和'validate'方法可能是不同的函子,尽管这与原来的问题不同。 (我不喜欢“BiPredicate”等低含义类型,我的意思是欧元。) –