Erweitern einer Klasse mit Generics

WeirdAl

Bekanntes Mitglied
Hallo zusammen,
ich habe folgendes Problem:
Ich habe eine Menge von Klassen die alle A extenden (... extends A). In A habe ich eine Methode check(String param) die in den Kind-Klassen unverändert verwendet wird.
Für meine Testfälle will ich jetzt die Methode check aus A überschreiben und eine Klasse mit der Stub-Methode check(String param) erstellen. Ich möchte dies über Generics lösen, da ich dann nicht X Klassen zu den X Kind-Klassen von A dazu brauche (sondern nur eine).

Mein Problem ist, wenn ich die Klasse mit "public class X <T extends A>" erstelle dann kann ich jedoch nicht auf die Methode check zugreifen. Sollte dies das nicht normalerweise können? Habt ihr eine Idee oder einen Link wie ich das effektiv lösen könnte?

Cu
Alex
 
Hmnee... wenn ich das jetzt richtig verstanden habe, sollte das ja auf sowas rauslaufen wie
Code:
class A { void check(){} }
class B { void check(){} } // Überschreibt check

// Sowas geht dann nicht
class First [b]extends <T extends A>[/b] { } // Kann von A oder von B (extends A) erben

Wär' eigentlich ganz interessant :reflect: (In C++ geht das... Dass es in Java nicht geht ist ein Zeichen dafür, dass es da das Typsystem irgendwie übel raushauen würde, aber das müßte man mal näher nachvollziehen).

Abhilfe wäre erstmal, den Inhalt der check-Methode von einem "Checker"-Objekt 😎 ausführen zu lassen, und für den Testfall dann eben dort einen "TestChecker" reinzupacken, der die spezielle, für den Testfall benötigte Aktion durchführt, aber man müßte sich genau überlegen, wie man das machen könnte, damit man nicht NUR für den Test die API irgendwie umbiegt. Vielleicht gibt's auch eine Elegantere Lösung. (Wieder einmal: Komposition ist oft besser als Vererbung...)
 
Mein Problem ist, wenn ich die Klasse mit "public class X <T extends A>" erstelle dann kann ich jedoch nicht auf die Methode check zugreifen. Sollte dies das nicht normalerweise können?

Ich glaube hier liegt ein Verständnisproblem vor: Wenn du z.B. List<String> schreibst, kannst du nicht plötzlich in List auf Methoden von String zugreifen. Anders ausgedrückt: Generics sind keine Form der Vererbung und können dir bei deinem Problem (so wie ich es verstanden habe) deshalb nicht weiterhelfen.

Wenn du die Klassen nicht doppelt haben willst, muss sich die Methode check selbst unterschiedlich verhalten. Dafür gibt es mehrere Möglichkeiten. Am unschönsten wäre ein Debug-Schalter:

Java:
class A {
   public static boolean DEBUG = false;

   public void check(String param) {
       if(DEBUG) {
           System.out.println("debugging!"); 
       } else {
           doTheRealThing();
       } 
   }
}

Eine andere Variante wäre Komposition: Die check-Methode in A delegiert an ein "Checker-Objekt". Das kann entweder an A übergeben werden, oder eleganter mit Dependency Injection oder einem SPI ServiceLoader gesetzt werden:

Java:
interface Checker {
   void check(String param);
}

class A {
   public static Checker checker = null; //muss von "außen" gesetzt werden, evtl. per DI oder SPI

   public void check(String param) {
       checker.check(param);
   }
}

Andere Lösungswege wären AOP oder ein Proxy. Oder man verwendet eine Sprache, deren Typsystem sowas ausdrücken kann (*hüstl* Signatur *hüstl*)
 
Hi,
ja, sowas in der Art hatte ich vor. Ich bin grad dabei mir Gedanken zu machen wie es elegant anders zu lösen ist. Danke für die schnellen Antworten 🙂
 
Java:
interface Checker {
   void check(String param);
}

class A {
   public static Checker checker = null; //muss von "außen" gesetzt werden, evtl. per DI oder SPI

   public void check(String param) {
       checker.check(param);
   }
}
ich hoffe mal dieses [c]public static[/c] ist n Fehler....
 
Nicht das Gelbe vom Ei, ich weiß, aber alles was hier bisher vorgeschlagen wurde ist mehr oder weniger eine Krücke. Da ich z.Z. auf dem Guice-Trip bin, hier die DI-Variante:

Java:
interface Checker {
   void check(String param);
}
 
//Braucht Google Guice
class A {
   private Checker checker;
    
   @Inject
   class A(Checker checker) {
       this.checker = checker;
   }

   public void check(String param) {
       checker.check(param);
   }
}
 
es wäre nur unsinnig von DI zu reden und dann die Variable die injected werden soll als public static zu definieren...
 
Ich habe von DI als eine von mehreren Möglichkeiten gesprochen. Eine andere Variante wäre halt, die Variable einfach "von außen" zu setzen. Wie gesagt nicht schön, aber auch eine Variante. Dass man injizierte Variablen normalerweise nicht public macht, weiß ich auch - siehe mein Guice-Beispiel.

Ich habe übrigens gelernt, "häßliche" Lösungen nicht sofort zu verwerfen, manchmal kann sich daraus noch etwas vernünftiges entwickeln. Voraussetzung dafür ist natürlich, dass man weiß, was "häßlich" ist, und wo jeweils die Probleme liegen.
 

Zurück
Oben