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:
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:
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:
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) :
Ich denke, dass <T extends Service, S extends T> void addService(S service, Class<T> clazz)
klingt, als ob es deine Kriterien erfüllt:
(Ich habe einige Statiken hinzugefügt und Car
aus Methodensignaturen entfernt, da ich keine Definition der zu kompilierenden Objekte habe)
Dies kann auch in Ordnung sein, je nachdem, wie Sie den Typ von service
verwenden:
Wenn service
ein Subtyp des Typs ist, der durch task
repräsentiert wird, kann er immer upcasted werden.
Das einzige Problem, das ich habe, sind die Varargs, die alle Array-Elemente vom selben Typ zwingen, und deshalb kann ich
nicht schreibenaddService(null, CarWash.class, CarRepair.class);
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.