2017-02-16 7 views
1

Ich habe meinen Code dies vereinfacht:Refactoring durch generische Methode übergeben

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

Da ich die gleiche Schleife bin mit (und da ich mehr als eine Klasse mit mehr als einem entsprechenden „Getter“ Verfahren und Validierungsmethode) Ich möchte es umgestalten. Ich versuchte dies:

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

Allerdings erhalte ich folgende Fehler:

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 

ich nur in der Funktionsdeklaration angeben Methoden mit dem richtigen Rückgabetyp zu akzeptieren? Wenn das so ist, wie? Ideen für andere Wege zum Refactor werden geschätzt.

EDITED Um es klar zu machen, ich fragte nicht, wie der Rückgabetyp der Methode widerspiegeln. Danke dir VGR für die Lösung.

+0

Mögliches Duplikat von [Wie finde ich den Rückgabetyp einer Methode in JAVA?] (Http://stackoverflow.com/questions/14730223/how-to-find-return-type-of-a-method-in -java) –

+0

@DmytroGrynets Was bedeutet es mit der OP-Frage? –

+0

Er konnte den Rückgabetyp der Methode innerhalb seiner Methode herausfinden und es überprüfen –

Antwort

2

nicht Reflexion anwenden.

Reflection ist langsamer, schwer für einen Entwickler (einschließlich Sie selbst) zu folgen, und kann nicht vom Compiler auf korrekte Argumente und Rückgabetyp überprüft werden.

Der richtige Weg, um das Äquivalent eines "Zeigers zu einer Methode" in Java zu erreichen, besteht darin, die verschiedenen Methodenaufrufe in eine gemeinsame Schnittstelle einzubinden.Ab Java 8, wie Markus Benko wies darauf hin, sollten Sie Lieferanten und Prädikate verwenden:

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

Wenn Sie eine ältere Version von Java verwenden, können Sie die gleiche Sache mit ein wenig mehr Arbeit tun:

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

Try this:

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

(auch Ausnahmen in der Signatur hinzugefügt und geändert getMehod-method in den Argumenten)

+1

Vermeiden Sie Reflexionen. Es ist keine gute Übung. Das Problem kann auf andere Weise gelöst werden. –

1

Vermeiden Sie Reflexion aus verschiedenen Gründen: loose von JVM-Optimierungen, Ihr Code kompiliert aber zur Laufzeit explodiert, ist der Code schwer zu debuggen.

Sie können versuchen, indem Sie eine Schnittstelle mit den Implementierungen für jeden zu validierenden Typ erstellen.

Etwas wie:

Schnittstelle:

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

Implementationen:

Eine Handler-Implementierung für die Eingabe String:

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

Eine Handler-Implementierung für die Eingabe 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; 
    } 
} 

Sie können alle „Handler“ hinzufügen und entfernen Sie wirklich schnell benötigen.

App das Beispiel auszuführen:

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

Was mit 'Boolean' anstelle von' boolean'? 'wait' kann von' InputHandler' entfernt werden und die 'private' Methoden' public' verlassen. Wahrscheinlich könnten die "get" - und "validate" -Methoden verschiedene Funktoren sein, obwohl das von der ursprünglichen Frage abweicht. (Ich bin kein Fan von Low-Bedeutungstypen wie 'BiPredicate'. Ich meine, eurgh.) –

Verwandte Themen