Generics-Platzhalter mit "extends" und "super"

8

Ich arbeite an einem Projekt, bei dem Services zu einer Komponente hinzugefügt werden müssen. Die Klasse Service ist eine Schnittstelle ohne Methoden. Hier ist ein Beispiel, wie meine Dienste funktionieren:

%Vor%

Jetzt gibt es viele Implementierungen dieser Dienste. Eine einzelne Klasse kann mehrere Dienste implementieren, wie diese Garage-Klasse:

%Vor%

Wenn ich einen Service zu einer Komponente hinzufüge, möchte ich den Service nicht für alle Aufgaben verwenden müssen, sondern zum Beispiel die Garage nur zum Waschen von Autos ( CarWash ) verwenden, aber nicht zum Reparieren von ihnen ( CarRepair ). Daher spezifiziere ich die Aufgaben als Klassen, genau so:

%Vor%

Um zu überprüfen, ob der Dienst die Aufgabe tatsächlich ausführen kann, habe ich Generika verwendet:

%Vor%

Dies funktioniert gut, überprüft jedoch nicht, ob die bereitgestellte Aufgabe tatsächlich eine Aufgabe ist (eine Klasse, die Service implementiert), also würde dies funktionieren:

%Vor%

Ich suche nach einer Möglichkeit, anzugeben, dass service die task implementieren und erweitern muss. Die task erweitert die Service -Schnittstelle, wie diese (kompiliert nicht) :

%Vor%     
Frithjof 04.04.2015, 21:23
quelle

2 Antworten

7

Ich denke, dass <T extends Service, S extends T> void addService(S service, Class<T> clazz) klingt, als ob es deine Kriterien erfüllt:

%Vor%

(Ich habe einige Statiken hinzugefügt und Car aus Methodensignaturen entfernt, da ich keine Definition der zu kompilierenden Objekte habe)

    
Andy Turner 04.04.2015, 21:46
quelle
1

Dies kann auch in Ordnung sein, je nachdem, wie Sie den Typ von service verwenden:

%Vor%

Wenn service ein Subtyp des Typs ist, der durch task repräsentiert wird, kann er immer upcasted werden.

%Vor%
  

Das einzige Problem, das ich habe, sind die Varargs, die alle Array-Elemente vom selben Typ zwingen, und deshalb kann ich addService(null, CarWash.class, CarRepair.class);

nicht schreiben

Dies ist tatsächlich ein schwieriges Problem für Java-Generika. (C ++ kann dies mit variadischen Vorlagen tun, was Java sehr unwahrscheinlich macht.)

Eine Möglichkeit, die Sie in Java lösen können, ist die Laufzeitvalidierung, z. B .:

%Vor%

(Oder verwenden Sie Class<? extends Service> und überprüfen Sie task.isInstance(service) .)

Aber ich weiß, dass wir das nicht wirklich mögen. ; )

Java hat einen sogenannten Schnitttyp (wenn wir einen Typ <? extends T & U> haben, wird der T & U -Teil als Schnitttyp bezeichnet), aber ein Schnittpunkttyp kann super und extends nicht kombinieren und sie sind ansonsten ziemlich eingeschränkt in dem, was sie sonst noch tun können.

    
Radiodef 05.04.2015 19:15
quelle

Tags und Links