Ich habe das Argument gehört, dass Sie die allgemeinste verfügbare Schnittstelle verwenden sollten, damit Sie nicht an eine bestimmte Implementierung dieser Schnittstelle gebunden sind. Gilt diese Logik für Schnittstellen wie java.util.Collection ?
Ich würde viel lieber Folgendes sehen:
List<Foo> getFoos()
oder
Set<Foo> getFoos()
Anstatt von
Collection<Foo> getFoos()
Im letzten Fall weiß ich nicht, um welche Art von Datensatz es sich handelt, während ich in den ersten beiden Fällen einige Annahmen über die Reihenfolge und Eindeutigkeit treffen kann. Hat java.util.Collection eine Nützlichkeit, die nicht darin besteht, ein logisches übergeordnetes Element für Mengen und Listen zu sein?
Wenn Sie bei einer Codeüberprüfung auf Code stoßen würden , der Collection verwendet, wie würden Sie feststellen, ob seine Verwendung gerechtfertigt ist, und welche Vorschläge würden Sie für den Ersatz durch eine spezifischere Schnittstelle machen?
Collection<List<?>>
? Sprechen Sie über Coding Horror!Antworten:
Abstraktionen leben länger als Implementierungen
Je abstrakter Ihr Design ist, desto länger bleibt es wahrscheinlich nützlich. Da Collection abstrakter ist als seine Unterschnittstellen, bleibt ein auf Collection basierendes API-Design mit größerer Wahrscheinlichkeit nützlich als ein auf List basierendes.
Das übergeordnete Prinzip besteht jedoch darin, die am besten geeignete Abstraktion zu verwenden . Wenn Ihre Sammlung geordnete Elemente unterstützen muss, müssen Sie eine Liste erstellen. Wenn keine Duplikate vorhanden sein sollen, müssen Sie einen Satz festlegen und so weiter.
Ein Hinweis zum generischen Interface-Design
Da Sie an der Verwendung der Collection-Oberfläche mit Generika interessiert sind, kann Folgendes hilfreich sein. Effektives Java von Joshua Bloch empfiehlt den folgenden Ansatz, wenn Sie eine Schnittstelle entwerfen, die auf Generika basiert: Producers Extend, Consumers Super
Dies wird auch als PECS-Regel bezeichnet . Wenn generische Sammlungen, die Daten erzeugen, an Ihre Klasse übergeben werden, sollte die Signatur im Wesentlichen folgendermaßen aussehen:
Somit kann der Eingabetyp E oder eine beliebige Unterklasse von E sein (E ist in der Java-Sprache sowohl als Super- als auch als Unterklasse von sich selbst definiert).
Umgekehrt sollte eine generische Sammlung, die zum Konsumieren von Daten übergeben wird, eine folgende Signatur haben:
Die Methode wird mit jeder Superklasse von E korrekt umgehen. Insgesamt wird Ihre Benutzeroberfläche durch die Verwendung dieses Ansatzes für Ihre Benutzer weniger überraschend, da Sie in der Lage sind, sie korrekt zu übergeben
Collection<Number>
undCollection<Integer>
behandeln zu lassen.quelle
Die
Collection
Benutzeroberfläche und die freizügigste FormCollection<?>
eignen sich hervorragend für Parameter , die Sie akzeptieren. Basierend auf der Verwendung in der Java-Bibliothek selbst ist dies als Parametertyp häufiger als als Rückgabetyp.Für Rückgabetypen denke ich, dass Ihr Punkt gültig ist: Wenn von Personen erwartet wird, dass sie darauf zugreifen, sollten sie die Reihenfolge (im Big-O-Sinne) der ausgeführten Operation kennen. Ich würde eine
Collection
zurückgegebene Datei durchlaufen und sie einer anderen Sammlung hinzufügen, aber es wäre ein bisschen verrückt, sie aufzurufencontains
, ohne zu wissen, ob es sich um eine O (1) -, O (log n) - oder O (n) -Operation handelt. Nur weil Sie ein habenSet
, heißt das natürlich nicht, dass es sich um ein Hashset oder ein sortiertes Set handelt, aber irgendwann werden Sie davon ausgehen, dass die Schnittstelle angemessen implementiert wurde (und dann müssen Sie zu Plan B gehen, wenn Sie davon ausgehen wird als falsch angezeigt).Wie Tom erwähnt, müssen Sie manchmal a zurückgeben
Collection
, um die Kapselung aufrechtzuerhalten: Sie möchten nicht, dass Implementierungsdetails herauskommen, selbst wenn Sie etwas Spezifischeres zurückgeben könnten. Oder, in dem von Tom erwähnten Fall, könnten Sie den spezifischeren Container zurückgeben, aber dann müssten Sie ihn konstruieren.quelle
Ich würde es aus dem völlig entgegengesetzten Blickwinkel betrachten und fragen:
Es ist ziemlich einfach, dies zu rechtfertigen. Sie verwenden die Liste, wenn Sie Funktionen benötigen, die von einer Sammlung nicht angeboten werden. Wenn Sie diese zusätzliche Funktionalität nicht benötigen - welche Rechtfertigung haben Sie? (Und ich werde nicht kaufen, "Ich würde es lieber sehen")
Es gibt viele Fälle, in denen Sie eine Sammlung für schreibgeschützte Zwecke verwenden, alles auf einmal füllen und vollständig durchlaufen - müssen Sie das Objekt jemals manuell indizieren?
Um ein echtes Beispiel zu geben. Angenommen, ich führe eine einfache Abfrage für eine Datenbank durch. (
SELECT id,name,rep FROM people WHERE name LIKE '%squared'
) Ich nehme die relevanten Daten zurück, fülle Personenobjekte aus und füge sie in eine Personenliste ein.)Welche Rechtfertigung hätte ich für diese zusätzlichen Methoden? (was in meiner PersonList sowieso nicht implementiert wäre)
quelle