2017-02-16 94 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」等低含義類型,我的意思是歐元。) –