J'ai entendu l'argument selon lequel vous devriez utiliser l'interface la plus générique disponible afin de ne pas être lié à une implémentation particulière de cette interface. Cette logique s'applique-t-elle aux interfaces telles que java.util.Collection ?
Je préfère de loin voir quelque chose comme ceci:
List<Foo> getFoos()
ou
Set<Foo> getFoos()
au lieu de
Collection<Foo> getFoos()
Dans le dernier cas, je ne sais pas à quel type d'ensemble de données je fais face, alors que dans les deux premiers cas, je peux faire des hypothèses sur l'ordre et l'unicité. Java.util.Collection a- t -il une utilité en dehors d'être un parent logique pour les ensembles et les listes?
Si vous rencontriez du code qui employait Collection lors d'une révision de code, comment détermineriez-vous si son utilisation est justifiée et quelles suggestions feriez-vous pour son remplacement par une interface plus spécifique?
Collection<List<?>>
? Parlez de coder l'horreur!Réponses:
Les abstractions vivent plus longtemps que les implémentations
En général, plus votre design est abstrait, plus il est susceptible de rester utile. Ainsi, puisque Collection est plus abstrait que ses sous-interfaces, une conception d'API basée sur Collection est plus susceptible de rester utile qu'une autre basée sur List.
Cependant, le principe général est d'utiliser l' abstraction la plus appropriée . Donc, si votre collection doit prendre en charge des éléments ordonnés, puis mandater une liste, s'il n'y a pas de doublons, alors mandater un ensemble, etc.
Une note sur la conception d'interface générique
Étant donné que vous êtes intéressé à utiliser l'interface Collection avec des génériques, vous pouvez être utile ci-dessous. Java efficace par Joshua Bloch recommande l'approche suivante lors de la conception d'une interface qui s'appuiera sur des génériques: Producers Extend, Consumers Super
Ceci est également connu comme la règle PECS . Essentiellement, si des collections génériques qui produisent des données sont transmises à votre classe, la signature devrait ressembler à ceci:
Ainsi, le type d'entrée peut être E ou n'importe quelle sous-classe de E (E est défini comme une super et une sous-classe de lui-même dans le langage Java).
Inversement, une collection générique transmise pour consommer des données doit avoir une signature comme celle-ci:
La méthode correctement face à toute superclasse de E. Dans l' ensemble, en utilisant cette approche fera l' interface moins surprenante à vos utilisateurs parce que vous serez en mesure de passer
Collection<Number>
etCollection<Integer>
et les ont traités correctement.la source
L'
Collection
interface, et la forme la plus permissiveCollection<?>
, est idéale pour les paramètres que vous acceptez. Basé sur l' utilisation dans la bibliothèque Java elle-même, il est plus courant comme type de paramètre que comme type de retour.Pour les types de retour, je pense que votre argument est valable: si les personnes sont censées y accéder, elles doivent connaître l'ordre (au sens Big-O) de l'opération en cours. Je voudrais itérer sur un
Collection
retour et l'ajouter à une autre collection, mais il semblerait un peu fou de l'appelercontains
, sans savoir s'il s'agit d'une opération O (1), O (log n) ou O (n). Bien sûr, ceSet
n'est pas parce que vous avez un hashset ou un ensemble trié, mais à un moment donné, vous supposerez que l'interface a été raisonnablement implémentée (et vous devrez ensuite aller au plan B si votre hypothèse s’avère incorrect).Comme Tom le mentionne, vous devez parfois retourner un
Collection
afin de maintenir l'encapsulation: vous ne voulez pas que les détails de l'implémentation fuient, même si vous pouvez retourner quelque chose de plus spécifique. Ou, dans le cas mentionné par Tom, vous pouvez retourner le conteneur plus spécifique, mais vous devrez alors le construire.la source
Je regarderais cela d'un point de vue complètement opposé et je demanderais:
C'est assez facile à justifier. Vous utilisez la liste lorsque vous avez besoin d'une fonctionnalité qui n'est pas offerte par une collection. Si vous n'avez pas besoin de cette fonctionnalité supplémentaire - quelle justification avez-vous? (Et je n'achèterai pas, "je préfère le voir")
Il existe de nombreux cas où vous utiliserez une collection à des fins de lecture seule, en la remplissant à la fois, en l'itérant entièrement - avez-vous besoin d'indexer la chose manuellement?
Pour donner un vrai exemple. Supposons que j'effectue une requête simple sur une base de données. (
SELECT id,name,rep FROM people WHERE name LIKE '%squared'
) Je récupère les données pertinentes, remplis les objets Person et les place dans une PersonList)Alors, quelle justification aurais-je pour ces méthodes supplémentaires? (qui serait de toute façon non implémenté dans ma PersonList)
la source