Un de mes collègues déclare que les booléens comme arguments de méthode ne sont pas acceptables . Ils sont remplacés par des énumérations. Au début, je n'ai vu aucun avantage, mais il m'a donné un exemple.
Qu'est-ce qui est plus facile à comprendre?
file.writeData( data, true );
Ou
enum WriteMode {
Append,
Overwrite
};
file.writeData( data, Append );
Maintenant j'ai compris! ;-)
Ceci est certainement un exemple où une énumération en tant que deuxième paramètre rend le code beaucoup plus lisible.
Alors, quelle est votre opinion sur ce sujet?
coding-style
boolean
enumeration
Thomas Koschel
la source
la source
Réponses:
Les booléens représentent des choix «oui / non». Si vous voulez représenter un "oui / non", utilisez un booléen, cela devrait être explicite.
Mais s'il s'agit d'un choix entre deux options, dont aucune n'est clairement oui ou non, alors une énumération peut parfois être plus lisible.
la source
setLightOn(bool)
.Les énumérations permettent également de futures modifications, où vous voulez maintenant un troisième choix (ou plus).
la source
Utilisez celui qui correspond le mieux à votre problème. Dans l'exemple que vous donnez, l'énumération est un meilleur choix. Cependant, il y aurait d'autres moments où un booléen est meilleur. Ce qui a plus de sens pour vous:
ou
Dans ce cas, je pourrais choisir l'option booléenne car je pense que c'est assez clair et sans ambiguïté, et je suis à peu près sûr que mon verrou n'aura pas plus de deux états. Pourtant, le deuxième choix est valide, mais inutilement compliqué, à mon humble avis.
la source
Pour moi, ni utiliser booléen ni énumération n'est une bonne approche. Robert C.Martin capture cela très clairement dans son Astuce Clean Code # 12: Éliminer les arguments booléens :
Si une méthode fait plus d'une chose, vous devriez plutôt écrire deux méthodes différentes, par exemple dans votre cas:
file.append(data)
etfile.overwrite(data)
.L'utilisation d'une énumération ne rend pas les choses plus claires. Cela ne change rien, c'est toujours un argument de drapeau.
la source
setVisible(boolean visible) { mVisible = visible; }
. Quelle serait une alternative que vous suggéreriez?Je pense que vous avez presque répondu à cela vous-même, je pense que le but final est de rendre le code plus lisible, et dans ce cas, l'énumération l'a fait, l'OMI est toujours préférable de regarder l'objectif final plutôt que les règles générales, peut-être y penser plus à titre indicatif, les énumérations sont souvent plus lisibles dans le code que les booléens génériques, les entiers, etc. mais il y aura toujours des exceptions à la règle.
la source
Vous vous souvenez de la question posée par Adlai Stevenson à l'ambassadeur Zorin à l'ONU pendant la crise des missiles cubains ?
Si le drapeau que vous avez dans votre méthode est d'une nature telle que vous pouvez le fixer à une décision binaire , et que cette décision ne se transformera jamais en une décision à trois ou à n voies, optez pour booléen. Indications: votre drapeau s'appelle isXXX .
Ne le rendez pas booléen dans le cas de quelque chose qui est un commutateur de mode . Il y a toujours un mode de plus que celui auquel vous aviez pensé lors de l'écriture de la méthode en premier lieu.
Le dilemme d'un mode de plus a par exemple hanté Unix, où les modes d'autorisation possibles qu'un fichier ou un répertoire peut avoir aujourd'hui entraînent d'étranges doubles significations de modes en fonction du type de fichier, de la propriété, etc.
la source
Il y a deux raisons pour lesquelles j'ai trouvé que c'était une mauvaise chose:
Parce que certaines personnes écriront des méthodes comme:
C'est évidemment mauvais car il est trop facile de mélanger les paramètres, et vous n'avez aucune idée en regardant ce que vous spécifiez. Un seul booléen n'est pas si mal.
Parce que contrôler le déroulement du programme par une simple branche oui / non peut signifier que vous avez deux fonctions entièrement différentes qui sont regroupées en une d'une manière maladroite. Par exemple:
Vraiment, cela devrait être deux méthodes
parce que le code dans ceux-ci pourrait être entièrement différent; ils peuvent avoir à faire toutes sortes de traitement et de validation des erreurs différents, ou peut-être même avoir à formater les données sortantes différemment. Vous ne pouvez pas le dire simplement en utilisant
Write()
ou mêmeWrite(Enum.Optical)
(bien que vous puissiez bien sûr avoir l'une de ces méthodes, appelez simplement les méthodes internes WriteOptical / Mag si vous le souhaitez).Je suppose que ça dépend. Je n'en parlerais pas trop, sauf pour le n ° 1.
la source
Les énumérations sont meilleures mais je n'appellerais pas les paramètres booléens «inacceptables». Parfois, il est juste plus facile d'ajouter un petit booléen et de passer à autre chose (pensez aux méthodes privées, etc.)
la source
Les booléens peuvent être OK dans les langages qui ont des paramètres nommés, comme Python et Objective-C, car le nom peut expliquer ce que fait le paramètre:
ou:
la source
Je ne serais pas d'accord pour dire que c'est une bonne règle . De toute évidence, Enum permet un meilleur code explicite ou détaillé dans certains cas, mais en règle générale, il semble bien trop étendu.
Tout d'abord, permettez-moi de prendre votre exemple: la responsabilité (et la capacité) des programmeurs d'écrire du bon code n'est pas vraiment mise en danger par un paramètre booléen. Dans votre exemple, le programmeur aurait pu écrire du code aussi détaillé en écrivant:
ou je préfère plus général
Deuxièmement: l'exemple Enum que vous avez donné n'est "meilleur" que parce que vous passez un CONST. Très probablement dans la plupart des applications, au moins certains sinon la plupart des paramètres de temps passés aux fonctions sont des VARIABLES. auquel cas mon deuxième exemple (donner des variables avec de bons noms) est bien meilleur et Enum vous aurait donné peu d'avantages.
la source
Les énumérations ont un avantage certain, mais vous ne devriez pas simplement remplacer tous vos booléens par des énumérations. Il existe de nombreux endroits où vrai / faux est en fait le meilleur moyen de représenter ce qui se passe.
Cependant, les utiliser comme arguments de méthode est un peu suspect, simplement parce que vous ne pouvez pas voir sans creuser dans les choses ce qu'ils sont censés faire, car ils vous permettent de voir ce que signifie réellement le vrai / faux
Les propriétés (en particulier avec les initialiseurs d'objets C # 3) ou les arguments de mots clés (à la ruby ou python) sont une bien meilleure façon d'aller là où vous utiliseriez autrement un argument booléen.
Exemple C #:
Exemple de rubis
Exemple Python
La seule chose à laquelle je peux penser où un argument de méthode booléenne est la bonne chose à faire est en java, où vous n'avez ni propriétés ni arguments de mots-clés. C'est l'une des raisons pour lesquelles je déteste java :-(
la source
S'il est vrai que dans de nombreux cas les énumérations sont plus lisibles et plus extensibles que les booléens, une règle absolue selon laquelle «les booléens ne sont pas acceptables» est stupide. Elle est inflexible et contre-productive - elle ne laisse pas de place au jugement humain. C'est un type intégré fondamental dans la plupart des langages car ils sont utiles - envisagez de l'appliquer à d'autres types intégrés: dire par exemple "ne jamais utiliser un int comme paramètre" serait juste fou.
Cette règle est juste une question de style, pas de potentiel de bogues ou de performances d'exécution. Une meilleure règle serait de "préférer les énumérations aux booléens pour des raisons de lisibilité".
Regardez le framework .Net. Les booléens sont utilisés comme paramètres sur de nombreuses méthodes. L'API .Net n'est pas parfaite, mais je ne pense pas que l'utilisation de booléen comme paramètres soit un gros problème. L'info-bulle vous donne toujours le nom du paramètre, et vous pouvez également créer ce type de guidage - remplissez vos commentaires XML sur les paramètres de la méthode, ils apparaîtront dans l'info-bulle.
Je dois également ajouter qu'il y a un cas où vous devriez clairement refactoriser les booléens en une énumération - lorsque vous avez deux ou plusieurs booléens sur votre classe, ou dans vos paramètres de méthode, et que tous les états ne sont pas valides (par exemple, il n'est pas valide de les avoir les deux sont définis sur true).
Par exemple, si votre classe a des propriétés comme
Et c'est une erreur d'avoir les deux vrais en même temps, ce que vous avez en fait, ce sont trois états valides, mieux exprimés comme quelque chose comme:
la source
Certaines règles auxquelles votre collègue pourrait mieux adhérer sont:
la source
Un booléen n'est acceptable que si vous n'avez pas l'intention d'étendre les fonctionnalités du framework. L'énumération est préférable car vous pouvez étendre l'énumération et ne pas interrompre les implémentations précédentes de l'appel de fonction.
L'autre avantage de Enum est qu'il est plus facile à lire.
la source
Si la méthode pose une question telle que:
où
Les arguments de méthode booléenne semblent avoir un sens absolument parfait.
la source
Cela dépend de la méthode. Si la méthode fait quelque chose qui est de toute évidence une chose vraie / fausse, c'est bien, par exemple ci-dessous [mais non je ne dis pas que c'est la meilleure conception pour cette méthode, c'est juste un exemple où l'utilisation est évidente].
Cependant, dans la plupart des cas, comme dans l'exemple que vous mentionnez, il est préférable d'utiliser une énumération. Il existe de nombreux exemples dans le .NET Framework lui-même où cette convention n'est pas respectée, mais c'est parce qu'ils ont introduit cette directive de conception assez tard dans le cycle.
la source
Cela rend les choses un peu plus explicites, mais commence à étendre massivement la complexité de vos interfaces - dans un simple choix booléen tel que l'ajout / l'écrasement, cela semble excessif. Si vous avez besoin d'ajouter une option supplémentaire (à laquelle je ne pense pas dans ce cas), vous pouvez toujours effectuer un refactor (selon la langue)
la source
Les énumérations peuvent certainement rendre le code plus lisible. Il y a encore quelques points à surveiller (au moins en .net)
Étant donné que le stockage sous-jacent d'une énumération est un entier, la valeur par défaut sera zéro, vous devez donc vous assurer que 0 est une valeur par défaut raisonnable. (Par exemple, les structures ont tous les champs mis à zéro lors de leur création, il n'y a donc aucun moyen de spécifier une valeur par défaut autre que 0. Si vous n'avez pas de valeur 0, vous ne pouvez même pas tester l'énumération sans transtyper en int, ce qui serait mauvais style.)
Si vos énumérations sont privées pour votre code (jamais exposées publiquement), vous pouvez arrêter de lire ici.
Si vos énumérations sont publiées de quelque manière que ce soit dans du code externe et / ou sont enregistrées en dehors du programme, envisagez de les numéroter explicitement. Le compilateur les numérote automatiquement à partir de 0, mais si vous réorganisez vos énumérations sans leur donner de valeurs, vous pouvez vous retrouver avec des défauts.
Je peux légalement écrire
Pour lutter contre cela, tout code qui consomme une énumération dont vous ne pouvez pas être certain (par exemple API publique) doit vérifier si l'énumération est valide. Vous faites cela via
Le seul inconvénient
Enum.IsDefined
est qu'il utilise la réflexion et est plus lent. Il souffre également d'un problème de version. Si vous avez besoin de vérifier souvent la valeur d'énumération, vous feriez mieux de:Le problème de la gestion des versions est que l'ancien code ne sait peut-être que comment gérer les 2 énumérations que vous avez. Si vous ajoutez une troisième valeur, Enum.IsDefined sera true, mais l'ancien code ne peut pas nécessairement le gérer. Oups.
Les énumérations sont encore plus amusantes
[Flags]
, et le code de validation est légèrement différent.Je noterai également que pour la portabilité, vous devez utiliser l'appel
ToString()
sur l'énumération, et l'utiliserEnum.Parse()
lors de leur lecture. Les deuxToString()
etEnum.Parse()
peuvent gérer[Flags]
ENUM est aussi bien, donc il n'y a aucune raison de ne pas les utiliser. Attention, c'est encore un autre piège, car maintenant vous ne pouvez même pas changer le nom de l'énumération sans éventuellement casser le code.Donc, parfois, vous devez peser tout ce qui précède lorsque vous vous demandez: Puis-je m'en tirer avec juste un booléen?
la source
IMHO, il semble qu'une énumération serait le choix évident pour toute situation où plus de deux options sont possibles. Mais il existe certainement des situations où un booléen est tout ce dont vous avez besoin. Dans ce cas, je dirais que l'utilisation d'une énumération où un booléen fonctionnerait serait un exemple d'utilisation de 7 mots alors que 4 suffirait.
la source
Les booléens ont un sens lorsque vous avez une bascule évidente qui ne peut être que l'une des deux choses (c'est-à-dire l'état d'une ampoule, allumée ou éteinte). En dehors de cela, il est bon de l'écrire de manière à ce que ce que vous transmettez soit évident - par exemple, les écritures sur disque - sans tampon, en tampon de ligne ou synchrone - devraient être passées comme telles. Même si vous ne voulez pas autoriser les écritures synchrones maintenant (et que vous êtes donc limité à deux options), il vaut la peine d'envisager de les rendre plus verbeuses afin de savoir ce qu'elles font au premier coup d'œil.
Cela dit, vous pouvez également utiliser False et True (booléen 0 et 1), puis si vous avez besoin de plus de valeurs plus tard, développez la fonction pour prendre en charge les valeurs définies par l'utilisateur (par exemple, 2 et 3), et vos anciennes valeurs 0/1 portera bien, donc votre code ne doit pas se casser.
la source
Parfois, il est simplement plus simple de modéliser différents comportements avec des surcharges. Pour continuer à partir de votre exemple serait:
Cette approche se dégrade si vous avez plusieurs paramètres, chacun permettant un ensemble fixe d'options. Par exemple, une méthode qui ouvre un fichier peut avoir plusieurs permutations de mode fichier (ouvrir / créer), d'accès au fichier (lecture / écriture), de mode de partage (aucun / lecture / écriture). Le nombre total de configurations est égal aux produits cartésiens des options individuelles. Naturellement, dans de tels cas, des surcharges multiples ne sont pas appropriées.
Les énumérations peuvent, dans certains cas, rendre le code plus lisible, bien que valider la valeur exacte de l'énumération dans certains langages (C # par exemple) puisse être difficile.
Souvent, un paramètre booléen est ajouté à la liste des paramètres en tant que nouvelle surcharge. Un exemple dans .NET est:
Cette dernière surcharge est devenue disponible dans une version plus récente du framework .NET que la première.
Si vous savez qu'il n'y aura jamais que deux choix, un booléen peut convenir. Les énumérations sont extensibles de manière à ne pas casser l'ancien code, bien que les anciennes bibliothèques puissent ne pas prendre en charge les nouvelles valeurs d'énumération, de sorte que la gestion des versions ne peut pas être complètement ignorée.
ÉDITER
Dans les versions plus récentes de C #, il est possible d'utiliser des arguments nommés qui, IMO, peuvent rendre le code d'appel plus clair de la même manière que les énumérations. En utilisant le même exemple que ci-dessus:
la source
Là où je suis d'accord que les Enums sont un bon moyen d'aller, dans des méthodes où vous avez 2 options (et seulement deux options, vous pouvez avoir une lisibilité sans enum.)
par exemple
J'adore les Enums, mais le booléen est également utile.
la source
Il s'agit d'une entrée tardive sur un ancien message, et il est si loin dans la page que personne ne le lira jamais, mais puisque personne ne l'a déjà dit ...
Un commentaire en ligne contribue grandement à résoudre le
bool
problème inattendu . L'exemple original est particulièrement odieux: imaginez essayer de nommer la variable dans la fonction de déclinaison! Ce serait quelque chose commeMais, à titre d'exemple, disons que c'est la déclaration. Ensuite, pour un argument booléen autrement inexpliqué, j'ai mis le nom de la variable dans un commentaire en ligne. Comparer
avec
la source
Cela dépend vraiment de la nature exacte de l'argument. Si ce n'est pas un oui / non ou un vrai / faux alors une énumération le rend plus lisible. Mais avec une énumération, vous devez vérifier l'argument ou avoir un comportement par défaut acceptable car des valeurs non définies du type sous-jacent peuvent être passées.
la source
L'utilisation d'énumérations au lieu de booléens dans votre exemple permet de rendre l'appel de méthode plus lisible. Cependant, c'est un substitut à mon élément de souhait préféré en C #, des arguments nommés dans les appels de méthode. Cette syntaxe:
serait parfaitement lisible, et vous pourriez alors faire ce qu'un programmeur devrait faire, c'est-à-dire choisir le type le plus approprié pour chaque paramètre de la méthode sans tenir compte de son apparence dans l'EDI.
C # 3.0 autorise les arguments nommés dans les constructeurs. Je ne sais pas pourquoi ils ne peuvent pas non plus faire cela avec des méthodes.
la source
Valeurs booléennes
true
/false
uniquement. Ce que cela représente n'est donc pas clair.Enum
peut avoir le nom significatif, par exempleOVERWRITE
,APPEND
, etc. énumérations ne sont donc mieux.la source