Frage

Ein Kollege von mir heißt es, dass booleans als Methodenargumente sind nicht akzeptabel . Sie werden von Aufzählungen ersetzt werden. 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 habe ich es! ;-)
Dies ist definitiv ein Beispiel, wo eine Aufzählung als zweiter Parameter den Code viel besser lesbar macht.

Also, was ist Ihre Meinung zu diesem Thema?

War es hilfreich?

Lösung

Boolean der repräsentieren "Ja / Nein" Entscheidungen. Wenn Sie ein „Ja / Nein“ darstellen wollen, dann einen boolean verwenden, sollte es selbsterklärend sein.

Aber wenn es eine Wahl zwischen zwei Möglichkeiten, von denen keines eindeutig ja oder nein, dann einer ENUM kann manchmal besser lesbar sein.

Andere Tipps

Aufzählungen auch für zukünftige Modifikationen ermöglichen, in dem Sie nun eine dritte Wahl wollen (oder mehr).

Verwenden Sie die am besten Modelle Ihr Problem. Im Beispiel Sie geben, ist die Enum eine bessere Wahl. Allerdings wäre es auch andere Zeiten, in denen ein boolean ist besser. Welche mehr Sinn macht für Sie:

lock.setIsLocked(True);

oder

enum LockState { Locked, Unlocked };
lock.setLockState(Locked);

In diesem Fall könnte ich die boolean Option wählen, da ich denke, es ist ganz klar und eindeutig sein, und ich bin mir ziemlich sicher, dass meine Sperre wird nicht mehr als zwei Zustände hat. Dennoch ist die zweite Wahl gültig, aber unnötig kompliziert, IMHO.

Ich glaube, Sie dies fast beantwortet sich selbst, ich denke, das Ende Ziel ist der Code besser lesbar zu machen, und in diesem Fall ist die Enum täte, IMO seine immer am besten, am Ende aussehen wollen, anstatt Decke Regeln, denken vielleicht davon mehr als Richtlinie sind also Aufzählungen oft besser lesbar in Code als generische bools, ints usw., aber es werden immer Ausnahmen von der Regel sein.

Denken Sie daran, die Frage Adlai Stevenson bei den Vereinten Nationen während des Kubanische Rakete Botschafter Zorin gestellt Krise ?

  

"Sie befinden sich im Saal der Welt   jetzt Meinung, und Sie können antworten    Ja oder Nein . Sie haben bestritten, dass [die Raketen]   existieren, und ich möchte wissen, ob ich   Sie richtig verstanden habe .... Ich bin   bereit, auf meine Antwort zu warten, bis   Hölle zufriert, wenn das Ihr   Entscheidung. "

Wenn das Flag Sie in Ihrer Methode haben, ist so beschaffen, dass man es bis zu einer binäre Entscheidung kann pinnen , und diese Entscheidung wird nie verwandeln sich in eine drei -Wege oder n-Wege-Entscheidung für boolean gehen. Indikationen: Ihre Flagge heißt isXXX .

Sie machen es bei etwas nicht boolean, die ein Modusschalter . Es gibt immer einen weiteren Modus , als Sie gedacht, wenn du in erster Linie die Methode zu schreiben.

Das Ein-mehr-Modus Dilemma hat z.B. frequentiert Unix, wo die mögliche Erlaubnis, eine Datei oder ein Verzeichnis-Modi können je nach Dateityp heute Ergebnis in seltsamen Zweideutigkeiten von Modi haben, Eigentum etc.

Für mich weder mit boolean noch Aufzählung ist ein guter Ansatz. Robert C. Martin fängt dies sehr deutlich in seinem Clean Code Tipp # 12: Beseitigen Sie Boolesche Argumente :

  

Boolesche Argumente erklären laut, dass die Funktion mehr als eine Sache tut. Sie sind verwirrend und sollte beseitigt werden.

Wenn eine Methode mehr als eine Sache tut, sollen Sie lieber schreiben zwei verschiedene Methoden, zum Beispiel in Ihrem Fall. file.append(data) und file.overwrite(data)

eine Aufzählung verwendet nicht die Dinge klarer machen. Es ändert nichts, es ist immer noch ein Flag Argument.

Es gibt zwei Gründe, warum ich habe in dieser ist eine schlechte Sache laufen:

  1. Da einige Menschen Methoden schreiben werden wie:

    ProcessBatch(true, false, false, true, false, false, true);
    

    Das ist natürlich schlecht, weil es zu einfach ist, Parameter zu mischen, und Sie haben keine Ahnung von ihm zu betrachten, was Sie angeben. obwohl nur ein Bool ist nicht so schlecht.

  2. Weil Programmablauf durch eine einfache Ja Steuerung / Nein-Zweig könnte bedeuten, Sie zwei völlig unterschiedliche Funktionen haben, die bis zu einem in einer awkard Weise gewickelt sind. Zum Beispiel:

    public void Write(bool toOptical);
    

    Wirklich, sollte dies zwei Methoden sein

    public void WriteOptical();
    public void WriteMagnetic();
    

    , da der Code in diese könnten ganz unterschiedlich sein können; sie könnten alle Arten von verschiedener Fehlerbehandlung zu tun haben und die Validierung, oder vielleicht sogar anders die abgehenden Daten formatiert werden müssen. Sie können nicht sagen, nur durch Write() oder sogar Write(Enum.Optical) (obwohl natürlich Sie eine dieser beiden Methoden haben könnten nur interne Methoden aufrufen WriteOptical / Mag, wenn Sie möchten).

Ich denke, es hängt nur davon. Ich würde nicht zu große Sache über sie machen bis auf # 1.

Aufzählungen sind besser, aber ich würde nicht boolean params als „inakzeptabel“ nennen. Manchmal ist es nur einfacher, ein wenig boolean in werfen und weiterziehen (man denke an private Methoden etc.)

Boolesche Werte können in Sprachen in Ordnung sein, die Parameter benannt haben, wie Python und Objective-C, da der Name erklären, was der Parameter tut:

file.writeData(data, overwrite=true)

oder:

[file writeData:data overwrite:YES]

würde ich nicht darüber einig, dass es eine gute ist Regel . Offensichtlich macht Enum für einen besseren expliziten oder ausführlichen Code in einigen Fällen, aber in der Regel scheint es weit über erreichen.

Lassen Sie mich zuerst Ihr Beispiel nehmen: Die Programmierer Verantwortung (und Fähigkeit) guten Code zu schreiben, indem er einen Booleschen Parameter nicht wirklich gefährdet. In Ihrem Beispiel könnte der Programmierer nur so ausführlich Code durch Schreiben geschrieben haben:

dim append as boolean = true
file.writeData( data, append );

oder ich ziehe allgemeinere

dim shouldAppend as boolean = true
file.writeData( data, shouldAppend );

An zweiter Stelle: Das Enum Beispiel Sie gab nur „besser“, weil Sie eine CONST sind vorbei. Wahrscheinlich in den meisten Anwendungszumindest einige, wenn nicht die meisten der Zeitparameter, die an Funktionen übergeben werden VARIABLES sind. wobei in diesem Fall mein zweites Beispiel (was Variablen mit guten Namen) ist viel besser und Enum würden Sie wenig Vorteile gegeben haben.

Aufzählungen haben einen bestimmten Nutzen, aber Sie should't nur alle booleans mit Aufzählungen gehen zu ersetzen. Es gibt viele Orte, an denen wahr / falsch eigentlich der beste Weg ist, um darzustellen, was los ist.

Doch sie als Methodenargumente verwendet, ist ein wenig suspekt, einfach weil man nicht ohne graben in die Dinge sehen, was sie tun sollen, wie sie können Sie sehen, was die wahr / falsch bedeutet eigentlich

Eigenschaften (insbesondere mit C # 3 Objektinitialisierer) oder Keyword-Argumenten (a la Rubin oder Python) sind ein viel besserer Weg zu gehen, wo man sonst ein boolean Argument verwenden würde.

C # Beispiel:

var worker = new BackgroundWorker { WorkerReportsProgress = true };

Ruby-Beispiel

validates_presence_of :name, :allow_nil => true

Python Beispiel

connect_to_database( persistent=true )

Das einzige, was ich denken kann, wo ein boolean Methode Argument ist das Richtige zu tun, ist in Java, wo Sie weder Eigenschaften oder Keyword-Argumente haben. Dies ist einer der Gründe, warum ich hasse java: - (

Es stimmt zwar, dass in vielen Fällen Aufzählungen sind besser lesbar und dehnbarer als booleans, eine absolute Regel, dass „booleans nicht akzeptabel ist“ ist bescheuert. Es ist unflexibel und kontraproduktiv - es läßt keinen Raum für menschliches Urteil. Sie sind ein fundamentales in den meisten Sprachen in Art gebaut, weil sie nützlich sind - halten es für andere integrierte-Typen Anwendung. Sagen, zum Beispiel würde „niemals einen int als Parameter verwenden“ nur verrückt sein

Diese Regel ist nur eine Frage des Stils, nicht Potenzial für Fehler oder Laufzeit-Performance. Eine bessere Regel wäre „Aufzählungen zu booleans aus Gründen der Lesbarkeit bevorzugen“.

Sehen Sie sich das .Net-Framework. Boolesche Werte werden als Parameter auf ziemlich viele Methoden verwendet. Der .NET-API ist nicht perfekt, aber ich glaube nicht, dass die Verwendung von boolean als Parameter ein großes Problem ist. Der Tooltip gibt Ihnen immer den Namen des Parameters, und Sie können diese Art von Führung bauen zu -. Geben Sie Ihre XML-Kommentare zu den Verfahrensparametern, sie im Tooltip werden kommen

Ich möchte auch hinzufügen, dass es einen Fall gibt, wenn Sie eindeutig booleans zu einer Aufzählung Refactoring sollte - wenn Sie zwei oder mehr booleans auf Ihrer Klasse oder in Ihrer Methode params, und nicht alle Staaten gelten (zB es ist nicht gültig sie haben beide festgelegt true).

Zum Beispiel, wenn Ihre Klasse hat Eigenschaften wie

public bool IsFoo
public bool IsBar

Und es ist ein Fehler wahr beide haben zur gleichen Zeit, was Sie tatsächlich hat drei gültige Zustände, ausgedrückt besser als so etwas wie:

enum FooBarType { IsFoo, IsBar, IsNeither };

Einige Regeln, die Ihr Kollege besser haften sein könnte, sind:

  • Sie mit Ihrem Entwurf nicht dogmatisch sein.
  • Wählen Sie, was passt am geeignetsten für die Benutzer Ihres Codes.
  • Versuchen Sie nicht zu bash sternförmigen Zapfen in jedes Loch, nur weil Sie die Form wie in diesem Monat!

Ein boolescher wäre nur dann akzeptabel, wenn Sie die Funktionalität des Rahmens zu verlängern beabsichtigen nicht. Die Enum ist bevorzugt, weil Sie die Enum erstrecken können und nicht frühere Implementierungen des Funktionsaufrufes durchbrechen.

Der andere Vorteil des Enum ist, dass leichter zu lesen ist.

Wenn die Methode eine Frage stellt, wie zum Beispiel:

KeepWritingData (DataAvailable());

Dabei steht

bool DataAvailable()
{
    return true; //data is ALWAYS available!
}

void KeepWritingData (bool keepGoing)
{
   if (keepGoing)
   {
       ...
   }
}

boolean Methode Argumente scheinen absolut perfekt Sinn zu machen.

Es hängt von der Methode. Wenn die Methode etwas tut, das ganz offensichtlich ein wahr / falsch daran ist, dann ist es in Ordnung, z.B. unter [wenn auch nicht ich sage nicht, das ist das beste Design für diese Methode ist, es ist nur ein Beispiel, wo die Nutzung liegt auf der Hand].

CommentService.SetApprovalStatus(commentId, false);

Doch in den meisten Fällen, wie das Beispiel, das Sie erwähnen, ist es besser, eine Aufzählung zu verwenden. Es gibt viele Beispiele in .NET Framework selbst, wo diese Konvention nicht gefolgt ist, aber das ist, weil sie diese Designrichtlinien eingeführt ziemlich spät im Zyklus.

Es tut Dinge ein wenig deutlicher machen, aber nicht gestartet massiv die Komplexität Ihrer Schnittstellen zu erweitern - in einer schieren boolean Wahl wie Anfügen / Überschreiben wie übertrieben scheint. Wenn Sie eine weitere Option hinzufügen müssen (was ich nicht in diesem Fall denken kann), können Sie immer ein Refactoring durchführen (je nach Sprache)

Aufzählungen können sicherlich den Code besser lesbar machen. Es gibt noch ein paar Dinge zu achten gilt (in .net mindestens)

Da der zugrunde liegende Speicher eines ENUM ist ein int, wird der Standardwert Null sein, so sollten Sie sicherstellen, dass 0 ein vernünftiger Standard ist. (ZB structs haben alle Felder auf Null gesetzt, wenn erstellt, so gibt es keine Möglichkeit, eine Standard andere als 0 angeben, wenn Sie nicht über einen Wert 0 haben, können Sie nicht einmal die Enum testen, ohne, int zu Gießen welche wäre stillos.)

Wenn Ihr Enum Privat sind, um Ihren Code (nie öffentlich ausgesetzt ist), dann können Sie hier aufhören zu lesen.

Wenn Ihre Aufzählungen sind veröffentlicht in irgendeine Weise zu externem Code und / oder außerhalb des Programms gespeichert, können Sie diese explizit Nummerierung. Der Compiler automatisch Zahlen sie von 0, aber wenn Sie Ihre Aufzählungen neu anordnen ohne ihnen Werte, die Sie mit Defekten am Ende kann.

Ich kann legal schreiben

WriteMode illegalButWorks = (WriteMode)1000000;
file.Write( data, illegalButWorks );

Um dies zu bekämpfen, jeder Code, der eine ENUM verbraucht, die Sie nicht sicher (z öffentlich API) sein können, muss prüfen, ob die Enum gültig ist. Sie tun dies über

if (!Enum.IsDefined(typeof(WriteMode), userValue))
    throw new ArgumentException("userValue");

Die einzige Einschränkung von Enum.IsDefined ist, dass es verwendet Reflektion und ist langsamer. Es leidet auch eine Versionierung Problem. Wenn Sie oft den ENUM-Wert zu überprüfen, würden Sie besser dran, wie folgt vor:

public static bool CheckWriteModeEnumValue(WriteMode writeMode)
{
  switch( writeMode )
  {
    case WriteMode.Append:
    case WriteMode.OverWrite:
      break;
    default:
      Debug.Assert(false, "The WriteMode '" + writeMode + "' is not valid.");
      return false;
  }
  return true;
}

Die Versionierung Problem ist, dass alte Code kann nur wissen, wie die 2 Aufzählungen zu handhaben Sie haben. Wenn Sie einen dritten Wert hinzufügen, wird Enum.IsDefined wahr sein, aber der alte Code nicht unbedingt umgehen kann. Whoops.

Es gibt noch mehr Spaß Sie mit [Flags] Aufzählungen tun können, und der Validierungscode für das ist etwas anders.

Ich werde beachten Sie, dass auch für die Portabilität, sollten Sie Anruf ToString() auf der ENUM nutzen, und Enum.Parse() verwenden, wenn sie wieder in das Lesen. Sowohl ToString() und Enum.Parse() [Flags] Enum der auch behandeln kann, so gibt es keinen Grund, sie nicht zu verwenden. Wohlgemerkt, es ist noch eine weitere Gefahr, weil Sie jetzt nicht einmal den Namen der Enumeration ändern kann, ohne möglicherweise Code zu brechen.

Also, manchmal müssen Sie alle oben in wiegen, wenn Sie sich fragen, Kann ich weg mit nur einem Bool?

IMHO scheint es wie eine Enumeration die offensichtliche Wahl für jede Situation sein würde, in denen mehr als zwei Optionen möglich sind. Aber es gibt definitiv Situationen, in denen ein boolean ist alles, was Sie brauchen. In diesem Fall würde ich sagen, dass eine Enumeration mit dem ein Bool ein Beispiel unter Verwendung von 7 Worten wäre funktionieren würde, wenn 4 tun wird.

Boolesche Werte machen Sinn, wenn man eine offensichtliche Toggle hat, die nur eines von zwei Dingen sein können (das heißt der Zustand einer Glühbirne, an oder aus). Other than that, ist es gut, es so zu schreiben, dass es offensichtlich ist, was Sie vorbei - z.B. Platte schreibt - ungepufferte, Line-gepuffert, oder synchron - sollten als solche übergeben werden. Auch wenn Sie jetzt nicht synchrone Schreibvorgänge erlauben wollen (und so sind Sie auf zwei Möglichkeiten begrenzt), ist es eine Überlegung wert, so dass sie ausführlicher für die Zwecke, zu wissen, was sie auf den ersten Blick zu tun.

Das heißt, Sie auch falsch und True (boolean 0 und 1) und dann verwenden, wenn Sie mehrere Werte müssen später, erweitern Sie die Funktion aus benutzerdefinierten Werte unterstützen (sagen wir, 2 und 3), und die alte 0 schön / 1 Werte portieren über, so sollten Sie den Code brechen nicht.

Manchmal ist es nur einfacher, unterschiedliches Verhalten mit Überlastungen zu modellieren. Um weiterhin von Ihrem Beispiel wäre:

file.appendData( data );  
file.overwriteData( data );

Dieser Ansatz verschlechtert, wenn Sie mehrere Parameter, die jeweils einen festen Satz von Optionen ermöglicht. Zum Beispiel kann ein Verfahren, das eine Datei öffnet möglicherweise mehrere Permutationen von Dateimodus haben (offen / erstellen), Dateizugriff (Lesen / Schreiben), den Austausch-Modus (keine / lesen / schreiben). Die Gesamtzahl der Konfigurationen ist gleich der cartesianischen Produkte der einzelnen Optionen. Natürlich in solchen Fällen mehr Überlastungen nicht geeignet ist.

Aufzählungen können in einigen Fällen machen Code besser lesbar, obwohl den genauen Enum-Wertes in einigen Sprachen (C # zum Beispiel) Validierung kann schwierig sein.

Oft wird ein boolean Parameter wird als eine neue Überlastung in der Liste der Parameter angehängt. Ein Beispiel in .NET ist:

Enum.Parse(str);  
Enum.Parse(str, true); // ignore case

Diese Überlastung wurde in einer späteren Version des .NET-Frameworks als die ersten zur Verfügung.

Wenn Sie wissen, dass es immer nur zwei Möglichkeiten, ein boolean könnte in Ordnung sein. Aufzählungen sind in einer Art und Weise erweiterbar, die nicht alten Code brechen, obwohl alte Bibliotheken keine neue ENUM-Werte unterstützen könnten, so kann die Versionierung nicht völlig außer Acht gelassen werden.


Bearbeiten

In neueren Versionen von C # ist es möglich, benannte Argumente zu verwenden, die, IMO, machen Code klarer auf die gleiche Art und Weise fordern, dass Aufzählungen können. Mit dem gleichen Beispiel wie oben:

Enum.Parse(str, ignoreCase: true);

Wo ich damit einverstanden, dass Aufzählungen guter Weg sind in Methoden zu gehen, wo Sie zwei Möglichkeiten (und nur zwei Optionen können Sie die Lesbarkeit ohne Enum haben.)

z.

public void writeData(Stream data, boolean is_overwrite)

Liebe der Aufzählungen, aber boolean ist auch nützlich.

Dies ist eine Nachmeldung auf einem alten Post, und es ist so weit unten auf der Seite, dass niemand es jemals lesen werden, aber da niemand gesagt hat es schon ....

Ein Inline-Kommentar geht ein langer Weg, um das unerwartete bool Problem zu lösen. Das ursprüngliche Beispiel ist besonders abscheulich: Stellen Sie versuchen, die Variable in der Funktion declearation zu nennen! Es wäre so etwas wie

void writeData( DataObject data, bool use_append_mode );

Aber im Interesse des Beispiels, sagen sie, das ist die Erklärung. Dann wird für ein ansonsten unerklärliches boolean Argument, habe ich die Variablennamen in einem Inline-Kommentar. Vergleichen

file.writeData( data, true );

mit

file.writeData( data, true /* use_append_mode */);

Es hängt wirklich von der genauen Beschaffenheit des Arguments. Wenn es nicht ein ja / nein oder wahr / falsch dann eine ENUM macht es besser lesbar. Aber mit einem Enum müssen Sie das Argument überprüfen oder zu akzeptablen Standardverhalten haben, da undefinierte Werte des zugrunde liegenden Typs übergeben werden.

Die Verwendung von Aufzählungen statt booleans in Ihrem Beispiel hilft den Aufruf der Methode besser lesbar zu machen. Dies ist jedoch ein Ersatz für meine Lieblings wünschen Artikel in C #, benannte Argumente in Methodenaufrufe. Diese Syntax:

var v = CallMethod(pData = data, pFileMode = WriteMode, pIsDirty = true);

wäre perfekt lesbar sein, und Sie könnten dann tun, was ein Programmierer tun soll, das ist der am besten geeigneten Typen für jeden Parameter in dem Verfahren ohne Rücksicht wählen, wie es aussieht, ist in der IDE.

C # 3.0 ermöglicht Argumente in Konstrukteuren benannt. Ich weiß nicht, warum sie können dies auch mit Methoden nicht tun.

Boolesche Werte true / false nur. So ist es nicht klar, was es darstellen. Enum kann aussagekräftige Namen haben, z OVERWRITE, APPEND, etc. So Aufzählungen sind besser.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top