Der Gebrauch von generics (Ich suche ein exklusives Anwendungsbeispiel)

Meine Frage ist eigentlich ganz einfach: Wo (also bei welchen Anwendungsbeispielen), außer wenn man mehrere „gleichartige“ Objekte zusammenfassen möchte (kollektieren), braucht man die Deklaration generischer Typen, in einer Klasse?

In welchen Struktur- oder Erzeugermustern (GoF?) kommen generics zum Einsatz?

Kann Polymorphie durch generics ersetzt werden?

Nein. Im Gegenteil setzen Generics ja gerade auf Vererbung und damit Polymorphie.

Factory wäre ein Beispiel, wo man das anwenden kann. Generics ersparen hier uU. das etwas komplexere AbstractFactory Muster anzuwenden.

bye
TT

Das hab ich mir auch schon gedacht…

Kannst du Factory und Abstract Factory einmal gegenüberstellen (key differences)? Vielleicht ist das genau, was ich gerade suche.

Ich nochmal!

https://stackoverflow.com/a/50786084

The main difference between Abstract Factory and Factory Method is that Abstract Factory is implemented by Composition; but Factory Method is implemented by Inheritance.

Yes, you read that correctly: the main difference between these two patterns is the old composition vs inheritance debate.

Also composition over inheritance-Debatte… Aber das Problem, das ich hier seh, ist doch, dass ich auch bei Composition nicht zwingend generics brauche. :confused:

Generics braucht man z.B. für das Curiously recurring template pattern - Wikipedia , mit dem man Self-Typen „simulieren“ kann (z.B. in der Enum-Klasse, von der alle enums ableiten).

Weiterhin sind Generics notwendig, um viele funktionale Konzepte umzusetzen, (wie etwa Lambdas, basierend auf Function, Supplier, Consumer, Laziness mit Supplier, Asynchronität mit Future u.ä.).

Ein Beispiel, was dir sicher schon über den Weg gelaufen ist, sind Vergleiche (Comparable, Comparator).

Ich bezog mich aber auf Java. :confused:

Deine genannten Beispiele beziehen sich leider alle mehr oder weniger auf das Kollektieren gleichartiger Elemente, bzw., auf die Bereitstellung oder die Bearbeitung ebenjener.

Machen wir es vielleicht etwas konkreter, sagen wir, ich habe zwei unterschiedliche Elemente/Klassen, aber mit gleicher Basisklasse. Jede Klasse kann jetzt nochmal zwei unterschiedliche Ausprägungen haben. Also gäbe es 7 Klassen bzw. Interface. Wobei könnte man hierbei generics/ generische Klassentypen einsetzen?

Die Enum-Klasse ist Java. Nur weil Wikipedia es nicht erwähnt, heißt das nicht, dass es in Java nicht funktioniert: Enum (Java SE 11 & JDK 11 )

Nein, tun sie nicht. Ich „kollektiere“ keine Elemente, wenn ich sie vergleiche, oder lazy erzeuge, oder asynchron verarbeite.

Man könnte z.B. in der Basisklasse oder dem Basisinterface das CTRP verwenden. Beispiel wäre eine bessere Implementierung einer Number-Hierarchie als sie Java bietet:

interface Num<N extends Num<N>> {
   N add(N that);
}

public class Int implements Num<Int> {
  public Int add(Int that) {
     // Code zum Addieren
  }
}

Oder du hast eine Abhängigkeit deiner Hierarchie zu einer anderen, etwa verschiedene Gruppen von Items, die auf verschiedenen Wegen quantifiziert werden (Stück, Laufende Meter, Gewicht, Fläche, Volumen)

public class Item<Q extends Quantity> {
  protected String name;
  protected Q quantity;
}

public class Meat extends Item<Weight> {
   ...
}

public class GroundBeef extends Meat {
  ...
}

public class Carpet extends Item<Area> {
   ...
}

public class WoolCarpet extends Carpet {
  ...
}

Das alles hat nichts, aber auch gar nichts mit „kollektieren“ zu tun. Hast du immer noch nicht verstanden, was Generics eigentlich sind? Generics sind einfach ein Weg, bestimmte gemeinsame Eigenschaften von Klassen zusammenzufassen, und damit zu vermeiden, Code mehrfach schreiben zu müssen. Überall wo ein Generic steht, kannst du auch immer stattdessen entweder die einzelnen Ausprägungen hinschreiben (aber dann kannst dann nicht mehr abstrakt über die ganze Gruppe von Typen sprechen) oder du verwendest Object oder einen anderen „kleinsten gemeinsamen Nenner“ statt des exakten generischen Typs (nur dann verlierst du Typsicherheit).

Funktionale Sprachen nennen Generics übrigens „Typkonstruktoren“, und das ist ein guter Art, sie zu verstehen: List oder Supplier sind an sich keine Typen, sie brauchen ein Argument (das selbst ein Typ ist), um einen konkreten, instantiierbaren Typen zu konstruieren, etwa List<String> oder Supplier<LocalDate>. Das besondere ist, dass man bereits für den Typkonstruktor definiert, wie sich die einzelnen Instanziierungen verhalten, und so darüber abstrahieren kann (wie eine Klasse gemeinsames Verhalten trotz unterschiedlicher Konstruktorargumente ihrer Instanzen definiert).

Auf dem (externen) technischen Level habe ich sie denke ich verstanden(x), aber ich such immer noch nach mir noch nicht bekannten Anwendungsbeispielen, um ihren Zweck besser zu verstehen. :wink:

Danke erst mal für das Number -Hierarchie Beispiel (und die Erklärung), das ist erst mal eine Anregung.

(x) Generics bieten eine „zusätzliche“ Typsicherheit. Zur Laufzeit werden allerdings alle generischen Informationen entfernt. (Ganz grob umschrieben). Daher beißt sich, imo, die Erstellung generischer Arrays auch ein bisschen, weil die Runtime bei Arrays genaue Typinformationen benötigt?