Manchmal (selten) scheint es der beste Weg zu sein, eine Funktion zu erstellen, die eine angemessene Menge von Parametern benötigt. Allerdings habe ich das Gefühl, dass ich die Reihenfolge der Parameter oft nach dem Zufallsprinzip wähle. Normalerweise gehe ich nach "Reihenfolge der Wichtigkeit" vor, wobei der wichtigste Parameter an erster Stelle steht.
Gibt es einen besseren Weg, dies zu tun? Gibt es eine "Best Practice" -Methode zum Ordnen von Parametern, die die Übersichtlichkeit erhöht?
refactoring
clean-code
functions
parameters
order
Casey Patton
quelle
quelle
MessageBox.Show
. Schauen Sie sich das auch an.Antworten:
Im Allgemeinen: benutze es .
Schreiben Sie einen Test für Ihre Funktion, einen realen Test.
Etwas, das Sie gerne mit dieser Funktion machen würden .
Und sehen Sie, in welcher Reihenfolge Sie diese abgelegt haben.
Es sei denn, Sie haben bereits einige Funktionen (oder kennen diese), die etwas Ähnliches tun.
In diesem Fall: Passen Sie sich an, was sie bereits tun, zumindest für die ersten Argumente.
Nehmen sie zB alle ein Dokument / Objekt / Dateizeiger / Wertereihen / Koordinaten als erstes Argument? Um Gottes willen, folge diesen Argumenten .
Vermeiden Sie es , Ihre Mitarbeiter und Ihr zukünftiges Selbst zu verwechseln .
quelle
Ich gehe normalerweise nach diesen Regeln vor, aber nicht immer mit der gleichen Priorität. Ich denke, es ist jetzt ein automatischer Denkprozess, und ich überlege es nicht, außer für das öffentliche API-Design .
Auswahltrichter
1. Semantik zuerst
Wählen Sie insbesondere in OOP Parameter basierend auf ihrer semantischen Bedeutung für die Aktion oder Nachricht aus. Die Signatur einer benannten Methode mit einem benannten Parameter sollte:
(Aus diesen Gründen kann manchmal die Verwendung benutzerdefinierter Typen oder Aliase anstelle von Grundelementen die Ausdruckskraft Ihrer Signatur erhöhen.)
2. Dann Wichtigkeit
Der "signifikanteste" Parameter kommt zuerst (oder als nächstes ...)
3. Dann Frequenz
Die Häufigkeit spielt auch eine Rolle, insbesondere in einer Sprache, in der Sie keine benannten Parameter haben, aber Standardwerte für Positionsparameter haben können. Dies bedeutet, dass sich die Reihenfolge der Parameter nicht ändert und dass Sie die N + 1-Parameter offensichtlich nicht festlegen können, wenn Sie den Standardwert des N-ten Parameters erzwingen möchten (es sei denn, Ihre Sprache hat das Konzept eines Platzhalterparameters ).
Die gute Nachricht für Sie ist, dass sich die Häufigkeit in der Regel auf die Wichtigkeit bezieht, sodass dies mit dem vorherigen Punkt einhergeht. Und dann liegt es wahrscheinlich an Ihnen, Ihre API so zu gestalten, dass sie die entsprechende Semantik aufweist.
4. Lassen Sie uns I / O nicht vergessen
Wenn Ihre Methode / Funktion eine Eingabe annimmt und eine Ausgabe erzeugt und letztere nicht "zurückgegeben" (über eine return-Anweisung) oder "geworfen" (unter Verwendung eines Ausnahmesystems) werden soll, haben Sie die Möglichkeit zu übergeben Werte werden mit Ihren anderen Parametern (oder dem Eingabeparameter) an den Aufrufer zurückgegeben. Das bezieht sich auf die Semantik, und in den meisten Fällen ist es sinnvoll, dass die ersten Parameter die Ausgabe definieren und die letzten Parameter die Ausgabe empfangen.
Ein anderer Ansatz, um weniger Parameter zu haben und die Semantik zu maximieren, ist die Verwendung eines funktionalen Ansatzes oder die Definition eines Builder-Musters , damit Sie Ihre Eingaben übersichtlich stapeln, Ihre Ausgaben definieren und sie bei Bedarf abrufen können.
(Beachten Sie, dass ich keine globalen Variablen erwähne, denn warum sollten Sie eine verwenden, richtig?)
Einige Dinge zu beachten
Benutzerfreundlichkeit
Die meisten der oben genannten Punkte werden natürlich angezeigt, wenn Sie den Ratschlägen von ZJR folgen : Use It!
Betrachten Sie Refactoring
Wenn Sie sich Gedanken über die Parameterreihenfolge machen, liegt dies möglicherweise an der oben genannten Ursache und an der Tatsache, dass Ihre API schlecht entworfen wurde. Wenn Sie zu viele Parameter haben, kann höchstwahrscheinlich etwas komponiert / modularisiert und umgestaltet werden .
Betrachten Sie die Leistung
Beachten Sie, dass die Implementierung einiger Sprachen bei der Verwendung von Parametern sehr wichtige Auswirkungen auf die Laufzeitspeicherverwaltung hat. Daher empfehlen die Style-Books vieler Sprachen, die Parameterliste einfach und kurz zu halten . Zum Beispiel bei maximal 4 Parametern. Ich überlasse es Ihnen, herauszufinden, warum.
Bevans Antwort und Erwähnung der Empfehlungen von Clean Code sind definitiv ebenfalls relevant!
quelle
Ich würde respektvoll einreichen, dass die Sorge um die Parameterreihenfolge die Sorge um das Falsche ist.
In Onkel Bobs Buch " Clean Code " tritt er überzeugend dafür ein, dass Methoden niemals mehr als zwei Argumente haben sollten - und die meisten sollten nur eines haben, wenn überhaupt. In diesem Fall ist die Bestellung entweder offensichtlich oder unwichtig.
Trotzdem versuche ich unvollkommen, Onkel Bobs Rat zu befolgen - und es verbessert meinen Code.
In den seltenen Fällen, in denen eine Methode mehr Informationen zu erfordern scheint, ist die Einführung eines Parameterobjekts eine gute Idee. Normalerweise ist dies der erste Schritt zur Entdeckung eines neuen Konzepts (Objekts), das der Schlüssel zu meinem Algorithmus ist.
quelle
Ich versuche, die IN-Parameter an erster Stelle, OUT-Parameter an zweiter Stelle zu setzen. Es gibt auch einige natürliche Ordnungen, die zB
createPoint(double x, double y)
stark vorzuziehen sindcreatePoint(double y, double x)
.quelle
addAllTo(target, something1, something2)
.Ich habe noch nie eine dokumentierte "Best Practice" in Bezug auf dieses spezielle Thema gesehen, aber mein persönlicher Standard ist es, sie entweder in der Reihenfolge aufzulisten, in der sie in der Methode erscheinen, für die sie verwendet werden, oder wenn die Methode eher eine ist Durchgang zu einer Datenschicht Ich werde sie in der Reihenfolge auflisten, in der sie im DB-Schema oder in den Datenschichtmethoden erscheinen würden.
Wenn es mehrere Überladungen einer Methode gibt, stelle ich fest, dass die typische Methode darin besteht, sie beginnend mit Parametern aufzulisten, die allen (oder den meisten) Methoden gemeinsam sind, wobei für jede Methodenüberladung wie jede andere Methode am Ende angehängt wird :
quelle
Reihenfolge: Eingabe (n), Ausgabe (n), optionale Parameter.
quelle
Ich folge oft der C / C ++ - Konvention, dass die
const
Parameter zuerst platziert werden ( dh die Parameter, die Sie als Wert übergeben) und dann die, die Sie als Referenz übergeben. Dies ist möglicherweise nicht die richtige Methode zum Aufrufen von Funktionen. Wenn Sie jedoch daran interessiert sind, wie jeder Compiler mit Parametern umgeht, finden Sie unter den folgenden Links die Regeln und / oder die Reihenfolge, in der die Parameter auf den Stapel verschoben werden.http://msdn.microsoft.com/en-us/library/zthk2dkh%28v=vs.80%29.aspx
http://en.wikipedia.org/wiki/Calling_convention
quelle
Normalerweise gehe ich einfach mit der Parameterreihenfolge "Was weniger zyprisch aussieht" um. Je weniger Male ich zur Methoden- / Funktionsdefinition gehen muss, desto besser. Und es ist schön, benannte Parameter zu haben, die beschreiben, wofür sie verwendet werden. Auf diese Weise wird es noch einfacher, wenn der kleine Tooltip (VS) angezeigt wird.
Wenn Sie Linien und Parameterlinien haben, möchten Sie möglicherweise ein anderes Design in Betracht ziehen. Machen Sie einen Schritt zurück und sehen Sie, wie Sie das in weitere Funktionen / Methoden aufteilen können. Nur eine Idee, aber wenn ich ein Dutzend Parameter in meiner Funktion habe, ist es fast immer kein Parameterproblem, sondern ein Designproblem.
quelle
Die Verwendung mehrerer Parameter ist häufig ein eindeutiger Hinweis darauf, dass Sie bei dieser Methode gegen die SRP verstoßen . Es ist unwahrscheinlich, dass eine Methode, die viele Parameter benötigt, nur eines tut. Excpetion kann eine mathematische Funktion oder eine Konfigurationsmethode sein, bei der tatsächlich mehrere Parameter als solche benötigt werden. Ich würde mehrere Parameter vermeiden, da der Teufel das Weihwasser meidet. Je mehr Parameter Sie in einer Methode verwenden, desto höher ist die Wahrscheinlichkeit, dass die Methode (zu) komplex ist. Je komplexer, desto schwieriger zu warten und desto weniger wünschenswert.
Im Prinzip wählen Sie nach dem Zufallsprinzip . Natürlich könnte man denken, dass Parameter A relevanter ist als Parameter B ; Dies ist jedoch möglicherweise nicht der Fall für Benutzer Ihrer API, die B für den relevantesten Parameter halten. Selbst wenn Sie bei der Auswahl der Bestellung aufpassen, kann dies für andere zufällig erscheinen .
Es gibt verschiedene Möglichkeiten:
a) Der triviale Fall: Verwenden Sie nicht mehr als einen Parameter.
b) Da Sie nicht angegeben haben, welche Sprache Sie gewählt haben, besteht die Möglichkeit, dass Sie eine Sprache mit benannten Parametern gewählt haben . Dies ist ein schöner syntaktischer Zucker , mit dem Sie die Bedeutung der Reihenfolge der Parameter lockern können:
fn(name:"John Doe", age:36)
Nicht jede Sprache erlaubt solche Feinheiten. Und was dann?
c) Sie könnten ein Dictionary / Hashmap / Associative Array als Parameter verwenden: zB würde Javascript folgendes erlauben:
fn({"name":"John Doe", age:36})
welches nicht weit von (b) entfernt ist.d) Natürlich, wenn Sie mit einer statisch typisierten Sprache wie Java arbeiten. Sie könnten eine Hashmap verwenden , verlieren jedoch die Typinformationen (z. B. beim Arbeiten mit
HashMap<String, Object>
), wenn Parameter unterschiedliche Typen haben (und umgewandelt werden müssen).Der nächste logische Schritt wäre die Übergabe eines
Object
(wenn Sie Java verwenden) mit entsprechenden Eigenschaften oder etwas Leichterem wie einer Struktur (wenn Sie z. B. C # oder C / C ++ schreiben).Faustregel:
1) Bester Fall - Ihre Methode benötigt überhaupt keinen Parameter
2) Guter Fall - Ihre Methode benötigt einen Parameter
3) Tolerierbarer Fall - Ihre Methode benötigt zwei Parameter
4) Alle anderen Fälle sollten überarbeitet werden
quelle
Oft ist ein komplexes Objekt als Parameter besser - die Version der benannten Parameter eines armen Mannes, die auf den meisten Plattformen funktioniert. Und öffnet die Tür zu Parametern mit Verhalten zum Booten.
Als Beispiel für die meisten Dinge, die Sie nicht tun sollten, möchten Sie vielleicht die Standard-Bibliotheksdokumentation von PHP lesen.
quelle
Ich bestelle sie in der Regel zuerst mit der erforderlichen, dann nach einem kombinierten Maß an Wichtigkeit und Verwendungshäufigkeit nach einem "Gefühl" (kann als "Gefühl" angesehen werden
ORDER BY required DESC, SOME_MAGIC_FEELING(importancy,frequency)
) und nicht nach einer bestimmten Praxis.Wie andere angemerkt haben, verwendet das zugrunde liegende Problem, das dies zu einem Problem macht, zu viele Parameter (IMHO, alles> 3 ist zu viele), und das ist das eigentliche Problem, mit dem Sie sich befassen sollten. Es gibt einen interessanten Beitrag dazu im Blog von Rebecca Murphey.
Ich denke, wenn Sie nur 1-3 Argumente haben, ist die richtige Reihenfolge ziemlich offensichtlich und Sie "fühlen" nur, was richtig ist.
quelle
Ähnlich wie bei der Antwort von @Wyatt Barnetts würde ich empfehlen, stattdessen ein Objekt zu übergeben, das nicht nur einige Parameter oder sehr explizite Parameter für die Methode enthält. Dies ist in der Regel einfacher zu aktualisieren / warten, übersichtlicher zu lesen und macht das Bestellen überflüssig . Außerdem sind zu viele Parameter für eine Methode ein Codegeruch, und es gibt gängige Refactoring-Muster, die Sie befolgen können, um sie zu korrigieren.
Explizites Beispiel:
Da dies ein ziemlich klar definiertes Beispiel ist und die Addition kommutativ ist (Reihenfolge spielt keine Rolle), machen Sie es einfach.
Wenn Sie jedoch etwas Komplexeres hinzufügen:
Würde werden:
Hoffe das hilft...
quelle
Bestellen Sie es so, wie es Ihnen am ehesten gefällt. Zum Beispiel zuerst die Funktionsparameter.
quelle
"Wichtig zuerst" bedeutet nicht viel. Es gibt einige Konventionen.
Wenn Sie das aufrufende Objekt (häufig Absender genannt) übergeben, geht das zuerst.
Die Liste sollte fließend sein , dh Sie sollten wissen, worum es bei einem Argument geht, wenn Sie es lesen. Beispiel:
CopyFolder (Zeichenkettenpfad, Bool rekursiv);
Wenn Sie zuerst rekursiv stellen, ist dies verwirrend, da noch kein Kontext vorhanden ist. Wenn es Ihnen jetzt schon darum geht, einen Ordner (1) zu kopieren (2), dann fängt das Argument rekursiv an Sinn zu machen.
Dadurch funktionieren auch IntelliSense-ähnliche Funktionen gut: Der Benutzer lernt, während er die Argumente eingibt, und baut ein Verständnis für die Methode und ihre Funktionsweise auf. Ebenso sollten Überladungen die gleiche Reihenfolge für die Teile beibehalten, die gleich sind.
Dann finden Sie möglicherweise immer noch Argumente, die in dieser Hinsicht "gleich" sind, und Sie könnten versucht sein, die Reihenfolge von der Art des Arguments abhängen zu lassen. Nur weil ein paar Saiten hintereinander und dann ein paar Boolesche besser aussehen. Auf einer gewissen Ebene wird dies eher eine Kunst als eine Fähigkeit.
Die Aussage, dass Sie alle Argumente in ein Objekt einschließen sollten, um nur ein einziges Argument zu erhalten, interessiert mich nicht sonderlich. Das täuscht sich nur selbst (es macht die Methode nicht weniger komplex, es hat immer noch all diese Argumente, man hat sie einfach versteckt). Dies kann immer noch praktisch sein, wenn Sie die Menge ein paarmal von Methode zu Methode weitergeben. Das Refactoring wird sicher viel einfacher, aber in Bezug auf das Design wird nur so getan, als ob Sie einen Unterschied machen. Es ist nicht so, dass Sie am Ende ein aussagekräftiges Objekt haben, das etwas darstellt, sondern nur eine Reihe von Argumenten, die sich nicht von der Liste in der Methodendeklaration unterscheiden. Es wird Onkel Bob nicht glücklich machen.
quelle