Ein Kollege von mir erklärt, dass Boolesche Werte als Methodenargumente nicht akzeptabel sind . Sie werden durch Aufzählungen ersetzt. Zuerst sah ich keinen Nutzen, aber er gab mir ein Beispiel.
Was ist leichter zu verstehen?
file.writeData( data, true );
Oder
enum WriteMode {
Append,
Overwrite
};
file.writeData( data, Append );
Jetzt hab ich es verstanden! ;-)
Dies ist definitiv ein Beispiel, bei dem eine Aufzählung als zweiter Parameter den Code viel lesbarer macht.
Wie ist Ihre Meinung zu diesem Thema?
coding-style
boolean
enumeration
Thomas Koschel
quelle
quelle
Antworten:
Boolesche Werte stehen für "Ja / Nein". Wenn Sie ein "Ja / Nein" darstellen möchten, verwenden Sie einen Booleschen Wert. Dieser sollte selbsterklärend sein.
Wenn es sich jedoch um eine Wahl zwischen zwei Optionen handelt, von denen keine eindeutig Ja oder Nein ist, kann eine Aufzählung manchmal besser lesbar sein.
quelle
setLightOn(bool)
.Aufzählungen ermöglichen auch zukünftige Änderungen, bei denen Sie jetzt eine dritte Auswahl (oder mehr) wünschen.
quelle
Verwenden Sie diejenige, die Ihr Problem am besten modelliert. In dem Beispiel, das Sie geben, ist die Aufzählung die bessere Wahl. Es würde jedoch andere Zeiten geben, in denen ein Boolescher Wert besser ist. Was für Sie sinnvoller ist:
oder
In diesem Fall könnte ich die boolesche Option wählen, da ich denke, dass sie ziemlich klar und eindeutig ist, und ich bin mir ziemlich sicher, dass meine Sperre nicht mehr als zwei Zustände haben wird. Dennoch ist die zweite Wahl meiner Meinung nach gültig, aber unnötig kompliziert.
quelle
Für mich ist weder die Verwendung von Booleschen Werten noch die Aufzählung ein guter Ansatz. Robert C. Martin fängt dies sehr deutlich in seinem Clean Code-Tipp Nr. 12 ein: Eliminieren Sie boolesche Argumente :
Wenn eine Methode mehr als eine Sache tut, sollten Sie lieber zwei verschiedene Methoden schreiben, zum Beispiel in Ihrem Fall:
file.append(data)
undfile.overwrite(data)
.Die Verwendung einer Aufzählung macht die Dinge nicht klarer. Es ändert nichts, es ist immer noch ein Flaggenargument.
quelle
setVisible(boolean visible) { mVisible = visible; }
. Was wäre eine Alternative, die Sie vorschlagen würden?Ich denke, Sie haben dies fast selbst beantwortet. Ich denke, das Endziel ist es, den Code lesbarer zu machen, und in diesem Fall hat die Aufzählung dies getan. IMO ist es immer am besten, das Endziel zu betrachten, anstatt pauschale Regeln, vielleicht mehr darüber nachzudenken Als Richtlinie, dh Aufzählungen sind im Code oft besser lesbar als generische Bools, Ints usw., aber es wird immer Ausnahmen von der Regel geben.
quelle
Erinnern Sie sich an die Frage, die Adlai Stevenson während der Kubakrise an Botschafter Zorin bei der UN stellte ?
Wenn das Flag, das Sie in Ihrer Methode haben, so beschaffen ist, dass Sie es auf eine binäre Entscheidung festlegen können und diese Entscheidung niemals zu einer Drei- oder N-Wege-Entscheidung wird, wählen Sie Boolesch. Anzeigen: Ihre Flagge heißt isXXX .
Machen Sie es nicht boolesch, wenn es sich um einen Modusschalter handelt . Es gibt immer noch einen Modus als Sie beim Schreiben der Methode gedacht haben.
Das Dilemma mit einem weiteren Modus hat z. B. Unix heimgesucht, wo die möglichen Berechtigungsmodi, die eine Datei oder ein Verzeichnis heute haben kann, zu seltsamen Doppelbedeutungen von Modi führen, abhängig von Dateityp, Besitz usw.
quelle
Es gibt zwei Gründe, warum ich darauf gestoßen bin, dass dies eine schlechte Sache ist:
Weil manche Leute Methoden schreiben wie:
Dies ist offensichtlich schlecht, da es zu einfach ist, Parameter zu verwechseln, und Sie keine Ahnung haben, wenn Sie sich ansehen, was Sie angeben. Nur ein Bool ist aber nicht schlecht.
Da die Steuerung des Programmflusses durch einen einfachen Ja / Nein-Zweig bedeuten kann, dass Sie zwei völlig unterschiedliche Funktionen haben, die auf unangenehme Weise in einer zusammengefasst sind. Zum Beispiel:
Wirklich, das sollten zwei Methoden sein
weil der Code in diesen völlig anders sein könnte; Möglicherweise müssen sie alle möglichen Fehlerbehandlungen und -validierungen durchführen oder sogar die ausgehenden Daten unterschiedlich formatieren. Sie können das nicht einfach mit
Write()
oder sogar sagenWrite(Enum.Optical)
(obwohl Sie natürlich auch eine dieser Methoden haben könnten, rufen Sie einfach die internen Methoden WriteOptical / Mag auf, wenn Sie möchten).Ich denke es kommt nur darauf an. Ich würde nicht zu viel daraus machen, außer # 1.
quelle
Aufzählungen sind besser, aber ich würde boolesche Parameter nicht als "inakzeptabel" bezeichnen. Manchmal ist es einfach einfacher, einen kleinen Booleschen Wert hineinzuwerfen und weiterzumachen (denken Sie an private Methoden usw.)
quelle
Boolesche Werte können in Sprachen mit benannten Parametern wie Python und Objective-C in Ordnung sein, da der Name erklären kann, was der Parameter bewirkt:
oder:
quelle
Ich würde nicht zustimmen, dass es eine gute Regel ist . Natürlich sorgt Enum in einigen Fällen für einen besseren expliziten oder ausführlichen Code, aber in der Regel scheint er weit über das Erreichen hinauszugehen.
Lassen Sie mich zunächst Ihr Beispiel nehmen: Die Verantwortung (und Fähigkeit) des Programmierers, guten Code zu schreiben, wird durch einen booleschen Parameter nicht wirklich gefährdet. In Ihrem Beispiel hätte der Programmierer genauso ausführlichen Code schreiben können, indem er Folgendes schrieb:
oder ich bevorzuge allgemeiner
Zweitens: Das von Ihnen angegebene Enum-Beispiel ist nur "besser", weil Sie eine CONST bestehen. Höchstwahrscheinlich sind in den meisten Anwendungen zumindest einige, wenn nicht die meisten Zeitparameter, die an Funktionen übergeben werden, VARIABLEN. In diesem Fall ist mein zweites Beispiel (Variablen mit guten Namen angeben) viel besser und Enum hätte Ihnen wenig Vorteile gebracht.
quelle
Aufzählungen haben definitiv einen Vorteil, aber Sie sollten nicht einfach alle Ihre Booleschen Werte durch Aufzählungen ersetzen. Es gibt viele Orte, an denen wahr / falsch tatsächlich der beste Weg ist, um darzustellen, was vor sich geht.
Die Verwendung als Methodenargumente ist jedoch etwas verdächtig, einfach weil Sie nicht sehen können, ohne sich mit den Dingen zu befassen, die sie tun sollen, da Sie sehen können, was wahr / falsch ist tatsächlich bedeutet
Eigenschaften (insbesondere bei C # 3-Objektinitialisierern) oder Schlüsselwortargumente (a la ruby oder python) sind ein viel besserer Weg, um dahin zu gelangen, wo Sie sonst ein boolesches Argument verwenden würden.
C # Beispiel:
Ruby Beispiel
Python-Beispiel
Das einzige, was ich mir vorstellen kann, wo ein boolesches Methodenargument das Richtige ist, ist in Java, wo Sie weder Eigenschaften noch Schlüsselwortargumente haben. Dies ist einer der Gründe, warum ich Java hasse :-(
quelle
Während es wahr ist, dass Enums in vielen Fällen lesbarer und erweiterbarer sind als Boolesche Werte, ist eine absolute Regel, dass "Boolesche Werte nicht akzeptabel sind", dumm. Es ist unflexibel und kontraproduktiv - es lässt keinen Raum für menschliches Urteilsvermögen. Sie sind in den meisten Sprachen ein grundlegender integrierter Typ, weil sie nützlich sind. Erwägen Sie, sie auf andere integrierte Typen anzuwenden: Zum Beispiel wäre es einfach verrückt zu sagen, dass Sie niemals ein int als Parameter verwenden.
Diese Regel ist nur eine Frage des Stils, nicht des Potenzials für Fehler oder die Laufzeitleistung. Eine bessere Regel wäre "aus Gründen der Lesbarkeit Enums gegenüber Booleschen Werten bevorzugen".
Schauen Sie sich das .Net-Framework an. Boolesche Werte werden bei einigen Methoden als Parameter verwendet. Die .Net-API ist nicht perfekt, aber ich denke nicht, dass die Verwendung von Booleschen Werten als Parameter ein großes Problem darstellt. Der Tooltip gibt Ihnen immer den Namen des Parameters an, und Sie können diese Art von Anleitung auch erstellen. Geben Sie Ihre XML-Kommentare zu den Methodenparametern ein. Diese werden im Tooltip angezeigt.
Ich sollte auch hinzufügen, dass es einen Fall gibt, in dem Sie Boolesche Werte eindeutig in eine Aufzählung umgestalten sollten - wenn Sie zwei oder mehr Boolesche Werte in Ihrer Klasse oder in Ihren Methodenparametern haben und nicht alle Zustände gültig sind (z. B. ist es nicht gültig, sie zu haben) beide setzen wahr).
Zum Beispiel, wenn Ihre Klasse Eigenschaften wie hat
Und es ist ein Fehler, beide gleichzeitig wahr zu haben. Was Sie tatsächlich haben, sind drei gültige Zustände, besser ausgedrückt als:
quelle
Einige Regeln, die Ihr Kollege möglicherweise besser einhält, sind:
quelle
Ein Boolescher Wert wäre nur akzeptabel, wenn Sie nicht beabsichtigen, die Funktionalität des Frameworks zu erweitern. Die Aufzählung wird bevorzugt, da Sie die Aufzählung erweitern und frühere Implementierungen des Funktionsaufrufs nicht unterbrechen können.
Der andere Vorteil der Aufzählung ist, dass sie leichter zu lesen ist.
quelle
Wenn die Methode eine Frage stellt wie:
wo
Argumente der booleschen Methode scheinen absolut sinnvoll zu sein.
quelle
Das hängt von der Methode ab. Wenn die Methode etwas tut, das ganz offensichtlich wahr / falsch ist, dann ist es in Ordnung, z. B. unten [obwohl ich nicht sage, dass dies das beste Design für diese Methode ist, ist es nur ein Beispiel dafür, wo die Verwendung offensichtlich ist].
In den meisten Fällen, wie in dem von Ihnen erwähnten Beispiel, ist es jedoch besser, eine Aufzählung zu verwenden. Es gibt viele Beispiele in .NET Framework selbst, in denen diese Konvention nicht befolgt wird. Dies liegt jedoch daran, dass diese Entwurfsrichtlinie erst spät im Zyklus eingeführt wurde.
quelle
Es macht die Dinge ein bisschen expliziter, erweitert aber die Komplexität Ihrer Schnittstellen massiv - bei einer bloßen booleschen Wahl wie Anhängen / Überschreiben scheint es übertrieben. Wenn Sie eine weitere Option hinzufügen müssen (an die ich in diesem Fall nicht denken kann), können Sie jederzeit einen Refactor durchführen (abhängig von der Sprache).
quelle
Aufzählungen können den Code sicherlich lesbarer machen. Es gibt noch ein paar Dinge zu beachten (zumindest in .net)
Da der zugrunde liegende Speicher einer Aufzählung ein int ist, ist der Standardwert Null. Stellen Sie daher sicher, dass 0 ein sinnvoller Standardwert ist. (Zum Beispiel haben Strukturen beim Erstellen alle Felder beim Erstellen auf Null gesetzt, daher gibt es keine Möglichkeit, einen anderen Standard als 0 anzugeben. Wenn Sie keinen 0-Wert haben, können Sie die Aufzählung nicht einmal testen, ohne sie in int umzuwandeln schlechter Stil.)
Wenn Ihre Aufzählungen für Ihren Code privat sind (niemals öffentlich zugänglich gemacht), können Sie hier aufhören zu lesen.
Wenn Ihre Aufzählungen veröffentlicht sind in irgendeiner Weise zu externem Code und / oder außerhalb des Programms gespeichert, können Sie diese explizit Nummerierung. Der Compiler nummeriert sie automatisch von 0, aber wenn Sie Ihre Aufzählungen neu anordnen, ohne ihnen Werte zu geben, können Fehler auftreten.
Ich kann legal schreiben
Um dem entgegenzuwirken, muss jeder Code, der eine Aufzählung verwendet, deren Sie sich nicht sicher sind (z. B. öffentliche API), überprüfen, ob die Aufzählung gültig ist. Sie tun dies über
Die einzige Einschränkung
Enum.IsDefined
ist, dass es Reflexion verwendet und langsamer ist. Es gibt auch ein Versionsproblem. Wenn Sie den Aufzählungswert häufig überprüfen müssen, ist Folgendes besser:Das Versionsproblem besteht darin, dass alter Code möglicherweise nur mit den 2 Aufzählungen umgehen kann. Wenn Sie einen dritten Wert hinzufügen, ist Enum.IsDefined wahr, aber der alte Code kann nicht unbedingt damit umgehen. Hoppla.
Es gibt noch mehr Spaß, den Sie mit
[Flags]
Aufzählungen machen können, und der Validierungscode dafür ist etwas anders.Ich werde auch beachten, dass Sie aus Gründen der Portabilität den Aufruf
ToString()
der Enumeration verwenden undEnum.Parse()
beim Einlesen verwenden sollten. BeideToString()
undEnum.Parse()
können damit umgehen[Flags]
ENUM ist auch, also gibt es keinen Grund , sie nicht zu verwenden. Wohlgemerkt, es ist eine weitere Gefahr, denn jetzt können Sie nicht einmal den Namen der Aufzählung ändern, ohne möglicherweise den Code zu brechen.Manchmal müssen Sie also alles oben Genannte abwägen, wenn Sie sich fragen. Kann ich mit nur einem Narren davonkommen?
quelle
IMHO scheint es, als wäre eine Aufzählung die offensichtliche Wahl für jede Situation, in der mehr als zwei Optionen möglich sind. Aber es gibt definitiv Situationen, in denen ein Boolescher Wert alles ist, was Sie brauchen. In diesem Fall würde ich sagen, dass die Verwendung einer Aufzählung, in der ein Bool funktionieren würde, ein Beispiel für die Verwendung von 7 Wörtern wäre, wenn 4 ausreichen.
quelle
Boolesche Werte sind sinnvoll, wenn Sie einen offensichtlichen Schalter haben, der nur eines von zwei Dingen sein kann (dh den Zustand einer Glühbirne, ein oder aus). Abgesehen davon ist es gut, es so zu schreiben, dass es offensichtlich ist, was Sie übergeben - z. B. Festplattenschreibvorgänge - ungepuffert, zeilengepuffert oder synchron - als solches übergeben werden sollten. Auch wenn Sie jetzt keine synchronen Schreibvorgänge zulassen möchten (und sich daher auf zwei Optionen beschränken), sollten Sie überlegen, sie ausführlicher zu gestalten, um zu wissen, was sie auf den ersten Blick tun.
Sie können jedoch auch False und True (Boolesche Werte 0 und 1) verwenden. Wenn Sie später weitere Werte benötigen, erweitern Sie die Funktion, um benutzerdefinierte Werte (z. B. 2 und 3) und Ihre alten 0/1-Werte zu unterstützen wird gut portieren, so dass Ihr Code nicht brechen sollte.
quelle
Manchmal ist es einfach einfacher, ein anderes Verhalten mit Überlastungen zu modellieren. Um von Ihrem Beispiel fortzufahren, wäre:
Dieser Ansatz verschlechtert sich, wenn Sie mehrere Parameter haben, die jeweils einen festen Satz von Optionen zulassen. Beispielsweise kann eine Methode, die eine Datei öffnet, mehrere Permutationen des Dateimodus (Öffnen / Erstellen), des Dateizugriffs (Lesen / Schreiben) und des Freigabemodus (Keine / Lesen / Schreiben) aufweisen. Die Gesamtzahl der Konfigurationen entspricht den kartesischen Produkten der einzelnen Optionen. In solchen Fällen sind Mehrfachüberlastungen natürlich nicht angebracht.
Aufzählungen können in einigen Fällen die Lesbarkeit von Code verbessern, obwohl es schwierig sein kann, den genauen Aufzählungswert in einigen Sprachen (z. B. C #) zu überprüfen.
Oft wird ein boolescher Parameter als neue Überladung an die Liste der Parameter angehängt. Ein Beispiel in .NET ist:
Die letztere Überlastung wurde in einer späteren Version des .NET-Frameworks als die erste verfügbar.
Wenn Sie wissen, dass es immer nur zwei Möglichkeiten gibt, ist ein Boolescher Wert möglicherweise in Ordnung. Aufzählungen sind so erweiterbar, dass alter Code nicht beschädigt wird, obwohl alte Bibliotheken möglicherweise keine neuen Aufzählungswerte unterstützen, sodass die Versionierung nicht vollständig ignoriert werden kann.
BEARBEITEN
In neueren Versionen von C # können benannte Argumente verwendet werden, die IMO das Aufrufen von Code auf die gleiche Weise wie Aufzählungen klarer machen können. Verwenden Sie das gleiche Beispiel wie oben:
quelle
Wo ich zustimme, dass Aufzählungen ein guter Weg sind, bei Methoden, bei denen Sie zwei Optionen haben (und nur zwei Optionen, können Sie ohne Aufzählung lesbar sein).
z.B
Ich liebe die Aufzählungen, aber Boolesche Werte sind auch nützlich.
quelle
Dies ist ein später Eintrag in einem alten Beitrag, und er befindet sich so weit unten auf der Seite, dass niemand ihn jemals lesen wird, aber da niemand ihn bereits gesagt hat ...
Ein Inline-Kommentar trägt wesentlich zur Lösung des unerwarteten
bool
Problems bei. Das ursprüngliche Beispiel ist besonders abscheulich: Stellen Sie sich vor, Sie versuchen, die Variable in der Funktionsdeklaration zu benennen! Es wäre so etwas wieNehmen wir zum Beispiel an, das ist die Erklärung. Dann habe ich für ein ansonsten ungeklärtes boolesches Argument den Variablennamen in einen Inline-Kommentar eingefügt. Vergleichen Sie
mit
quelle
Es hängt wirklich von der genauen Art des Arguments ab. Wenn es kein Ja / Nein oder Wahr / Falsch ist, wird es durch eine Aufzählung besser lesbar. Bei einer Aufzählung müssen Sie jedoch das Argument überprüfen oder ein akzeptables Standardverhalten aufweisen, da undefinierte Werte des zugrunde liegenden Typs übergeben werden können.
quelle
Die Verwendung von Aufzählungen anstelle von Booleschen Werten in Ihrem Beispiel trägt dazu bei, dass der Methodenaufruf besser lesbar ist. Dies ist jedoch ein Ersatz für mein Lieblingswunschelement in C #, benannte Argumente in Methodenaufrufen. Diese Syntax:
wäre perfekt lesbar, und Sie könnten dann tun, was ein Programmierer tun sollte, dh den am besten geeigneten Typ für jeden Parameter in der Methode auswählen, unabhängig davon, wie er in der IDE aussieht.
C # 3.0 erlaubt benannte Argumente in Konstruktoren. Ich weiß nicht, warum sie das nicht auch mit Methoden machen können.
quelle
Boolesche Werte
true
/false
nur. Es ist also nicht klar, was es darstellt.Enum
kann aussagekräftige Namen haben, zBOVERWRITE
,APPEND
usw. So Aufzählungen sind besser.quelle