Ich habe von Zeit zu Zeit eine Übung gesehen, die sich "falsch" anfühlt, aber ich kann nicht genau artikulieren, was daran falsch ist. Oder vielleicht ist es nur mein Vorurteil. Hier geht:
Ein Entwickler definiert eine Methode mit einem Booleschen Wert als einen ihrer Parameter, und diese Methode ruft einen anderen auf. Dieser Boolesche Wert wird schließlich nur verwendet, um zu bestimmen, ob eine bestimmte Aktion ausgeführt werden soll oder nicht. Dies kann zum Beispiel verwendet werden, um die Aktion nur dann zuzulassen, wenn der Benutzer bestimmte Rechte besitzt oder wenn wir uns im Testmodus, Batch-Modus oder Live-Modus befinden (oder nicht) oder wenn sich das System in einem befindet bestimmter Zustand.
Nun, es gibt immer eine andere Möglichkeit, dies zu tun, sei es durch Abfragen, wann es Zeit ist, die Aktion auszuführen (anstatt den Parameter zu übergeben), oder durch mehrere Versionen der Methode oder mehrere Implementierungen der Klasse usw. Meine Frage ist nicht Es geht nicht so sehr darum, dies zu verbessern, sondern vielmehr darum, ob es wirklich falsch ist (wie ich vermute), und wenn ja, was ist daran falsch?
Antworten:
Ja, dies ist wahrscheinlich ein Codegeruch, der zu nicht wartbarem Code führen würde, der schwer zu verstehen ist und dessen Wahrscheinlichkeit geringer ist, leicht wiederverwendet zu werden.
Wie andere Plakate bereits festgestellt haben, ist der Kontext alles (gehen Sie nicht zu grob, wenn er einmalig ist oder wenn die Praxis als absichtlich entstandene technische Verschuldung eingestuft wurde, die später überarbeitet werden soll), sondern im Großen und Ganzen, wenn ein Parameter übergeben wird in eine Funktion, die ein bestimmtes auszuführendes Verhalten auswählt, ist eine weitere schrittweise Verfeinerung erforderlich; Wenn Sie diese Funktion in kleinere Funktionen aufteilen, erhalten Sie stärker zusammenhängende Funktionen.
Was ist also eine sehr zusammenhängende Funktion?
Es ist eine Funktion, die nur eine Sache und eine Sache tut.
Das Problem mit einem Parameter, der wie beschrieben übergeben wird, besteht darin, dass die Funktion mehr als zwei Dinge ausführt. Abhängig vom Status des Booleschen Parameters kann er die Zugriffsrechte des Benutzers überprüfen oder nicht. Abhängig von diesem Entscheidungsbaum führt er eine Funktionalität aus.
Es wäre besser, die Belange der Zugriffskontrolle von den Belangen der Aufgabe, Aktion oder des Befehls zu trennen.
Wie Sie bereits bemerkt haben, scheint die Verflechtung dieser Bedenken nicht in Ordnung zu sein.
Der Begriff der Kohäsivität hilft uns zu identifizieren, dass die fragliche Funktion nicht sehr kohäsiv ist und dass wir den Code umgestalten könnten, um eine Reihe von kohäsiveren Funktionen zu erzeugen.
Die Frage könnte also erneut gestellt werden. Angesichts der Tatsache, dass wir uns alle einig sind, dass die Übergabe von Verhaltensauswahlparametern am besten vermieden wird, wie können wir die Situation verbessern?
Ich würde den Parameter komplett loswerden. Die Möglichkeit, die Zugriffskontrolle auch für Testzwecke auszuschalten, ist ein potenzielles Sicherheitsrisiko. Zu Testzwecken können Sie die Zugriffsprüfung entweder stummschalten oder verspotten , um sowohl das Szenario "Zugriff erlaubt" als auch das Szenario "Zugriff verweigert" zu testen.
Ref: Kohäsion (Informatik)
quelle
Ich habe dieses Muster vor langer Zeit aus einem sehr einfachen Grund nicht mehr verwendet. Wartungskosten. Mehrmals stellte ich fest, dass ich eine Funktion hatte,
frobnicate(something, forwards_flag)
die mehrfach in meinem Code aufgerufen wurde, und alle Stellen im Code suchen musste, an denen der Wertfalse
als Wert von übergeben wurdeforwards_flag
. Sie können nicht einfach danach suchen, was zu Wartungsproblemen führt. Und wenn Sie an jeder dieser Sites einen Bugfix vornehmen müssen, kann es sein, dass Sie ein unglückliches Problem haben, wenn Sie eines verpassen.Dieses spezifische Problem lässt sich jedoch leicht beheben, ohne den Ansatz grundlegend zu ändern:
Mit diesem Code müsste man nur nach Instanzen von suchen
FrobnicateBackwards
. Es ist zwar möglich, dass es einen Code gibt, der dies einer Variablen zuweist, so dass Sie ein paar Steuerthreads folgen müssen. In der Praxis ist dies jedoch so selten, dass diese Alternative in Ordnung ist.Es gibt jedoch ein anderes Problem, die Flagge zumindest im Prinzip auf diese Weise zu übergeben. Dies liegt daran, dass einige (nur einige) Systeme mit diesem Design möglicherweise zu viel Wissen über die Implementierungsdetails der tief verschachtelten Teile des Codes (der das Flag verwendet) an die äußeren Schichten weitergeben (die wissen müssen, welcher Wert übergeben werden soll) in dieser Flagge). Um die Terminologie von Larry Constantine zu verwenden, besteht möglicherweise eine zu starke Kopplung zwischen dem Setter und dem Benutzer der Booleschen Flagge. Franky, obwohl es schwierig ist, diese Frage mit Sicherheit zu beantworten, ohne mehr über die Codebasis zu wissen.
Um auf die konkreten Beispiele einzugehen, die Sie nennen, hätte ich in jeder Hinsicht einige Bedenken, jedoch hauptsächlich aus Gründen des Risikos / der Richtigkeit. Das heißt, wenn Ihr System Flags weitergeben muss, die angeben, in welchem Zustand sich das System befindet, stellen Sie möglicherweise fest, dass Sie Code haben, der dies hätte berücksichtigen sollen, den Parameter jedoch nicht überprüft (da er nicht an übergeben wurde) diese Funktion). Sie haben also einen Fehler, weil jemand den Parameter nicht übergeben hat.
Man muss auch zugeben, dass ein Systemstatusindikator, der an fast jede Funktion übergeben werden muss, im Wesentlichen eine globale Variable ist. Viele der Nachteile einer globalen Variablen werden zutreffen. Ich denke, in vielen Fällen ist es besser, die Kenntnis des Systemzustands (oder der Anmeldeinformationen des Benutzers oder der Systemidentität) in einem Objekt zu kapseln, das dafür verantwortlich ist, auf der Grundlage dieser Daten korrekt zu handeln. Dann übergeben Sie einen Verweis auf dieses Objekt im Gegensatz zu den Rohdaten. Das Schlüsselkonzept ist hier die Kapselung .
quelle
bool
Parameter hinzugefügt wurden und die Aufrufe so aussehenDoSomething( myObject, false, false, true, false )
. Es ist unmöglich herauszufinden, was die zusätzlichen booleschen Argumente bedeuten, während es mit sinnvoll benannten Enum-Werten einfach ist.Dies ist nicht unbedingt falsch, kann aber einen Codegeruch darstellen .
Das grundlegende Szenario, das in Bezug auf boolesche Parameter vermieden werden sollte, ist:
Wenn Sie dann anrufen, rufen Sie normalerweise an
foo(false)
und dasfoo(true)
hängt von dem genauen Verhalten ab, das Sie möchten.Dies ist wirklich ein Problem, da es sich um einen schlechten Zusammenhalt handelt. Sie erstellen eine Abhängigkeit zwischen Methoden, die nicht wirklich erforderlich ist.
Was Sie in diesem Fall tun sollten, ist verlassen
doThis
unddoThat
als separate und öffentliche Methoden dann tun:oder
Auf diese Weise überlassen Sie die richtige Entscheidung dem Aufrufer (genau so, als würden Sie einen booleschen Parameter übergeben), ohne eine Kopplung zu erstellen.
Natürlich werden nicht alle booleschen Parameter so schlecht verwendet, aber es ist definitiv ein Codegeruch und Sie haben Recht, misstrauisch zu werden, wenn Sie das viel im Quellcode sehen.
Dies ist nur ein Beispiel für die Lösung dieses Problems anhand der von mir geschriebenen Beispiele. In anderen Fällen ist ein anderer Ansatz erforderlich.
Es gibt einen guten Artikel von Martin Fowler , der die gleiche Idee ausführlicher erklärt.
PS: Wenn Methode
foo
anstelle von zwei einfachen Methoden eine komplexere Implementierung hatte, müssen Sie nur eine kleine Refactoring- Extraktionsmethode anwenden , damit der resultierende Code der vonfoo
mir geschriebenen Implementierung ähnelt .quelle
if (flag) doThat()
Innerefoo()
legitim ist.doThat()
Wenn Sie die Entscheidung über das Aufrufen an jeden Aufrufer weitergeben, wird die Wiederholung erzwungen, die entfernt werden muss, wenn Sie später herausfinden, welche Methoden verwendet werden, und dasflag
Verhalten muss ebenfalls aufgerufen werdendoTheOther()
. Ich würde viel lieber Abhängigkeiten zwischen Methoden in dieselbe Klasse setzen, als später alle Aufrufer durchsuchen zu müssen.doOne
unddoBoth
-Methoden (für den falschen bzw. den wahren Fall) oder die Verwendung eines separaten Aufzählungstyps, wie von James Youngman vorgeschlagendoOne()
oderdoBoth()
-Entscheidung zu treffen. Unterprogramme / Funktionen / Methoden haben Argumente, so dass ihr Verhalten variiert werden kann. Die Verwendung einer Aufzählung für eine wirklich boolesche Bedingung klingt nach einer Wiederholung, wenn der Name des Arguments bereits erklärt, was es bewirkt.Zunächst einmal: Programmieren ist weniger eine Wissenschaft als vielmehr eine Kunst. Es gibt also sehr selten einen "falschen" und einen "richtigen" Weg, um zu programmieren. Die meisten Codierungsstandards sind lediglich "Einstellungen", die einige Programmierer für nützlich halten. aber letztendlich sind sie eher willkürlich. Daher würde ich eine Parameterauswahl niemals als an und für sich "falsch" bezeichnen - und schon gar nicht als etwas, das so allgemein und nützlich ist wie ein boolescher Parameter. Die Verwendung eines
boolean
(oder einesint
) zur Verkapselung von Zuständen ist in vielen Fällen durchaus gerechtfertigt.Kodierungsentscheidungen sollten im Großen und Ganzen in erster Linie auf Leistung und Wartbarkeit basieren. Wenn die Leistung nicht auf dem Spiel steht (und ich kann mir nicht vorstellen, wie sie jemals in Ihren Beispielen aussehen könnte), sollte Ihre nächste Überlegung lauten: Wie einfach ist dies für mich (oder einen zukünftigen Redakteur) zu warten? Ist es intuitiv und verständlich? Ist es isoliert? Ihr Beispiel für verkettete Funktionsaufrufe scheint in dieser Hinsicht tatsächlich potenziell spröde zu sein: Wenn Sie sich für eine Änderung von
bIsUp
in entscheidenbIsDown
, wie viele andere Stellen im Code müssen ebenfalls geändert werden? Auch steigt Ihre Parameterliste im Ballon auf? Wenn Ihre Funktion 17 Parameter hat, ist die Lesbarkeit ein Problem, und Sie müssen überdenken, ob Sie die Vorteile der objektorientierten Architektur schätzen.quelle
Ich denke, Robert C. Martins Clean-Code-Artikel besagt, dass Sie boolesche Argumente, wenn möglich, entfernen sollten, da sie zeigen, dass eine Methode mehr als eine Sache tut. Eine Methode sollte eine Sache tun und nur eine Sache, die ich denke, ist eines seiner Mottos.
quelle
Ich denke, das Wichtigste hier ist, praktisch zu sein.
Wenn der Boolesche Wert das gesamte Verhalten bestimmt, erstellen Sie einfach eine zweite Methode.
Wenn der Boolesche Wert nur ein wenig Verhalten in der Mitte festlegt, möchten Sie ihn möglicherweise in einem Zustand belassen, um die Codeduplizierung zu verringern. Möglicherweise können Sie die Methode sogar in drei aufteilen: Zwei aufrufende Methoden für eine der beiden booleschen Optionen und eine, die den Großteil der Arbeit erledigt.
Zum Beispiel:
Natürlich haben Sie in der Praxis immer einen Punkt zwischen diesen Extremen. Normalerweise gehe ich einfach mit dem um, was sich richtig anfühlt, aber ich bevorzuge es, auf der Seite weniger Code-Duplizierung zu irren.
quelle
FooInternal
in der Zukunft zu erhöhen , was dann?Foo1
wird:{ doWork(); HandleTrueCase(); doMoreWork() }
. Im Idealfall werden die FunktionendoWork
unddoMoreWork
jeweils in (einen oder mehrere) bedeutungsvolle Teile diskreter Aktionen (dh als separate Funktionen) unterteilt, und nicht nur in zwei Funktionen, um sie aufzuteilen.Mir gefällt der Ansatz, das Verhalten mithilfe von Builder-Methoden anzupassen, die unveränderliche Instanzen zurückgeben. So benutzt Guava
Splitter
es:Die Vorteile davon sind:
Splitter
. Sie würden niemalssomeVaguelyStringRelatedOperation(List<Entity> myEntities)
eine Klasse mit dem NamenSplitter
einfügen, aber Sie würden darüber nachdenken, sie als statische Methode in eineStringUtils
Klasse einzufügen.true
oder übergebenfalse
werden soll, um das richtige Verhalten zu erzielen.quelle
Auf jeden Fall ein Codegeruch . Wenn es nicht gegen das Prinzip der Einzelverantwortung verstößt , verstößt es wahrscheinlich gegen Tell, Don't Ask . Erwägen:
Wenn sich herausstellt, dass eines dieser beiden Prinzipien nicht verletzt wird, sollten Sie trotzdem eine Aufzählung verwenden. Boolesche Flags sind das boolesche Äquivalent zu magischen Zahlen .
foo(false)
macht so viel Sinn wiebar(42)
. Aufzählungen können für Strategiemuster nützlich sein und Sie können flexibel eine weitere Strategie hinzufügen. (Denken Sie daran, sie entsprechend zu benennen .)Ihr spezielles Beispiel stört mich besonders. Warum wird diese Flagge so oft durchlaufen? Das hört sich so an, als müssten Sie Ihren Parameter in Unterklassen aufteilen .
quelle
TL; DR: Verwenden Sie keine booleschen Argumente.
Sehen Sie unten, warum sie schlecht sind und wie Sie sie ersetzen können (fett gedruckt).
Boolesche Argumente sind sehr schwer zu lesen und daher schwer zu pflegen. Das Hauptproblem ist, dass der Zweck im Allgemeinen klar ist, wenn Sie die Methodensignatur lesen, in der das Argument benannt ist. Die Benennung eines Parameters ist jedoch in den meisten Sprachen nicht erforderlich. Sie haben also Anti-Patterns, bei
RSACryptoServiceProvider#encrypt(Byte[], Boolean)
denen der boolesche Parameter festlegt, welche Art von Verschlüsselung in der Funktion verwendet werden soll.So erhalten Sie einen Anruf wie:
wo der Leser die Signatur der Methode nachschlagen muss, um festzustellen, was zum Teufel
true
eigentlich bedeuten könnte. Eine Ganzzahl zu übergeben ist natürlich genauso schlecht:würde dir genauso viel sagen - oder vielmehr: genauso wenig. Selbst wenn Sie Konstanten definieren, die für die Ganzzahl verwendet werden sollen, können Benutzer der Funktion diese einfach ignorieren und weiterhin Literalwerte verwenden.
Der beste Weg, dies zu lösen, ist die Verwendung einer Aufzählung . Wenn Sie eine Enumeration
RSAPadding
mit zwei Werten übergeben müssen:OAEP
oderPKCS1_V1_5
dann können Sie den Code sofort lesen:Boolesche Werte können nur zwei Werte haben. Wenn Sie also eine dritte Option haben, müssen Sie Ihre Signatur überarbeiten. Im Allgemeinen kann dies nicht einfach durchgeführt werden, wenn Abwärtskompatibilität ein Problem ist, sodass Sie eine öffentliche Klasse mit einer anderen öffentlichen Methode erweitern müssen. Dies ist, was Microsoft schließlich tat, als sie einführten,
RSACryptoServiceProvider#encrypt(Byte[], RSAEncryptionPadding)
wo sie eine Aufzählung (oder zumindest eine Klasse, die eine Aufzählung nachahmt) anstelle eines Booleschen verwendeten.Es kann sogar einfacher sein, ein vollständiges Objekt oder eine vollständige Schnittstelle als Parameter zu verwenden, falls der Parameter selbst parametrisiert werden muss. Im obigen Beispiel könnte die OAEP-Auffüllung selbst mit dem Hash-Wert parametrisiert werden, der intern verwendet wird. Beachten Sie, dass es jetzt 6 SHA-2-Hash-Algorithmen und 4 SHA-3-Hash-Algorithmen gibt, sodass die Anzahl der Aufzählungswerte explodieren kann, wenn Sie nur eine einzelne Aufzählung anstelle von Parametern verwenden (dies ist möglicherweise das nächste, was Microsoft herausfinden wird ).
Boolesche Parameter können auch darauf hinweisen, dass die Methode oder Klasse nicht gut entworfen wurde. Wie im obigen Beispiel: Jede andere kryptografische Bibliothek als .NET verwendet überhaupt kein Füllflag in der Methodensignatur.
Fast alle Software-Gurus, die ich mag, warnen vor booleschen Argumenten. Zum Beispiel warnt Joshua Bloch in dem hochgeschätzten Buch "Effective Java" davor. Im Allgemeinen sollten sie einfach nicht verwendet werden. Sie könnten argumentieren, dass sie verwendet werden könnten, wenn es einen Parameter gibt, der leicht zu verstehen ist. Aber selbst dann:
Bit.set(boolean)
wird wahrscheinlich besser mit zwei Methoden implementiert :Bit.set()
undBit.unset()
.Wenn Sie den Code nicht direkt umgestalten können, können Sie Konstanten definieren , um sie zumindest lesbarer zu machen:
ist viel lesbarer als:
auch wenn du lieber hättest:
stattdessen.
quelle
Ich bin überrascht, dass niemand Named-Parameter erwähnt hat .
Das Problem, das ich bei Booleschen Flags sehe, ist, dass sie die Lesbarkeit beeinträchtigen. Zum Beispiel, was macht
true
inmachen? Ich habe keine Ahnung. Aber was ist mit:
Jetzt ist klar, was der Parameter, den wir übergeben, bewirken soll: Wir weisen die Funktion an, ihre Änderungen zu speichern. In diesem Fall, wenn die Klasse nicht öffentlich ist, denke ich, dass der boolesche Parameter in Ordnung ist.
Natürlich können Sie die Benutzer Ihrer Klasse nicht zwingen, Named-Parameter zu verwenden. Aus diesem Grund
enum
sind in der Regel ein oder zwei separate Methoden vorzuziehen, je nachdem, wie häufig Ihr Standardfall ist. Genau das macht .Net:quelle
myFunction(true)
möglicherweise ein Code ist, Geruch.SaveBig
Namen definieren . Jeder Code kann vermasselt werden, diese Art der Vermasselung bezieht sich nicht auf benannte Parameter.Wenn es wie ein Codegeruch aussieht, sich wie ein Codegeruch anfühlt und - nun - wie ein Codegeruch riecht, ist es wahrscheinlich ein Codegeruch.
Was Sie tun möchten, ist:
1) Vermeiden Sie Methoden mit Nebenwirkungen.
2) Behandeln Sie notwendige Zustände mit einer zentralen, formalen Zustandsmaschine ( so ).
quelle
Ich bin mit allen Bedenken einverstanden, Boolesche Parameter zu verwenden, um nicht die Leistung zu bestimmen, um; Verbesserung, Lesbarkeit, Zuverlässigkeit, Verringerung der Komplexität, Verringerung der Risiken durch schlechte Verkapselung und Kohäsion sowie Senkung der Gesamtbetriebskosten durch Wartbarkeit.
Ich begann Mitte der 70er Jahre mit der Entwicklung von Hardware, die wir heute SCADA (Supervisor Control and Data Acquisition) nennen. Dabei handelte es sich um fein abgestimmte Hardware mit Maschinencode im EPROM, auf der Makro-Fernbedienungen ausgeführt und Hochgeschwindigkeitsdaten erfasst wurden.
Die Logik heißt Mealey & Moore- Maschinen, die wir jetzt Finite-State-Maschinen nennen . Diese müssen ebenfalls nach den gleichen Regeln wie oben ausgeführt werden, es sei denn, es handelt sich um eine Echtzeitmaschine mit einer begrenzten Ausführungszeit, und dann müssen Verknüpfungen ausgeführt werden, um diesen Zweck zu erfüllen.
Die Daten sind synchron, aber die Befehle sind asynchron, und die Befehlslogik folgt der speicherlosen Booleschen Logik, jedoch mit sequentiellen Befehlen, die auf dem Speicher des vorherigen, gegenwärtigen und gewünschten nächsten Zustands basieren. Damit dies in der effizientesten Maschinensprache (nur 64 KB) funktioniert, wurde große Sorgfalt darauf verwendet, jeden Prozess auf heuristische Weise für IBM HIPO zu definieren. Das bedeutete manchmal, boolesche Variablen zu übergeben und indizierte Verzweigungen auszuführen.
Aber jetzt mit viel Speicher und einfacher OOK, ist Encapsulation heute ein wesentlicher Bestandteil, aber eine Strafe, wenn Code in Bytes für Echtzeit- und SCADA-Maschinencode gezählt wurde.
quelle
Es ist nicht unbedingt falsch, aber in Ihrem konkreten Beispiel für die Aktion, die von einem Attribut des "Benutzers" abhängt, würde ich eher einen Verweis auf den Benutzer als ein Flag übergeben.
Dies verdeutlicht und hilft in mehrfacher Hinsicht.
Jeder, der die aufrufende Anweisung liest, wird feststellen, dass sich das Ergebnis je nach Benutzer ändert.
In der Funktion, die letztendlich aufgerufen wird, können Sie einfach komplexere Geschäftsregeln implementieren, da Sie auf alle Benutzerattribute zugreifen können.
Wenn eine Funktion / Methode in der "Kette" in Abhängigkeit von einem Benutzerattribut etwas anderes ausführt, ist es sehr wahrscheinlich, dass eine ähnliche Abhängigkeit von Benutzerattributen für einige der anderen Methoden in der "Kette" eingeführt wird.
quelle
Meistens würde ich diese schlechte Kodierung in Betracht ziehen. Ich kann mir jedoch zwei Fälle vorstellen, in denen dies eine gute Praxis sein könnte. Da es bereits viele Antworten gibt, die sagen, warum es schlecht ist, biete ich zwei Mal an, wenn es gut sein könnte:
Der erste ist, wenn jeder Aufruf in der Sequenz für sich genommen Sinn macht. Es wäre sinnvoll , wenn der anrufende Code könnte von true in false oder falsch wahr, geändert werden oder wenn die aufgerufene Methode könne geändert werden als Weitergabe direkt vielmehr den Booleschen Parameter zu verwenden. Die Wahrscheinlichkeit von zehn solchen Aufrufen hintereinander ist gering, aber es könnte passieren, und wenn dies der Fall wäre, wäre es eine gute Programmierpraxis.
Der zweite Fall ist etwas schwierig, da es sich um einen Booleschen handelt. Wenn das Programm jedoch mehrere Threads oder Ereignisse enthält, ist die Übergabe von Parametern der einfachste Weg, um thread- / ereignisspezifische Daten zu verfolgen. Beispielsweise kann ein Programm Eingaben von zwei oder mehr Sockets erhalten. Code, der für einen Socket ausgeführt wird, muss möglicherweise Warnmeldungen ausgeben, Code, der für einen anderen Socket ausgeführt wird, möglicherweise nicht. Es ist dann (irgendwie) sinnvoll, wenn ein Boolescher Satz auf einer sehr hohen Ebene durch viele Methodenaufrufe an die Stellen geleitet wird, an denen möglicherweise Warnmeldungen generiert werden. Die Daten können nicht (außer unter großen Schwierigkeiten) in irgendeiner Art von Global gespeichert werden, da mehrere Threads oder verschachtelte Ereignisse jeweils ihren eigenen Wert benötigen würden.
In letzterem Fall würde ich wahrscheinlich eine Klasse / Struktur erstellen, deren einziger Inhalt ein Boolescher Wert ist, und diesen stattdessen weitergeben. Ich bin mir ziemlich sicher, dass ich in Kürze andere Felder benötige - zum Beispiel, wohin die Warnmeldungen gesendet werden sollen.
quelle
Der Kontext ist wichtig. Solche Methoden sind in iOS ziemlich verbreitet. Als nur ein häufig verwendetes Beispiel stellt UINavigationController die Methode bereit
-pushViewController:animated:
, und deranimated
Parameter ist ein BOOL. Die Methode führt in beiden Fällen im Wesentlichen dieselbe Funktion aus, animiert jedoch den Übergang von einem Ansichtscontroller zu einem anderen, wenn Sie JA übergeben, und nicht, wenn Sie NEIN übergeben. Dies scheint völlig vernünftig; Es wäre albern, zwei Methoden anstelle dieser bereitzustellen, damit Sie bestimmen können, ob Sie Animation verwenden möchten oder nicht.In Objective-C ist dies möglicherweise einfacher zu rechtfertigen, da die Syntax zur Benennung von Methoden mehr Kontext für jeden Parameter bietet als in Sprachen wie C und Java. Trotzdem würde ich denken, dass eine Methode, die einen einzelnen Parameter verwendet, leicht einen Booleschen Wert annehmen kann und dennoch Sinn ergibt:
quelle
false
das imfile.saveWithEncryption
Beispiel bedeutet. Bedeutet das, dass es ohne Verschlüsselung gespeichert wird? Wenn ja, warum sollte die Methode "mit Verschlüsselung" im Namen stimmen? Ich könnte eine Methode wie diese verstehensave(boolean withEncryption)
, aber wenn ich sie sehefile.save(false)
, ist es auf den ersten Blick nicht offensichtlich, dass der Parameter angibt, dass es sich um eine verschlüsselte oder unverschlüsselte Methode handelt . Ich denke in der Tat, das macht James Youngman zum ersten Mal darauf an, eine Aufzählung zu verwenden.false
keine existierende Datei mit dem gleichen Namen überschrieben wird. Ich kenne ein erfundenes Beispiel, aber um sicherzugehen, müssen Sie die Dokumentation (oder den Code) für die Funktion überprüfen.saveWithEncryption
, die manchmal nicht mit Verschlüsselung gespeichert wird, ist ein Fehler. Es sollte möglich seinfile.encrypt().save()
, oder wie Javasnew EncryptingOutputStream(new FileOutputStream(...)).write(file)
.saveWithEncryption(boolean)
zu erstellen, die manchmal ohne Verschlüsselung gespeichert wird, genauso wie es nicht fliegt, um eine Methode zu erstellen,saveWithoutEncryption(boolean)
die manchmal mit Verschlüsselung gespeichert wird.