Default vs Impl lors de l'implémentation d'interfaces en Java


34

Après avoir lu Les noms de paquets doivent-ils être singuliers ou au pluriel? Il m'est apparu que je n'avais jamais vu un vrai débat couvrir l'un de mes bêtes noires: nommer les implémentations d'interfaces.

Supposons que vous ayez une interface Orderdestinée à être implémentée de différentes manières, mais que l'implémentation initiale n'existe que lorsque le projet est créé. Allez-vous pour DefaultOrderou OrderImplou une autre variante pour éviter la fausse dichotomie? Et que faites-vous lorsque plusieurs implémentations arrivent?

Et le plus important ... pourquoi?

Réponses:


59

Les noms ont la possibilité de donner un sens. Pourquoi voudriez-vous jeter cette opportunité avec Impl?

Tout d’abord, si vous n’avez qu’une seule implémentation, supprimez l’interface. Cela crée ce problème de nommage et n’ajoute rien. Pire encore, des signatures de méthode incohérentes dans les API pourraient poser problème si vous et tous les autres développeurs ne faites pas attention à toujours utiliser uniquement l'interface.

Compte tenu de cela, nous pouvons supposer que chaque interface a ou peut avoir deux implémentations ou plus.

  • Si vous n'en avez qu'un pour le moment et que vous ne savez pas en quoi l'autre peut être différent, Default est un bon début.

  • Si vous en avez deux à présent, nommez-les chacun en fonction de son objectif.

    Exemple: Nous avons récemment eu une classe concrète Context (en référence à une base de données). On s'est rendu compte qu'il fallait pouvoir représenter un contexte hors ligne. Le nom Context a donc été utilisé pour une nouvelle interface (afin de préserver la compatibilité des anciennes API) et une nouvelle implémentation a été créée, OfflineContext . Mais devinez quoi l'original a été renommé? C'est vrai, ContextImpl ( beurk ).

    Dans ce cas, DefaultContext serait probablement correct et les gens l’obtiendraient, mais ce n’est pas aussi descriptif qu’il pourrait l’être. Après tout, si ce n'est pas hors ligne , qu'est-ce que c'est? Nous sommes donc allés avec: OnlineContext .


Cas particulier: utilisation du préfixe "I" sur les interfaces

Une des autres réponses suggéra d'utiliser le préfixe I sur les interfaces. De préférence, vous n'avez pas besoin de faire cela.

Toutefois, si vous avez besoin d'une interface pour les implémentations personnalisées, mais que vous avez également une implémentation concrète principale qui sera utilisée souvent, et que le nom de base qui lui est attribué est trop simple pour être abandonné à une seule interface, vous pouvez envisager d'ajouter "Je" à l'interface (cependant, c'est tout à fait bien si ça ne vous convient pas, à vous et à votre équipe).

Exemple: De nombreux objets peuvent être un "EventDispatcher". Pour les API, cela doit être conforme à une interface. Mais vous souhaitez également fournir un répartiteur d'événements de base pour la délégation. DefaultEventDispatcher conviendrait, mais il est un peu long et si vous voyez souvent son nom, vous préférerez peut- être utiliser le nom de base EventDispatcher pour la classe concrète et implémenter IEventDispatcher pour les implémentations personnalisées:

/* Option 1, traditional verbose naming: */
interface EventDispatcher { /* interface for all event dispatchers */ }
class DefaultEventDispatcher implements EventDispatcher {
  /* default event dispatcher */
}

/* Option 2, "I" abbreviation because "EventDispatcher" will be a common default: */
interface IEventDispatcher { /* interface for all event dispatchers */ }
class EventDispatcher implements IEventDispatcher {
  /* default event dispatcher. */
}

3
+1 pour une réponse solide. Comme le raisonnement derrière ne pas utiliser Impl.
Gary Rowe

2
+1 absolument d'accord. Nommer une interface en dehors du concept de domaine qu’elle représente n’a pas sa place.
Rupjones

9
"Si vous n’avez qu’une seule implémentation", comment savoir à l’avance que vous n’aurez qu’une implémentation? "chaque interface a ou peut avoir deux implémentations ou plus" ... avant d'avoir deux implémentations, vous n'en avez aucune, vous en avez une, puis vous en avez deux, je veux dire qu'il peut y avoir un moment où vous n'avez qu'une implémentation, juste avant de mettre en œuvre le second.
Tulains Córdova

2
@ NickC Je ne suis pas pédantinc sur la sémantique (je suis un poète et je ne le savais même pas). L'anglais n'est pas ma langue maternelle, je ne peux donc pas en être pédant. Je parlais de logique erronée. Vous utilisez des interfaces pour le découplage. Cela ne nécessite pas un certain nombre d'implémentations.
Tulains Córdova

4
if you will only ever have one implementation, do away with the interface- sauf si vous souhaitez tester le composant, auquel cas vous pouvez conserver cette interface afin de créer MockOrder, OrderStub ou similaire.
JBRWilkinson

15

Je décide de la dénomination par le cas d'utilisation de l'interface.

Si l'interface est utilisée pour le découplage , je choisis Implpour les implémentations.

Si le but de l'interface est l'abstraction comportementale , les implémentations sont nommées en fonction de ce qu'elles font concrètement. J'y ajoute souvent le nom de l'interface. Donc, si l'interface est appelée Validator, je l'utilise FooValidator.

Je trouve que Defaultc'est un très mauvais choix. D'abord, il pollue les fonctionnalités de complétion de code, car les noms commencent toujours par. L'autre chose est qu'un défaut est sujet à changement avec le temps. Ainsi, ce qui pourrait être un défaut par défaut peut être une fonctionnalité obsolète. Donc, soit vous commencez toujours à renommer vos classes dès que les valeurs par défaut changent ou vous vivez avec des noms trompeurs.


8

Je suis d' accord avec la réponse de Nicole ( en particulier que l'interface est probablement pas nécessaire dans la plupart des cas), mais pour le bien de la discussion , je vais jeter à une autre alternative supplémentaire que OrderImplet DefaultOrder: cacher la mise en œuvre derrière une méthode de fabrication statique comme Orders.create(). Par exemple:

public final class Orders {
  public static Order create() {
    return new Order() {
      // Implementation goes here.
    };
  }
}

Avec cette approche, l'implémentation peut être une classe interne anonyme, ou une classe privée avec Defaultou Impldans le nom, ou encore nommée autrement. Quel que soit le choix qui est fait, l’appelant n’a pas besoin de s’inquiéter, vous bénéficiez donc d’une plus grande flexibilité maintenant et plus tard, lorsque vous décidez de le modifier.

Les classes d’utilitaires java.util.Collectionset java.util.concurrent.Executorsdont les méthodes renvoient des implémentations masquées sont d’excellents exemples de ce modèle en pratique . Comme le mentionne Effective Java (élément 1), ce modèle peut aider à réduire le "poids conceptuel" de l’API.


+1 pour un cas supplémentaire intéressant: les implémentations anonymes.
Gary Rowe

1
Également utilisé en goyave .
Nicole

3

Je vais toujours pour OrderImplsimplement parce que cela apparaît par ordre alphabétique juste après l' Orderinterface.


2
Et comment gérez-vous les autres implémentations en cours, pour des manipulations spéciales, etc.?
Gary Rowe

1
Vous avez posé des questions sur la mise en œuvre initiale. Une fois que vous commencez à mettre en œuvre DomesticOrder, ForeignOrder ou autre, ils sont nommés de manière plus réfléchie et sans égard à leur position dans l'alphabet.
Ben Hoffstein

Très bien, j'ai modifié la question initiale pour refléter cette nouvelle exigence.
Gary Rowe

Pas une bonne idée S'il y aura plus d'une implémentation.
Sadegh

0

Vous pouvez nommer l'interface avec le préfixe I (IW Whatever) et ensuite faire la mise en œuvre.

Les conventions officielles du code Java ne parlent pas de ce type de nommage pour les interfaces, mais ce type de nommage facilite la reconnaissance et la navigation.


Pourquoi préfixeriez-vous l'interface avec un I? Est-ce pour aider à la reconnaissance en navigation?
Gary Rowe

@Gary: préfixer les types d'interface avec I est une convention bien établie dans le langage Delphi. Dans Delphi, les types de classe portent le préfixe T. Nous aurions donc une interface IOrder et une implémentation par défaut de TOrder avec TSomethingOrder et TBullMarketOrder comme implémentations spécifiques.
Marjan Venema

3
J'ai également constaté que cette convention était largement utilisée dans le développement .NET. Peut-être parce que la documentation et les exemples de Microsoft l'utilisent.
Ben Hoffstein

5
Il semble que @Renesis ait mis au point un cas utile pour l’utiliser en Java. Personnellement, je me fie à l'IDE pour me dire la différence, sinon nous aurions des E pour Enums, des C pour les cours et tous largement redondants.
Gary Rowe

0

Je pense que bien que Default puisse avoir un sens dans certains cas, il serait plus utile de décrire la mise en œuvre. Donc , si votre interface est UserProfileDAOalors vos implémentations peuvent être UserProfileSQLDAOou UserProfileLDAPDAOquelque chose comme ça.


0

si possible, nommez-le après quoi / comment il fait sa chose.

En général, la pire approche consiste à le nommer en fonction de son utilisation.

Si elle est supposée être utilisée comme classe de base pour la mise en oeuvre, vous pouvez utiliser BaseX ou AbstractX (si elle est abstraite (mais essayez de presser ce qu'elle fait, car si vous ne faites rien, vous ne la créeriez pas, vous avez déjà Si elle fournit les fonctionnalités les plus simples possibles et qu’elle est censée être utilisée directement (sans l’étendre) lorsque cette fonctionnalité suffit, vous pouvez l’appeler SimpleX ou BasicX.

S'il est utilisé sauf si une autre implémentation est fournie, nommez-le DefaultX


-2

La plupart de ces réponses décrivent ce qui est fait mais pas pourquoi.

Qu'est-il arrivé aux principes OO? Qu'est-ce que Impl me dit à propos d'un cours et comment l'utiliser? Vous devriez être préoccupé par la compréhension des usages et non de la façon dont il est construit.

Si je crée une interface Person, qu'est-ce qu'un PersonImpl? Sans signification. Au moins, DefaultPerson me dit que celui qui l'a codé n'aurait pas dû créer une interface.

Les interfaces typent pour le polymorphisme et doivent être utilisées telles quelles.


1
La réponse acceptée de @NickC décrit en détail ce qui est fait et pourquoi.
Gary Rowe
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.