ich versuche mir gerade einen generische CRUD Service zu bauen, um mir den immer wieder kehrenden crud Code für die einzelnen Implementierungen zu sparen.
Funktioniert auch ganz gut, nur frage ich mich: kann ich irgendwie mit Generics auf eine (nicht bekannte) Methode wie getId() zugreifen?
In der Facade würde ich gerne nur ein delete(c) ausführen. Und mir die id dann innerhalb des Services angeln. Nur geht dort t.getId() verständlicherweise nicht.
Deshalb: gibt es eine Möglichkeit sowas zu implementieren, oder muss ich mit der Lösung leben das komplette Objekt und zusätzlich noch seine ID übergeben zu müssen?
Danke
Java:
publicclassBaseService<T>{@InjectEntityManager em;@Overridepublicvoiddelete(T t,Object id){Object ref =this.em.getReference(t.getClass(), id);//t.getId() geht hier leider nichtthis.em.remove(ref);}}
Du brauchst ein Interface mit der Funktion getId, welches deine Klassen implementieren. Dann kannst du durch "public class BaseService<T extends ObjektMitId>" auf die getId Funktion zugreifen.
Aber wenn ich zb [c]public class BaseService<T extends Customerinterface>[/c] schreibe, habe ich ja doch wieder x Klassen (bzw Interfaces) hinterher. Ich möchte das ja gerade alles auf nur eine DAO/Service reduzieren.
Sodass mir der simple Aufruf BaseService<Customer> reicht, um service-methoden für eine bestimmte Klasse ausführen zu können.
Ja das kannst du doch. Es ist nur einfach so, dass wenn du von deiner BaseService Klasse aus erwartest, dass die T Klasse eine Funktion getId bereitstellt, heisst das, dass deine BaseService Klasse auch nur mit Klassen funktioniert, die ein Interface implementieren welchens getId definiert, anders gehts (fast) nicht.
Es wäre noch möglich mit Reflection auf sämtliche auf Fields und Methoden einer Klasse zuzugreifen, vielleicht entspricht das eher deinen Erwartungen.
Aber wenn ich zb [c]public class BaseService<T extends Customerinterface>[/c] schreibe, habe ich ja doch wieder x Klassen (bzw Interfaces) hinterher. Ich möchte das ja gerade alles auf nur eine DAO/Service reduzieren.
Sodass mir der simple Aufruf BaseService<Customer> reicht, um service-methoden für eine bestimmte Klasse ausführen zu können.
es ist ein Unterschied ob es einen Verwender von X gibt oder mehrere Implementierungen von X. Wenn es nur eine Implementierung von X geben soll ist die Frage ob alles mit einer Klasse erledigt werden kann. Oder ob es eine Vaterklasse X gibt und dann nur noch - falls noetig abweichende Implementierungen und dein generischer Aufruf ist dann [c]T extends Vaterklasse[/c]. X muss ja nicht unbedingt ein Interface sein, geht ja auch eine (abstrakte) Klasse
Es gibt noch eine alternativ. Allerdings würde ich dir eher zu dem Raten, was bereits gesagt worden ist. (Also eine [abstrakte] Klasse oder ein Interface verwenden).
Java:
classUseMe{publicintgetId(){return42;}}publicclassSample{publicstaticvoidmain(finalString[] args){UseMe um=newUseMe();printId(um);}publicstaticvoidprintId(finalObject o){Class<?> oClass=o.getClass();try{Method m=oClass.getMethod("getId");System.out.println("Id: "+ m.invoke(o));}catch(Exception e){// Klasse kann eben nicht verwendet werden
e.printStackTrace();}}}
Aber wie bereits angesprochen: Wenn du möchtest, dass eine Klasse bestimmte Methoden implementiert, dann verwende ein Interface/eine (abstrakte)Klasse. Damit bist du gezwungen, die Methoden bereitzustellen. Bei der Lösung via Reflection ist dies nicht der Fall und ist imho Fehleranfälliger und Aufwändiger.
Ach klar, ich war irgendwie verwirrt. Das mit dem Interface leuchtet mir ein.
Jetzt habe ich quasi 3 Möglichkeiten:
a) Interface mit id in jeder Entity implementieren
b) abstrakte Klasse mit id extenden
c) @mappedsuperclass mit id extenden
Kann man generell sagen welche Variante die bessere ist? Oder ist das Geschmackssache?
Bei den Möglichkeiten mittels Vererbung wäre der Vorteil, dass ich das Id Feld nur 1x implementieren muss in der Superklasse. Was wiederum schön Codeduplikation einspart. Und jede Klasse bekommt ja sowieso eine Id.
Bei Tieren zB wäre extend einleuchtend: Dog extends Animal, Cat extends Animal.
Ich habe aber eher Beziehungen wie Customer, Person, Payment, Item usw vorliegen. Wäre es da trotzdem richtig von der selben Superklasse zu erben (um das DRY Prinzip einzuhalten)?
??? dann verstehe ich den Sinn dahinter allerdings nicht, wenn sowohl abstract class als auch Interface bloß für die ID zuständig sind...
[c]Customer extends AbstractClass implements Interface[/c]
??? dann verstehe ich den Sinn dahinter allerdings nicht, wenn sowohl abstract class als auch Interface bloß für die ID zuständig sind...
[c]Customer extends AbstractClass implements Interface[/c]
wenn wir wirklich NUR ueber eine getId Methode reden ist es natuerlich fraglich, vor allem wenn die Klassen, die das betrifft eine andere Vererbungslinie haben. Aber man nutzt ein Interface meist zum generellen Definieren von Funktionalitaet und die abstrakte Klasse als Art Templateimplementierung.