Fermé . Cette question doit être plus ciblée . Il naccepte pas les réponses actuellement.

Commentaires

  • Il semble que MainMa et moi avons une définition différente de lindicateur ". " Je pensais au préprocesseur #ifdefs. Laquelle demandiez-vous?
  • Cest une très bonne question. Je ' me suis beaucoup posé cette question moi-même, et je me suis en fait retrouvé à dire " bon, utilisons simplement un indicateur " un peu trop.
  • Les booléens sont des indicateurs. (Il en va de même pour les entiers …)
  • @KarlBielefeldt Je crois que OP fait référence à des variables booléennes ou entières auxquelles vous attribuez une valeur à certains endroits, puis en bas, vous cochez puis ou plus pour faire quelque chose ou pas, comme, par exemple en utilisant newItem = true puis quelques lignes en dessous de if (newItem ) then
  • Considérez également le présente la refactorisation des variables explicatives dans ce contexte. Tant que la méthode reste courte et comporte un faible nombre de chemins, je considère cela comme une utilisation valable.

Réponse

Le problème que jai vu lors de la gestion du code qui utilise des indicateurs est que le nombre détats augmente rapidement et quil y a presque toujours des états non gérés. Un exemple tiré de ma propre expérience: je travaillais sur du code qui avait ces trois indicateurs

bool capturing, processing, sending; 

Ces trois ont créé huit états (en fait, il y avait deux autres indicateurs ainsi que). Toutes les combinaisons de valeurs possibles nétaient pas couvertes par le code, et les utilisateurs voyaient des bogues:

if(capturing && sending){ // we must be processing as well ... } 

Il sest avéré quil y avait des situations où lhypothèse dans linstruction if ci-dessus était faux.

Les indicateurs ont tendance à se composer avec le temps, et ils cachent létat réel dune classe. Cest pourquoi ils doivent être évités.

Les commentaires

  • +1, " doivent être évités ". Jajouterais quelque chose à propos de ' mais des drapeaux sont nécessaires dans certaines situations ' (certains pourraient dire ' un mal nécessaire ')
  • @TrevorBoydSmith Daprès mon expérience, ils ne le sont pas, vous avez juste besoin dun peu plus que la puissance cérébrale moyenne que vous utiliseriez pour un indicateur
  • Dans votre exemple, il aurait dû être une seule énumération représentant létat, et non 3 booléens.
  • Vous pourriez arriver à un problème similaire à ce que je ' m face en ce moment. En plus de couvrir tous les états possibles, deux applications peuvent partager le même indicateur (par exemple, le téléchargement de données client). Dans ce cas, un seul téléchargeur utilisera lindicateur, le désactivera et bonne chance pour trouver le problème à lavenir.

Réponse

Voici un exemple où les indicateurs sont utiles.

Jai un morceau de code qui génère des mots de passe (en utilisant un générateur de nombres pseudo-aléatoires cryptographiquement sécurisé). Lappelant de la méthode choisit si ou non le mot de passe doit contenir des majuscules, des minuscules, des chiffres, des symboles de base, des symboles étendus, des symboles grecs, des symboles cyrilliques et unicode.

Avec les drapeaux, appeler cette méthode est facile:

 var password = this.PasswordGenerator.Generate( CharacterSet.Digits | CharacterSet.LowercaseLetters | CharacterSet.UppercaseLetters);  

et il peut même être simplifié en:

 var password = this.PasswordGenerator.Generate(CharacterSet.LettersAndDigits);  

Sans les indicateurs, quelle serait la signature de la méthode?

 public byte[] Generate( bool uppercaseLetters, bool lowercaseLetters, bool digits, bool basicSymbols, bool extendedSymbols, bool greekLetters, bool cyrillicLetters, bool unicode);  

appelé comme ceci:

 // Very readable, isn"t it? // Tell me just by looking at this code what symbols do I want to be included? var password = this.PasswordGenerator.Generate( true, true, true, false, false, false, false, false);  

Comme indiqué dans les commentaires, une autre approche serait dutiliser une collection:

 var password = this.PasswordGenerator.Generate( new [] { CharacterSet.Digits, CharacterSet.LowercaseLetters, CharacterSet.UppercaseLetters, });  

Cest beaucoup plus lisible par rapport à lensemble des true et false, mais présente toujours deux inconvénients:

Linconvénient majeur est que pour permettre des valeurs combinées, comme CharacterSet.LettersAndDigits vous écririez quelque chose comme ça dans la méthode Generate():

 if (set.Contains(CharacterSet.LowercaseLetters) || set.Contains(CharacterSet.Letters) || set.Contains(CharacterSet.LettersAndDigits) || set.Contains(CharacterSet.Default) || set.Contains(CharacterSet.All)) { // The password should contain lowercase letters. }  

éventuellement réécrit comme ceci:

 var lowercaseGroups = new [] { CharacterSet.LowercaseLetters, CharacterSet.Letters, CharacterSet.LettersAndDigits, CharacterSet.Default, CharacterSet.All, }; if (lowercaseGroups.Any(s => set.Contains(s))) { // The password should contain lowercase letters. }  

Comparez cela avec ce que vous avez en utilisant des indicateurs:

 if (set & CharacterSet.LowercaseLetters == CharacterSet.LowercaseLetters) { // The password should contain lowercase letters. }  

Le s econd, un inconvénient très mineur est quil « nest pas clair comment la méthode se comporterait si elle était appelée comme ceci:

 var password = this.PasswordGenerator.Generate( new [] { CharacterSet.Digits, CharacterSet.LettersAndDigits, // So digits are requested two times. });  

Commentaires

  • Je crois que OP fait référence à des variables booléennes ou entières auxquelles vous attribuez une valeur à certains endroits, puis en bas, vous vérifiez puis dans ou plus pour faire quelque chose ou pas, comme par exemple en utilisant newItem = true puis quelques lignes en dessous de if (newItem ) then
  • @MainMa Apparemment, il ' sa 3e: La version avec 8 arguments booléens est ce à quoi jai pensé lorsque jai lu " flags " …
  • Désolé, mais à mon humble avis, cest le cas parfait pour le chaînage de méthodes ( en.wikipedia.org/wiki/Method_chaining), De plus, vous pouvez utiliser un tableau de paramètres (doit être un tableau associatif ou une carte), où toute entrée dans ce tableau de paramètres que vous omettez utilise le comportement de valeur par défaut pour ce paramètre. En fin de compte, lappel via le chaînage de méthodes ou les tableaux de paramètres peut être aussi succinct et expressif que les indicateurs de bits.De plus, tous les langages nont pas dopérateurs de bits (jaime en fait les indicateurs binaires, mais jutiliserais plutôt les méthodes que je viens de mentionner). / li>
  • Ce ' nest pas très OOP, nest-ce pas? Je ' d créer une interface ala: String myNewPassword = makePassword (randomComposeSupplier (new RandomLowerCaseSupplier (), new RandomUpperCaseSupplier (), new RandomNumberSupplier)); avec String makePassword (Supplier < Character > charSupplier); et Fournisseur < Caractère > randomComposeSupplier (Fournisseur < Caractère > … fournisseurs); Vous pouvez désormais réutiliser vos fournisseurs pour dautres tâches, les composer comme vous le souhaitez et simplifier votre méthode generatePassword afin quelle utilise létat minimal.
  • @Dibbeke Parlez dun royaume des noms

Réponse

Un énorme bloc fonction est lodeur , pas les drapeaux. Si vous définissez le drapeau sur la ligne 5, puis vérifiez uniquement le drapeau sur la ligne 354, alors cest mauvais. Si vous définissez le drapeau sur la ligne 8 et vérifiez le drapeau sur la ligne 10, cest très bien. De plus, un ou deux indicateurs par bloc de code, cest bien, 300 indicateurs dans une fonction, cest mauvais.

Réponse

Généralement des indicateurs peut être complètement remplacé par une certaine saveur du modèle de stratégie, avec une mise en œuvre de stratégie pour chaque valeur possible du drapeau. Cela rend lajout dun nouveau comportement beaucoup plus facile.

Dans les situations critiques de performances, le coût de lindirection pourrait faire surface et rendre nécessaire la déconstruction en indicateurs clairs. Cela étant dit, jai du mal à me souvenir dun seul cas où jai dû faire ça.

Réponse

Non, les drapeaux ne sont pas mauvais ou un mal qui doit être refactorisé à tout prix.

Considérez Java « s Pattern.compile (String regex, int flags) appel. Cest un masque de bits traditionnel et cela fonctionne. Jetez un coup dœil aux constantes en java et partout où vous voyez un groupe de 2 n , vous savez quil y a des indicateurs.

Dans un monde refactoré idéal, on utiliserait plutôt un EnumSet où les constantes sont à la place des valeurs dans une énumération et comme le lit la documentation:

Les performances spatiales et temporelles de cette classe doivent être suffisamment bonnes pour permettre son utilisation comme alternative de haute qualité et sécurisée aux « bit flags » traditionnels basés sur int.

Dans un monde parfait, cet appel Pattern.compile devient Pattern.compile(String regex, EnumSet<PatternFlagEnum> flags).

Tout cela dit, ses drapeaux toujours.Il est beaucoup plus facile de travailler avec Pattern.compile("foo", Pattern.CASE_INSENSTIVE | Pattern.MULTILINE) quavec Pattern.compile("foo", new PatternFlags().caseInsenstive().multiline()) ou un autre style pour essayer de faire ce que sont réellement les indicateurs et bon pour.

Les drapeaux sont souvent vus quand on travaille avec des choses au niveau du système. Lors de linterfaçage avec quelque chose au niveau du système dexploitation, on est susceptible davoir un indicateur quelque part – que ce soit la valeur de retour dun processus, ou les autorisations dun fichier, ou les indicateurs pour ouvrir un socket. Essayer de refactoriser ces instances dans une chasse aux sorcières contre une odeur de code perçue aboutira probablement à un code pire que si lun deux acceptait et comprenait le drapeau.

Le problème survient lorsque les gens abusent des drapeaux en les jetant ensemble et créer un ensemble de fanions francs de toutes sortes de drapeaux non liés ou essayer de les utiliser là où ils ne sont pas du tout des drapeaux.

Réponse

Je suppose que nous parlons de drapeaux dans les signatures de méthode.

Utiliser un seul drapeau est déjà assez mauvais.

Cela ne signifiera rien pour vos collègues la première fois quils le verront. Ils « devront regarder le code source de la méthode pour déterminer ce quelle fait. Vous serez probablement dans la même position quelques mois plus tard, quand vous oublierez de quoi il sagissait.

Passer un drapeau à la méthode signifie normalement que votre méthode est responsable de plusieurs choses. À lintérieur de la méthode, vous faites probablement une simple vérification sur les lignes de:

if (flag) DoFlagSet(); else DoFlagNotSet(); 

Cest « une mauvaise séparation des préoccupations et vous pouvez normalement trouver un moyen de contourner cela.

Jai normalement deux méthodes distinctes:

public void DoFlagSet() { } public void DoFlagNotSet() { } 

Cela aura plus de sens avec les noms de méthodes applicables au problème que vous résolvez.

Passer plusieurs indicateurs est deux fois plus mauvais. Si vous avez vraiment besoin de passer plusieurs indicateurs, envisagez de les encapsuler dans une classe. Même dans ce cas, vous serez toujours confronté au même problème, car votre méthode fait probablement plusieurs choses.

Réponse

Drapeaux et la plupart des variables de température ont une forte odeur. Très probablement, ils pourraient être refactorisés et remplacés par des méthodes de requête.

Révisé:

Les indicateurs et les variables temporaires lors de lexpression de létat, devraient être refactorisés en méthodes de requête. Les valeurs détat (booléens, entiers et autres primatives) devraient presque toujours être masquées dans le cadre des détails dimplémentation.

Les indicateurs utilisés pour le contrôle, le routage et le déroulement général du programme peuvent également indiquer le possibilité de refactoriser des sections des structures de contrôle en stratégies ou usines séparées, ou tout ce qui pourrait être approprié à la situation, qui continuent à utiliser les méthodes de requête.

Réponse

Quand nous parlons dindicateurs, nous devons savoir quils vont être modifiés au cours de lexécution du programme et quils vont affecter le comportement du programme en fonction de leurs états. Tant que nous avons un contrôle précis sur ces deux choses, elles fonctionneront très bien.

Les indicateurs peuvent très bien fonctionner si

  • Vous les avez définis dans une portée appropriée. Par approprié, jentends que la portée ne doit contenir aucun code qui na pas besoin / ne devrait pas les modifier. Ou au moins le code est sécurisé (par exemple, il peut ne pas être appelé directement de lextérieur)
  • Sil est nécessaire de gérer des indicateurs de lextérieur et sil y a beaucoup dindicateurs, nous pouvons coder le gestionnaire dindicateurs comme un seul moyen pour modifier en toute sécurité les indicateurs. Ce gestionnaire dindicateur peut lui-même encapsuler des indicateurs et des méthodes pour les modifier. Il peut alors être rendu singleton et peut ensuite être partagé entre les classes qui ont besoin daccéder aux indicateurs.
  • Et enfin pour la maintenabilité, sil y a trop dindicateurs:
    • Pas besoin de dire quils devraient suivre une dénomination sensée
    • Doit être documenté avec quelles sont les valeurs valides (peut-être avec des énumérations)
    • Doit être documenté avec QUEL CODE MODIFIERA chacune delles, et aussi avec QUELLE CONDITION en résultera dans lattribution dune valeur particulière à lindicateur.
    • QUEL CODE LES CONSOMMERA et QUEL COMPORTEMENT en résultera pour une valeur particulière

Sil y a beaucoup dindicateurs, un bon travail de conception devrait précéder puisque les indicateurs commencent à jouer un rôle clé dans le comportement du programme. Vous pouvez opter pour des diagrammes détat pour la modélisation. Ces diagrammes fonctionnent également comme documentation et guide visuel tout en les traitant.

Tant que ces éléments sont en place, je pense que cela ne mènera pas au désordre.

Réponse

Jai supposé à partir de la question que le QA signifiait des variables dindicateur (globales), et non des bits dun paramètre de fonction.

Il y a des situations où vous n « avez pas beaucoup d » autres possibilités. Par exemple, sans système d « exploitation, vous devez évaluer les interruptions.Si une interruption survient très fréquemment et que vous navez pas le temps de faire une longue évaluation dans lISR, il est non seulement autorisé mais parfois même la meilleure pratique de ne définir que quelques indicateurs globaux dans lISR (vous devriez passer le moins de temps possible dans lISR), et pour évaluer ces indicateurs dans votre boucle principale.

Answer

Je ne pense pas tout est un mal absolu en programmation, jamais.

Il y a une autre situation où les drapeaux pourraient être en ordre, ce qui nont pas encore été mentionnés ici …

Considérez lutilisation de fermetures dans cet extrait de code Javascript:

exports.isPostDraft = function ( post, draftTag ) { var isDraft = false; if (post.tags) post.tags.forEach(function(tag){ if (tag === draftTag) isDraft = true; }); return isDraft; } 

La fonction interne, en cours de transmission au « Array.forEach », ne peut pas simplement « retourner vrai ».

Par conséquent, vous devez garder létat à lextérieur avec un drapeau.

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *