Quelle que soit la définition d'une classe, j'ai vu les définitions de méthodes ordonnées de différentes manières: alphabétique, chronologique selon l'usage le plus courant, alphabétique groupé par visibilité, alphabétique avec les getters et les setters regroupés, etc. Lorsque je commence à écrire une nouvelle classe, J'ai tendance à taper simplement tout, puis à réordonner quand j'ai fini d'écrire toute la classe. Sur cette note, j'ai trois questions:
- L'ordre est-il important?
- Y a-t-il un "meilleur" ordre?
- J'imagine que non, alors quels sont les avantages et les inconvénients des différentes stratégies de classement?
code-quality
Johntron
la source
la source
Réponses:
Dans certains langages de programmation, l'ordre est important, car vous ne pouvez pas utiliser des éléments tant qu'ils ne sont pas déclarés. Mais à part cela, pour la plupart des langues, cela n’a aucune importance pour le compilateur. Donc, il ne vous reste plus qu'à importer pour les humains.
Ma citation préférée de Martin Fowler est la suivante:
Any fool can write code that a computer can understand. Good programmers write code that humans can understand.
Je dirais donc que l'ordre de votre classe devrait dépendre de ce qui le rend facile à comprendre pour les humains.Personnellement, je préfère le traitement réducteur que Bob Martin donne dans son
Clean Code
livre. Variables membres en haut de la classe, puis constructeurs, puis toutes les autres méthodes. Et vous ordonnez que les méthodes soient proches de la manière dont elles sont utilisées au sein de la classe (plutôt que de placer arbitrairement tous les éléments publics puis privés puis protégés). Il appelle cela minimiser la "distance verticale" ou quelque chose du genre (ne pas avoir le livre sur moi pour le moment).Modifier:
L'idée de base de la "distance verticale" est que vous voulez éviter de faire sauter tout le monde autour de votre code source simplement pour le comprendre. Si les choses sont liées, elles devraient être plus proches les unes des autres. Les choses sans rapport peuvent être plus éloignées.
Le chapitre 5 de Clean Code (great book, btw) décrit en détail la façon dont M. Martin suggère de commander du code. Il suggère que la lecture du code fonctionne un peu comme si vous lisiez un article de journal: les détails de haut niveau sont prioritaires (en haut) et vous obtenez plus de détails lorsque vous lisez. Il dit: "Si une fonction en appelle une autre, elle devrait être rapprochée verticalement et l'appelant devrait être au-dessus de l'appelé, si possible." De plus, les concepts connexes doivent être proches les uns des autres.
Voici donc un exemple artificiel qui est mauvais à bien des égards (conception OO médiocre; ne jamais utiliser
double
pour de l'argent) mais illustre bien l'idée:Les méthodes sont ordonnées de manière à être proches de celles qui les appellent, en descendant du haut. Si nous avions placé toutes les
private
méthodes souspublic
celles-ci, il vous faudrait faire plus de sauts pour suivre le déroulement du programme.getFirstName
etgetLastName
sont conceptuellement liés (etgetEmployeeId
probablement aussi), ils sont donc proches les uns des autres. Nous pourrions tous les déplacer vers le bas, mais nous ne voudrions pas voirgetFirstName
en haut etgetLastName
en bas.J'espère que cela vous donne l'idée de base. Si ce genre de chose vous intéresse, je vous recommande fortement de lire
Clean Code
.la source
calculateBonus()
venir avantisFullTimeEmployee()
etdidCompleteBonusObjectives()
?isFullTimeEmployee
etdidCompleteBonusObjectives
sont utilisés par deisEligibleForBonus
sorte qu'ils devraient être verticalement près de lui. Mais vous pourriez potentiellementcalculateBonus
monter pour le rapprocher de l'endroit où il est appelé. Malheureusement, comme vous avez des fonctions appelant des fonctions, vous finissez par vous retrouver avec des problèmes (comme des fonctions partagées appelées par plusieurs autres) où il n’ya pas de classement parfait. Ensuite, cela dépend de votre meilleur jugement. Je recommande de garder les classes et les fonctions réduites pour atténuer ces problèmes.Je commande généralement mes méthodes par relation et ordre d'utilisation.
Prenez un cours de mise en réseau, je vais regrouper toutes les méthodes TCP, puis toutes les méthodes UDP. Le TCP interne, je voudrais avoir la méthode d'installation comme le premier, peut-être envoyer un message donné en second et fermer le socket TCP en troisième.
Il est évident que toutes les classes ne correspondent pas à ce modèle, mais c'est mon flux de travail général.
Je le fais de cette façon pour le débogage plus que tout autre chose, quand j'ai un problème et que je veux passer à la méthode, je ne pense pas comment est-il orthographié, je pense que c'est responsable de cela et aller à cette section.
De cette façon, il est particulièrement judicieux qu’un tiers visualise / utilise votre code comme étant regroupé et suive l’ordre dans lequel il est utilisé, de sorte que le code qu’il écrira avec votre classe suivra la même structure que la classe.
En ce qui concerne est-ce important?
pour la lisibilité, définitivement.
En dehors de cela pas vraiment, seulement dans les cas où certaines langues, vous ne pouvez pas appeler la méthode sauf si elle est définie ci-dessus, où elle est appelée, etc.
la source
Idéalement, vos cours sont si petits que cela n'a pas d'importance. Si vous ne disposez que d'une douzaine de méthodes et que votre éditeur ou votre IDE prend en charge le pliage, vous n'avez pas de problème, car la liste complète des méthodes tient sur 12 lignes.
À défaut, la distinction de haut niveau devrait être publique ou privée. Commencez par énumérer les méthodes publiques: ce sont ce que les gens vont rechercher, car ils définissent la manière dont votre classe s'interface avec le reste de la base de code.
Ensuite, à l'intérieur de chacun de ces éléments, il est judicieux de regrouper les méthodes par fonctionnalité: constructeurs et destructeurs dans un bloc, getters / setters dans un autre, surcharges d'opérateurs, méthodes statiques et reste du groupe. En C ++, j’aime cependant rester
operator=
proche des constructeurs, car c’est étroitement lié au constructeur de copie, mais aussi parce que je veux être capable de repérer rapidement si tous (ou aucun) ctor, copy ctor, operator = et dtor par défaut exister.la source
tl; dr
Seulement si la langue dans laquelle vous travaillez nécessite un ordre spécifique. Autre que cela, la commande est à vous. Choisissez un système cohérent et logique, et essayez de vous en tenir au maximum.
Seulement si la langue dans laquelle vous travaillez a besoin d'une fonction définie plus tôt dans le fichier qu'à l'endroit où elle est appelée, comme dans cet exemple:
vous obtiendrez une erreur car vous appelez
funcB()
avant de l'utiliser. Je pense que c'est un problème dans PL / SQL et peut-être aussi en C, mais vous pouvez avoir des déclarations en aval telles que:C’est la seule situation à laquelle je puisse penser où, si la commande est "fausse", vous ne pourrez même pas compiler.
Sinon, vous pouvez toujours les commander à votre guise. Vous pourriez probablement même écrire un outil pour le faire pour vous (si vous ne pouvez pas en trouver un).
Si la langue / l'environnement ne nécessite pas de commande, le "meilleur" ordre est celui qui vous convient le mieux . Pour moi, j'aime avoir tous les getters / setters ensemble, généralement au début de la classe (mais après les constructeurs / initialiseurs statiques), puis les méthodes privées, puis protégées, puis publiques. Dans chaque groupe basé sur la portée, il n'y a généralement pas d' ordre, bien que les méthodes surchargées que j'essaie de garder ensemble, par ordre de nombre de paramètres. J'essaie également de garder les méthodes avec les fonctionnalités liées ensemble, bien que parfois je dois rompre mon ordre basé sur les portées pour le faire; et parfois, essayer de maintenir un ordre basé sur la portée, par groupe de fonctionnalités. Et mon IDE peut me donner un aperçu alphabétique, alors c’est bien aussi. ;)
Certaines langues, comme C #, ont la possibilité de regrouper le code dans des "régions" qui n'ont aucun effet sur la compilation, mais peuvent faciliter la conservation des fonctions associées, puis les masquer / afficher avec l'EDI. Comme MainMa l'a souligné , certains considèrent que c'est une mauvaise pratique. J'ai vu de bons et de mauvais exemples de régions utilisées de cette manière. Par conséquent, si vous allez suivre cette voie, soyez prudent.
la source