Les noms d'interface doivent-ils commencer par un préfixe «I»?

73

Je lisais " Clean Code " de Robert Martin pour devenir, je l' espère, un meilleur programmeur. Jusqu'à présent, rien de tout cela n'a été réellement novateur, mais cela m'a fait penser différemment à la façon dont je conçois des applications et écris du code.

Il y a une partie du livre avec laquelle je ne suis pas d'accord, mais qui n'a pas de sens pour moi, en particulier en ce qui concerne les conventions de dénomination des interfaces. Voici le texte, tiré directement du livre. J'ai mis en évidence l'aspect de ce qui me rend confus et j'aimerais des éclaircissements.

Je préfère laisser les interfaces sans fioritures. Le je précédent, si courant dans les héritages actuels, constitue au mieux une distraction et trop d'informations au pire. Je ne veux pas que mes utilisateurs sachent que je leur donne une interface .

C'est peut-être parce que je ne suis qu'un étudiant, ou peut-être parce que je n'ai jamais fait de programmation professionnelle ou en équipe, mais je voudrais que l'utilisateur sache qu'il s'agit d'une interface. Il y a une grande différence entre implémenter une interface et étendre une classe.

Donc, ma question se résume à: "Pourquoi devrions-nous cacher le fait qu'une partie du code attend une interface?"

Modifier

En réponse à une réponse:

Si votre type est une interface ou une classe, c'est votre affaire, pas celle de quelqu'un qui utilise votre code. Donc, vous ne devriez pas divulguer les détails de votre code dans ce code tiers.

Pourquoi ne devrais-je pas "divulguer" les détails de savoir si un type donné est une interface ou une classe en code tiers? N’est-il pas important que le développeur tiers qui utilise mon code sache s’il va implémenter une interface ou étendre une classe? Est-ce que les différences ne sont tout simplement pas aussi importantes que je les fais paraître dans mon esprit?

Charles Sprayberry
la source
3
Je suis d'accord avec votre point. Il y a un moment où trop de dissimulation d'informations n'est pas très utile. Cependant, même si vous suivez ces instructions, vous pourrez toujours identifier le type à l'aide de l'EDI ou d'un add-on.
NoChance
3
Cette question est essentiellement connue sous le nom de "notation hongroise". Vous devriez trouver de nombreux arguments et la raison pour laquelle la plupart des développeurs non-MS l'ont abandonnée sous ce mot-clé. La notation hongroise prévalait principalement pour les variables, mais est essentiellement la même pour les types.
thiton
2
Avant l'édition du titre était terrible. Cette question ne concerne pas la notation hongroise en général simplement parce qu'elle mentionne une convention qui pourrait lui être associée. Les mérites relatifs de HN sont totalement hors de propos ici; la question portait spécifiquement sur les interfaces contre les classes et sur le point de savoir si les différences sémantiques sont suffisamment importantes / suffisamment intéressantes pour justifier une convention de dénomination des cas spéciaux.
Aaronaught
Re to know whether they will be implementing an interface or extending a class: oui, mais la plupart des utilisateurs de votre code l'appelleront, ne l'implémenteront pas ou ne l'étendront pas, et ils ne se soucient vraiment pas de savoir lequel.
david.pfx
Pour ce que cela vaut, je préfère massivement le préfixe "I". J'utilise également un préfixe "Résumé" sur les classes abstraites pour la même raison. Cela ne fait pas de différence pour les utilisateurs de la classe / interface, mais peut faire une grande différence pour ceux qui ont besoin de fournir des instances de celle-ci, et le rend beaucoup plus simple pour les autres développeurs qui lisent votre code. Cela signifie qu'ils peuvent voir d'un coup d'œil ce qu'ils font, au lieu d'avoir à consulter l'EDI au cas par cas pour plus d'informations. Je viens juste de commencer à utiliser Angular et je trouve très ennuyeux de ne pas suivre cette convention!
Dan King

Réponses:

67

Si vous vous arrêtez pour y penser, vous verrez qu'une interface n'est pas très différente sémantiquement d'une classe abstraite:

  • Les deux ont des méthodes et / ou des propriétés (comportement);
  • Aucun des deux ne devrait avoir de champs non privés (données);
  • Aucune ne peut être instanciée directement;
  • Dériver de l'un signifie mettre en œuvre ses méthodes abstraites, à moins que le type dérivé ne soit également abstrait.

En fait, les distinctions les plus importantes entre les classes et les interfaces sont les suivantes:

  • Les interfaces ne peuvent pas avoir de données privées;
  • Les membres de l'interface ne peuvent pas avoir de modificateurs d'accès (tous les membres sont "publics");
  • Une classe peut implémenter plusieurs interfaces (par opposition à la possibilité généralement d'hériter d'une seule classe de base).

Etant donné que les seules distinctions particulièrement significatives entre les classes et les interfaces tournent autour de (a) données privées et (b) hiérarchie de types - aucune d’entre elles ne faisant la moindre différence pour un appelant - il n’est généralement pas nécessaire de savoir si un type est une interface ou une classe. Vous n'avez certainement pas besoin de l' indication visuelle .

Cependant, il faut tenir compte de certains cas. En particulier, si vous utilisez la réflexion, l’interception, les proxy / mixins dynamiques, le tissage de bytecodes, la génération de code ou tout ce qui implique de manipuler directement le système de dactylographie de l’environnement ou le code lui-même - il est alors très utile et parfois nécessaire de le savoir directement. bat si vous avez affaire à une interface ou une classe. Vous ne voulez manifestement pas que votre code échoue mystérieusement parce que vous avez essayé d'ajouter une classe plutôt qu'un interface en tant que mixin.

Toutefois, dans le cas d’un code de logique métier standard et standard, il n’est pas nécessaire d’annoncer les distinctions entre les classes abstraites et les interfaces, car elles ne seront jamais prises en compte.

Ceci dit, j’ai quand même tendance à préfixer mes interfaces C #, Icar c’est la convention .NET utilisée et préconisée par Microsoft. Et lorsque j'explique les conventions de codage à un nouveau développeur, il est beaucoup moins compliqué d'utiliser les règles de Microsoft que d'expliquer pourquoi nous avons nos propres règles "spéciales".

Aaronaught
la source
Merci pour cette ventilation. +1 pour "les distinctions significatives entre les classes et les interfaces ..."
Charles Sprayberry
24
+1 pour "Tout cela étant dit, j’ai quand même tendance à préfixer mes interfaces C #, car c’est la convention .NET utilisée et préconisée par Microsoft". C'est une raison suffisante pour moi en C #. En suivant cette norme commune, il est plus probable que d'autres programmeurs .NET identifient l'interface.
Robotsushi
4
En tant que personne qui écrit à la fois en Java et en C #, la déclaration "Tout cela étant dit, j’ai quand même tendance à préfixer mes interfaces en C # car c’est la convention .NET utilisée et préconisée par Microsoft" ne peut pas être sous-estimée - c’est l’une des choses que m'aide à me souvenir de la langue dans laquelle je travaille
Aidos
3
Une autre différence dans .NET (mais pas dans Java) est que de nombreux langages .NET n'autorisent pas les interfaces à contenir des méthodes statiques. Par conséquent, le piratage Id'une interface peut donner un bon nom à une classe pour contenir des méthodes statiques associées à l'interface (par exemple Enumerable<T>.Emptyou Comparer<T>.Default).
Supercat
J'ai une préoccupation. En C ++, si vous ouvrez un en-tête et voyez que celui-ci class Foos'étend déjà class Bar, il n'est pas immédiatement évident de savoir s'il class Barest étendu ou implémenté. Alors maintenant, vous devez regarder dans l’en- class Bartête pour décider s’il est acceptable de modifier class Foopour étendre class Baz. De plus, le préfixe I donne un indice visuel évident si la "classe de base unique" est violée ou non - vous obtenez ainsi un contrôle de cohérence à chaque fois que vous ouvrez un en-tête.
JSJ
14

À bien des égards, la cohérence est plus importante que la convention. Tant que vos schémas de nommage sont cohérents, ils ne seront pas difficiles à travailler. Préfixe les interfaces avec un I si vous préférez, ou laissez simplement le nom sans fioritures, cela ne m'importe pas tant que vous choisissez un style et vous y tenez!

Jim Nutt
la source
2
+1 pour la cohérence> convention. En C #, vous préfixez un I et en Java, vous ne le feriez pas. Des tâches différentes appellent des conventions différentes
Bringer128
2
+1 alors que je préfère personnellement ne pas avoir Is sur mes interfaces, le fait d'être incompatible avec les bibliothèques BCL et tierces utilisées dans les projets .Net n'est pas une option à mon humble avis.
jk.
13

Le livre est plein de bonnes choses, mais j'ajouterais quand même "I" au nom de l'interface.

Imaginez que vous ayez public interface ILogune implémentation par défaut public class Log.

Maintenant, si vous décidez de le faire public interface Log, vous devez tout à coup changer de classe de journal en public class LogDefaultou quelque chose du genre. Vous êtes passé d’un personnage supplémentaire à sept, ce qui est une perte de temps.

Il y a souvent une ligne de démarcation entre théorie et pratique. En théorie, c'est une très bonne idée, mais en pratique, ce n'est pas très bon.

CodeART
la source
Ceci est également mentionné dans la documentation
levininja
30
"Imaginez que vous ayez une interface publique ILog avec un journal de classe publique d'implémentation par défaut." - Vous avez alors un mauvais nom pour votre implémentation par défaut. Que fait Log-il? Se connecter à la console? Pour syslog? À nulle part? Ceux-ci devraient être appelés ConsoleLog, SyslogLoget NullLog, respectivement. Logn'est pas un bon nom pour une classe concrète, car ce n'est pas un nom concret.
Sebastian Redl
7
Personnellement, c’est exactement la raison pour laquelle je déteste voir ITheClassName, créez-vous simplement une interface sans raison, s’agit-il de bruit au-dessus de TheClassName. Si votre interface a une fonction, il devrait être possible de lui attribuer un meilleur nom que ITheClassName
Richard Tingle.
Le nom de la classe est utilisé une fois (pour instancier), le nom de l'interface est utilisé partout. Ajouter une lettre à l'interface pour enregistrer une lettre sur le nom de la classe est une fausse économie (de caractères).
sergut
@RichardTingle Mais je pense que l’usage courant y est simplement pour que cela MyClassait une variation mocassable , non? En d’autres termes, nous utilisons souvent des interfaces pour rendre les méthodes publiques réellement publiques d’une manière qui permette les tests. (Ne dites pas que c'est bon ou mauvais, mais comprendre que la motivation pour les interfaces est souvent simplement de faire en sorte que les classes qui sont des dépendances facilement moquables explique le mappage MyClassde 1 à 1. IMyClass)
ruffin
8

Il ne s’agit pas de mettre en oeuvre l’interface ou d’étendre une classe. Dans ces cas, vous savez quand même ce que vous faites.

Cependant, lorsqu'un code tiers (un autre module de l'application par exemple) manipule vos données, ce code ne doit pas vous inquiéter si vous présentez une interface ou une classe.

C'est tout le but de l'abstraction. Vous présentez à ce code tiers un objet d'un type donné. Ce type donné a une fonction membre que vous pouvez appeler. C'est assez.

Si votre type est une interface ou une classe, c'est votre affaire, pas celle de quelqu'un qui utilise votre code. Vous ne devriez donc pas divulguer les détails de votre code dans ce code tiers.

Par ailleurs, les interfaces et les classes sont des types de référence à la fin. Et c'est ce qui compte. C'est donc ce que votre convention de nommage doit souligner.

Deadalnix
la source
@Mat> Oui, c'était une erreur de ma part et je l'ai modifiée.
deadalnix
5

La plupart des réponses semblent supposer que le langage de programmation est Java ou C # où il existe un concept (ou mot clé) pour les interfaces / classes abstraites. Dans ces cas, dans un IDE décent, il est immédiatement visible avec quel type de classe on traite et l'écriture public interface IMyClassest une duplication inutile. C'est comme si vous n'écriviez pas public final FinalMyClass- imaginez de mettre chaque mot clé dans le nom de la classe.

Cependant, à mon avis, en C ++, la situation est un peu différente, car il faut plonger dans le fichier d’en-tête et voir si la classe dispose de méthodes virtuelles pour déterminer s’il s’agit d’une classe abstraite. Dans ce cas, je peux clairement voir un argument pour écrire class AbstractMyClass.

Donc, ma réponse serait: Cela dépend du langage de programmation.

Mise à jour 2016: 2 ans d'expérience de C ++ plus tard, je considérerais maintenant probablement comme une mauvaise pratique de préfixer les noms de classe Abstract, bien que je dirais qu'il existe probablement des bases de code si complexes que cela pourrait avoir un sens.

Ela782
la source
Êtes-vous sûr que cela répond à la question? Vous voudrez peut-être lire les autres réponses et clarifier certains de vos points.
david.pfx
C ++ a définitivement des interfaces, même s'il n'y a pas de mot clé pour cela. Comment appelez-vous une classe où chaque fonction membre est purement virtuelle et où il n'y a pas de variables membres?
@ david.pfx: Je pense avoir répondu précisément à la question "Les noms d'interface doivent-ils commencer par un préfixe« I »?": Cela dépend du langage de programmation. Si vous pensez que mon élaboration n'est pas assez claire, je suis heureuse de l'améliorer - quelles parties ne sont pas claires pour vous?
Ela782
2
@JohnGaughan: Bien sûr, il a des interfaces! Mais tout ce que je veux dire, c'est qu'il s'agit du mot clé. C ++ n'en a pas, il n'est donc pas visible pour l'EDI / utilisateur s'il traite avec une interface ou non. En Java, cependant, il est immédiatement visible.
Ela782
1
Lisez la réponse la mieux cotée et comparez la vôtre. Vous êtes nouveau dans SO, et c’est une occasion d’apprendre quels types de réponses attirent les votes. En l'état, le tien ne le fera pas. Avec plus de travail, plus d'explications, plus de valeur, ça pourrait bien l'être. Accrochez-vous!
david.pfx
4

Suivez les idiomes de la langue que vous utilisez.

Chaque langue a ses propres idiomes et directives de codage. Par exemple, en C #, il est idiomatique de préfixer les interfaces avec I. In Go, ce n’est pas le cas.

Pete
la source
+1 Suivez les idiomes de la langue que vous utilisez. De toute évidence, l'auteur du livre est un développeur Java. .NET / C #: ILog Java: Log Mais l’inconvénient: quand j’aime avoir une classe Log qui implémente l’interface ILog .... MyLog, LogDefault, LogBase, ...? Moche, n'est-ce pas? Plus moche, c'est: LogImpl ....: D
hfrmobile
0

Dans mon code (Java), j'ai tendance à avoir cette convention dans les API que j'expose aux appelants:

  • La fonctionnalité est fournie par des interfaces et jamais par des classes.
  • Les parties non fonctionnelles sont des classes.

Par non fonctionnel, j'entends des choses comme des structures de données pures (telles que des classes qui agissent comme des ponts vers la sérialisation XML ou l'ORM), des énumérations et des exceptions, qui ne peuvent pas toutes être des interfaces (vous pouvez le faire pour les classes de données pures , mais c’est beaucoup de travail pour très peu d’avantages car il n’ya rien que ces classes fassent sauf des données).

En termes de conventions de dénomination, les interfaces ont tendance à mapper sur des noms d'acteur (par exemple FooBarWatcher) ou des adjectifs (par exemple FooBarWatchable), et les classes de données pures et les énumérations sont mappées sur des noms non actifs (par exemple FooBarStatus); l'EDI peut guider le consommateur d'API sans conventions de dénomination particulières. Les exceptions suivent les conventions habituelles de Java ( FooBarException, FooBarError, FooBarFault) bien sûr.

Je vais aussi souvent mettre les interfaces dans leur propre paquet ou même dans leur propre bibliothèque, juste pour m'assurer que je ne suis pas tenté de casser mes propres règles. (Cela me permet également de gérer la construction lorsque je dérive le code à partir de sources externes telles que des documents WSDL.)

Donal Fellows
la source
De plus, je ne mets jamais de Ipréfixes sur les interfaces. Bien sûr que c'est une interface! C'est dans une API (ou SPI)!
Donal Fellows