Clean Code: Funktionen mit wenigen Parametern [geschlossen]

48

Ich habe die ersten Kapitel von Clean Code von Robert C. Martin gelesen und es scheint mir ziemlich gut zu sein, aber ich habe Zweifel, in einem Teil wird erwähnt, dass es gut (kognitiv) ist, dass die Funktionen möglichst wenige Parameter haben sollten Möglicherweise deutet dies sogar darauf hin, dass 3 oder mehr Parameter zu viel für eine Funktion sind (was ich sehr übertrieben und idealistisch finde), also begann ich mich zu wundern ...

Sowohl die Verwendung globaler Variablen als auch die Übergabe vieler Argumente für die Funktionen wären eine schlechte Programmierpraxis, aber die Verwendung globaler Variablen kann die Anzahl der Parameter in den Funktionen erheblich verringern ...

Ich wollte hören, was Sie darüber denken. Lohnt es sich, globale Variablen zu verwenden, um die Anzahl der Parameter der Funktionen zu verringern, oder nicht? In welchen Fällen wäre es?

Was ich denke ist, dass es von mehreren Faktoren abhängt:

  • Quellcode Größe.
  • Anzahl der Parameter im Durchschnitt der Funktionen.
  • Anzahl der Funktionen.
  • Häufigkeit, mit der dieselben Variablen verwendet werden.

Meiner Meinung nach, wenn der Quellcode relativ klein ist (wie weniger als 600 Codezeilen), gibt es viele Funktionen, die gleichen Variablen werden als Parameter übergeben und die Funktionen haben viele Parameter, dann wäre die Verwendung globaler Variablen aber sinnvoll würde gerne Wissen...

  • Teilen Sie meine Meinung?
  • Was halten Sie von anderen Fällen, in denen der Quellcode größer ist, usw.?

PS . Ich habe diesen Beitrag gesehen , die Titel sind sehr ähnlich, aber er fragt nicht, was ich wissen möchte.

OiciTrap
quelle
144
Ich glaube nicht, dass die Alternative global wäre, sondern Argumente zu Objekten zusammenfassen. Es ist wahrscheinlich eher ein Vorschlag, der postLetter(string country, string town, string postcode, string streetAddress, int appartmentNumber, string careOf)eine stinkende Version von ist postLetter(Address address). Lesen Sie das Buch weiter, es wird hoffentlich so etwas sagen.
Nathan Cooper
3
@DocBrown Ich habe die Frage so verstanden, als würde Onkel Bob sagen, dass er nicht mehr als 3 Parameter verwendet, damit ich dieses Problem umgehen kann, indem ich globale Variablen verwende, oder? :-) Ich denke, wahrscheinlich weiß der Autor nicht, wie man dieses Problem besser umgehen kann - wie in den Antworten unten erwähnt.
Bytedev
9
Nicht mehr als n Parameter sind eine Faustregel (für jeden Wert von n), die nicht auf einen Diamanten geätzt ist. Verwechseln Sie gute Ratschläge nicht mit einem Mandat. Viele Parameter sind im Allgemeinen ein Codegeruch, bei dem in einer Funktion / Methode zu viel los ist. Früher wurde die Aufteilung in mehrere Funktionen vermieden, um den zusätzlichen Aufwand für zusätzliche Anrufe zu umgehen. Nur noch wenige Anwendungen sind so leistungsintensiv und ein Profiler kann Ihnen sagen, wann und wo Sie zusätzliche Anrufe vermeiden müssen.
Jared Smith
14
Dies zeigt, was an dieser Art von urteilsfreier Regel falsch ist: Sie öffnet die Tür zu urteilsfreien „Lösungen“. Wenn eine Funktion viele Argumente hat, kann dies auf ein suboptimales Design hinweisen, in der Regel nicht nur der Funktion, sondern auch des Kontexts, in dem sie verwendet wird. Die Lösung (falls erforderlich) besteht darin, den Code umzugestalten. Ich kann Ihnen keine einfache, allgemeine und urteilsfreie Regel dazu geben, aber das heißt nicht, dass nicht mehr als N Argumente eine gute Regel sind.
Sdenham
4
Wenn Sie zu viele Parameter für eine Funktion haben, hängen einige von ihnen mit Gewinnchancen zusammen und sollten zu einem Objekt gruppiert werden, das dann zu einem einzigen Parameter wird, der mehrere Datenelemente zusammenfasst. Hier gibt es eine dritte Option.

Antworten:

113

Ich teile deine Meinung nicht. Meiner Meinung nach ist die Verwendung globaler Variablen ungeachtet der von Ihnen beschriebenen Eigenschaften eine schlechtere Praxis als mehr Parameter. Ich bin der Meinung, dass mehr Parameter das Verständnis einer Methode erschweren, aber globale Variablen viele Probleme für den Code verursachen können, darunter schlechte Testbarkeit, Fehler bei der Parallelität und enge Kopplung. Unabhängig von der Anzahl der Parameter einer Funktion treten nicht dieselben Probleme auf wie bei globalen Variablen.

... werden die gleichen Variablen als Parameter übergeben

Es kann ein Designgeruch sein. Wenn Sie die gleichen Parameter an die meisten Funktionen in Ihrem System übergeben haben, kann es zu einem Querschnittsthema kommen, das durch die Einführung einer neuen Komponente behoben werden sollte. Ich denke nicht, dass die Übergabe derselben Variablen an viele Funktionen eine solide Argumentation für die Einführung globaler Variablen ist.

In einer Bearbeitung Ihrer Frage haben Sie angegeben, dass die Einführung globaler Variablen die Lesbarkeit von Code verbessern könnte. Ich stimme dir nicht zu. Die Verwendung globaler Variablen ist im Implementierungscode verborgen, während Funktionsparameter in der Signatur deklariert sind. Funktionen sollten idealerweise rein sein. Sie sollten nur an ihren Parametern arbeiten und sollten keine Nebenwirkungen haben. Wenn Sie eine reine Funktion haben, können Sie über die Funktion nachdenken, indem Sie nur eine Funktion betrachten. Wenn Ihre Funktion nicht rein ist, müssen Sie den Zustand anderer Komponenten berücksichtigen, und es wird sehr viel schwieriger, darüber nachzudenken.

Samuel
quelle
Ok, es ist gut, andere Meinungen zu hören, aber über den Designgeruch programmiere ich in C-Problemen, die durch Methoden der künstlichen Intelligenz gelöst werden, und ich neige dazu, viele Funktionen zu verwenden, die fast immer die gleichen Matrizen, Arrays oder Variablen verwenden (die Ich übergebe als Parameter an die Funktionen.) Ich sage dies, weil ich nicht der Meinung bin, dass ich diese Variablen in ein gemeinsames Konzept / Ding wie eine Struktur oder eine Vereinigung einfügen kann, damit ich nicht weiß, wie man ein besseres Design macht. Aus diesem Grund denke ich, dass die Verwendung globaler Variablen in diesem Fall sinnvoll sein könnte, aber höchstwahrscheinlich irre ich mich.
OiciTrap
1
Das klingt nicht nach einem Designproblem. Ich denke immer noch, dass die Übergabe von Parametern an die Funktionen das beste Design ist. In einem KI-System, wie Sie es beschreiben, wäre es nützlich, Komponententests zu schreiben, um die Teile des Systems zu testen, und der einfachste Weg, dies zu tun, sind Parameter.
Samuel
96
Weitere Parameter erschweren das Verständnis eines Unterprogramms, globale Variablen erschweren das Verständnis des gesamten Programms, dh aller Unterprogramme .
Jörg W Mittag
2
Ich verwalte eine Codebasis, in der einige Funktionen mehr als ein Dutzend Parameter enthalten. Es ist eine enorme Zeitverschwendung - jedes Mal, wenn ich die Funktion aufrufen muss, muss ich diese Datei in einem anderen Fenster öffnen, damit ich weiß, in welcher Reihenfolge die Parameter angegeben werden müssen. Wenn ich eine IDE verwenden würde, die mir so etwas wie Intellisense gibt, oder wenn ich eine Sprache verwende, die Parameter benennt, dann wäre das nicht so schlimm, aber wer kann sich erinnern, in welcher Reihenfolge sich ein Dutzend Parameter für all diese Funktionen befinden?
Jerry Jeremiah
6
Die Antwort ist richtig, obwohl es den Anschein hat, dass das Missverständnis der OPs bezüglich der Empfehlungen in "Clean Code" eine Selbstverständlichkeit ist. Ich bin sicher, dass es in diesem Buch keine Empfehlung gibt, Funktionsparameter durch globale zu ersetzen.
Doc Brown
68

Sie sollten globale Variablen wie die Pest vermeiden .

Ich würde nicht eine harte Begrenzung der Anzahl von Argumenten (wie 3 oder 4) setzen, aber Sie tun wollen , dass sie auf ein Minimum zu halten, wenn möglich.

Verwenden Sie structs (oder Objekte in C ++), um Variablen zu einer einzigen Entität zusammenzufassen und diese (als Referenz) an Funktionen zu übergeben. Normalerweise erhält eine Funktion eine Struktur oder ein Objekt (mit ein paar verschiedenen Dingen darin) zusammen mit ein paar anderen Parametern, die die Funktion anweisen, etwas mit dem zu tun struct.

Halten Sie sich für einen gut riechenden, sauberen und modularen Code an das Prinzip der einmaligen Verantwortung . Tun Sie dies mit Ihren Strukturen (oder Objekten), den Funktionen und den Quelldateien. Wenn Sie dies tun, ist die natürliche Anzahl der Parameter, die an eine Funktion übergeben werden, offensichtlich.

Robert Bristow-Johnson
quelle
5
Was ist der Hauptunterschied zwischen der Übergabe von zehn Parametern, die in einer Struktur verborgen sind, und der expliziten Übergabe von Parametern?
Ruslan
21
@ Ruslan Zusammenhalt.
abuzittin gillifirca
9
Und es ist wahrscheinlicher, dass Sie die Funktion in kleinere Funktionen umgestalten, da Sie anstelle von zehn Parametern nur einen Parameter an die Unterfunktionen übergeben können. Und weniger Risiko, die Parameter zu verwechseln, wenn Sie Positionsargumente verwenden.
Hans Olsson
8
Das ist in Ordnung, aber Sie müssen für Kohärenz in den Structs sorgen - stellen Sie sicher, dass die in einer Struct gruppierten Parameter "verwandt" sind. Unter bestimmten Umständen können Sie mehr als eine Struktur verwenden.
Andrew Dodds
8
@abuzittingillifirca Sie erhalten nicht automatisch Zusammenhalt. Wenn die einzige Rechtfertigung für das Einfügen von Parametern in eine Struktur darin besteht, sie an eine bestimmte Funktion zu übergeben, ist der Zusammenhalt wahrscheinlich illusorisch.
Sdenham
55

Wir sprechen von kognitiver Last, nicht von Syntax. Die Frage ist also ... Was ist in diesem Zusammenhang ein Parameter?

Ein Parameter ist ein Wert, der das Verhalten der Funktion beeinflusst. Je mehr Parameter, desto mehr mögliche Kombinationen von Werten erhalten Sie, desto schwieriger wird es, über die Funktion nachzudenken.

In diesem Sinne globale Variablen , die die Funktion verwendet werden Parameter. Hierbei handelt es sich um Parameter, die nicht in der Signatur enthalten sind und Probleme mit der Reihenfolge der Erstellung, der Zugriffskontrolle und der Remanenz aufweisen.

Sofern es sich bei diesem Parameter nicht um ein so genanntes Querschnittsthema handelt , dh um einen programmweiten Status, den alles verwendet, aber nichts ändert (z. B. ein Protokollierungsobjekt), sollten Sie Funktionsparameter nicht durch globale Variablen ersetzen. Sie wären immer noch Parameter, aber fieser.

QUentin
quelle
11
Für Sie eine +1, sei es eine Toilette oder eine Kommode, stinken sie gleich. Gute Arbeit, um den Wolf im Schafspelz hervorzuheben.
Jared Smith
1
+1 für die Angabe, dass sowohl viele Parms als auch globale Vars schlecht sind. Aber ich möchte etwas klarstellen. In den meisten Sprachen werden primitive Parameter standardmäßig als Wert übergeben (Java). In anderen Sprachen können Sie sie explizit als Wert übergeben (PL / SQL). Andererseits wird auf globale Primitive immer per Referenz zugegriffen (sozusagen). So sind Parameter, zumindest von primitiven Typen, immer sicherer als globale Variablen. Obwohl es natürlich ein Geruch ist, mehr als zwei oder drei Parameter zu haben, und zwölf Parameter zu haben, ist ein riesiger Geruch, der umgestaltet werden sollte.
Tulains Córdova
4
Absolut ist eine globale Variable ein versteckter Parameter.
Bill K
+1 Ich habe MATLAB-Simulationen gesehen, die auf globalen Variablen basieren, um Daten weiterzuleiten. Das Ergebnis war völlig unlesbar, weil es so schwer war zu sagen, welche Variablen Parameter für welche Funktion waren.
Cort Ammon
34

IMHO basiert Ihre Frage auf einem Missverständnis. In "Clean Code" schlägt Bob Martin nicht vor, wiederholte Funktionsparameter durch globale zu ersetzen, was ein wirklich schrecklicher Rat wäre. Er schlägt vor, sie durch private Mitgliedsvariablen der Klasse der Funktion zu ersetzen . Außerdem schlägt er kleine, zusammenhängende Klassen vor (normalerweise kleiner als die 600 Codezeilen, die Sie erwähnt haben), sodass diese Mitgliedsvariablen definitiv keine globalen Variablen sind.

Wenn Sie also die Meinung in einem Kontext mit weniger als 600 Zeilen haben, "die Verwendung globaler Variablen wäre es wert" , dann teilen Sie perfekt die Meinung von Onkel Bob. Natürlich ist es fraglich, ob "maximal 3 Parameter" die ideale Zahl ist und ob diese Regel manchmal zu vielen Mitgliedsvariablen führt, selbst in kleinen Klassen. IMHO ist dies ein Kompromiss, es gibt keine feste Regel, wo die Grenze gezogen werden soll.

Doc Brown
quelle
10
Ich habe nie verstanden, warum jemand es vorziehen würde, seine Klasse zustandsmäßig zu machen, indem er Parameter in einen Konstruktor einfügt, anstatt nur mit einem tatsächlichen Argument zu leben. Das hat mich immer als einen enormen Anstieg der Komplexität empfunden. (Ein Beispiel aus der Praxis, das ich gesehen habe, ist ein Datenbankverbindungsobjekt, das den Versuch, den Status der Datenbank über das Programm zu verfolgen, in Kombination mit der Abhängigkeitsinjektion nahezu unmöglich gemacht hat.) Aber vielleicht hat Clean Code dazu mehr zu sagen Gegenstand. Globals sind natürlich eine noch schlechtere Option, wenn es darum geht, die Dinge in einen Zustand zu versetzen.
jpmc26
2
@ jpmc26: Nur wenn die Klassen zu groß werden und zu viele Membervariablen haben, bekommt man eine "enorme Steigerung der Komplexität", so dass das Ergebnis nicht mehr schlüssig ist.
Doc Brown
4
Ich denke, diese Reaktion ignoriert die Schwierigkeit, den Zustand (der möglicherweise sogar veränderlich ist), der über viele Klassen verteilt ist, zu managen. Wenn eine Funktion nicht nur von den Argumenten abhängt, sondern auch davon, wie das Objekt während seiner Lebensdauer konstruiert (oder sogar geändert) wurde, wird es schwieriger, den aktuellen Status zu verstehen, wenn Sie einen bestimmten Aufruf tätigen. Sie müssen jetzt die Konstruktion eines anderen Objekts aufspüren , um herauszufinden, was der Aufruf bewirken wird. Durch das Hinzufügen von Instanzvariablen wird der Status des Programms aktiv erhöht, es sei denn, Sie erstellen das Objekt und werfen es sofort weg.
jpmc26
3
@ jpmc26 Ein Muster, das ich beim Refactoring regelmäßig verwende, ist, dass der Konstruktor wie das Festlegen eines Kontexts funktioniert und die Methodenargumente für eine Aktion spezifisch sind. Das Objekt ist nicht genau statusbehaftet, da sich der Status, den es enthält, nie ändert. Durch das Verschieben dieser allgemeinen Aktionen in die Methoden dieses Containers wird jedoch die Lesbarkeit bei dieser Verwendung erheblich verbessert (der Kontext wird nur einmal festgelegt, ähnlich wie bei Pythons Kontextmanagern) und die Duplizierung verringert, wenn Die Methoden des Objekts werden mehrfach aufgerufen.
Izkata
3
+1 Um klar zu sagen, dass Mitgliedsvariablen keine globalen Variablen sind. Viele Leute denken, dass sie sind.
Tulains Córdova
34

Viele Parameter zu haben, wird als unerwünscht angesehen, aber sie in Felder oder globale Variablen umzuwandeln ist viel schlimmer, weil es das eigentliche Problem nicht löst, sondern neue Probleme einführt.

Viele Parameter zu haben, ist an sich nicht das Problem, aber es ist ein Symptom, dass Sie möglicherweise ein Problem haben. Betrachten Sie diese Methode:

Graphics.PaintRectangle(left, top, length, height, red, green, blue, transparency);

7 Parameter zu haben, ist ein eindeutiges Warnzeichen. Das Grundproblem ist, dass diese Parameter nicht unabhängig sind, sondern zu Gruppen gehören. leftund topgehören zusammen als Position-Struktur, lengthund heightals eine SizeStruktur, und red, blueund greenals eine ColorStruktur. Und vielleicht Colorgehört Transparenz in eine BrushStruktur? Vielleicht Positionund Sizegehört in einer RectangleStruktur zusammen. In diesem Fall können wir sogar in Erwägung ziehen, sie stattdessen in eine PaintMethode für das RectangleObjekt umzuwandeln. So können wir am Ende mit:

Rectangle.Paint(brush);

Mission erfüllt! Das Wichtigste ist jedoch, dass wir das Gesamtdesign tatsächlich verbessert haben, und die Verringerung der Anzahl der Parameter ist eine Folge davon. Wenn wir nur die Anzahl der Parameter reduzieren, ohne die zugrunde liegenden Probleme anzugehen, könnten wir Folgendes tun:

Graphics.left = something;
Graphics.top = something;
Graphics.length = something;
...etc
Graphics.PaintRectangle();

Hier haben wir die gleiche Reduzierung der Parameteranzahl erreicht, aber das Design tatsächlich verschlechtert .

Fazit: Für Programmierempfehlungen und Faustregeln ist es wirklich wichtig, die zugrunde liegenden Argumente zu verstehen.

JacquesB
quelle
4
+1 nette, konstruktive, verständliche, nicht theoretische Antwort.
AnoE
1
Ganz zu schweigen davon, was zum Teufel Ihr "Quadrat" macht, das sowohl ein Längen- als auch ein Höhenattribut hat. :)
Wildcard
1
+1 für die Bestätigung, dass der offensichtliche dritte Weg, den einige Antworten implizieren (dh viele Zuweisungen zu einer Struktur / einem Objekt vor dem Funktionsaufruf), nicht besser ist.
Benxyzzy
@Wildcard: Danke, habe es in "Rechteck" geändert, um das Problem nicht zu verwechseln!
JacquesB
7

lohnt es sich, globale Variablen zu verwenden, um die Anzahl der Parameter der Funktionen zu verringern oder nicht?

Nicht

Ich habe die ersten Kapitel dieses Buches gelesen

Hast du den Rest des Buches gelesen?

Ein globaler ist nur ein versteckter Parameter. Sie verursachen einen anderen Schmerz. Aber es tut immer noch weh. Überlegen Sie nicht länger, wie Sie diese Regel umgehen können. Überlegen Sie, wie Sie dem folgen sollen.

Was ist ein Parameter?

Es ist Zeug. In einer schön beschrifteten Box. Warum ist es wichtig, wie viele Kartons Sie haben, wenn Sie alles hineinlegen können?

Es sind die Kosten für Versand und Bearbeitung.

Move(1, 2, 3, 4)

Sag mir, dass du das lesen kannst. Mach weiter, versuch es.

Move(PointA, PointB)

Deshalb.

Dieser Trick heißt Introduce Parameter Object .

Und ja, es ist nur ein Trick, wenn Sie nur Parameter zählen. Was Sie zählen sollten, ist IDEEN! Abstraktionen! An wie viel lässt du mich auf einmal denken? Halte es einfach.

Nun ist dies die gleiche Zählung:

Move(xyx, y)

OW! Das ist schrecklich! Was ist hier schief gelaufen?

Es reicht nicht aus, die Anzahl der Ideen zu begrenzen. Es müssen klare Vorstellungen sein. Was zum Teufel ist ein xyx?

Das ist jetzt noch schwach. Was ist eine mächtigere Art, darüber nachzudenken?

Funktionen sollten klein sein. Nicht kleiner als das.

Onkel Bob

Move(PointB)

Warum sollte die Funktion nicht mehr tun, als sie wirklich tun muss? Das Prinzip der Einzelverantwortung gilt nicht nur für den Unterricht. Im Ernst, es lohnt sich, eine gesamte Architektur zu ändern, nur um zu verhindern, dass eine Funktion zu einem überlasteten Albtraum mit 10 manchmal verwandten Parametern wird, von denen einige nicht für andere verwendet werden können.

Ich habe Code gesehen, bei dem die häufigste Anzahl von Zeilen in einer Funktion 1 war. Ich sage nicht, dass Sie so schreiben müssen, aber meine Güte, sagen Sie mir nicht, dass ein globaler Weg der EINZIGE ist, mit dem Sie diese Regel einhalten können. Versuchen Sie nicht länger, diese Funktion ordnungsgemäß umzugestalten. Sie wissen, dass Sie können. Es könnte in einige Funktionen zerfallen. Es könnte sich tatsächlich in ein paar Objekte verwandeln. Zum Teufel, Sie könnten sogar einen Teil davon in eine ganz andere Anwendung ausbrechen.

Das Buch fordert Sie nicht auf, Ihre Parameter zu zählen. Es fordert Sie auf, auf die Schmerzen zu achten, die Sie verursachen. Alles, was den Schmerz behebt, behebt das Problem. Seien Sie sich nur bewusst, wenn Sie einfach einen Schmerz gegen einen anderen eintauschen.

kandierte_orange
quelle
3
"Hast du den Rest des Buches gelesen?" Ihre Frage wird in den ersten 8 Worten meines Beitrags beantwortet ...
OiciTrap
Ich stimme vollkommen zu - es geht darum, das Problem in kleine Stücke zu zerlegen. Objekte können wirklich helfen, diese Teile zu organisieren und zu gruppieren. Sie ermöglichen auch die Übergabe einer einzelnen konzeptionellen Einheit als Parameter und nicht als Bündel nicht verbundener Teile. Ich ärgere mich, wenn ich eine Methode mit mehr als 3 Parametern sehe. 5 ist ein Anzeichen dafür, dass mein Design kaputt gegangen ist und ich eine weitere Umgestaltungsrunde brauche. Der beste Weg, um Designprobleme wie die Parameteranzahl zu lösen, besteht darin, Dinge einfach in kleinere, einfachere Einheiten (Klassen / Methoden) umzugestalten.
Bill K
2
Der Ton dieser Antwort könnte verbessert werden. Es liest sich sehr abrupt und hart. Zum Beispiel: "Sagen Sie mir, dass Sie das lesen können. Fahren Sie fort, versuchen Sie es." erscheint sehr aggressiv und könnte umgeschrieben werden als "Welcher der beiden Funktionsaufrufe oben / unten ist leichter zu lesen?" Sie sollten versuchen, den Punkt ohne die Aggression zu vermitteln. Das OP versucht nur zu lernen.
Kyle A
Vergessen Sie nicht, dass das OP auch versucht, wach zu bleiben.
candied_orange
4

Ich würde niemals globale Variablen verwenden, um Parameter zu reduzieren. Der Grund dafür ist, dass globale Variablen von jeder Funktion / jedem Befehl geändert werden können, wodurch die Funktionseingabe unzuverlässig und anfällig für Werte wird, die außerhalb des Funktionsbereichs liegen. Was passiert, wenn die Variable während der Ausführung der Funktion geändert wurde und die Hälfte der Funktion andere Werte als die andere Hälfte aufweist?

Wenn Sie hingegen Parameter übergeben, wird der Gültigkeitsbereich der Variablen auf ihre eigene Funktion beschränkt, sodass nur die Funktion einen Parameter ändern kann, wenn er einmal aufgerufen wurde.

Wenn Sie anstelle eines Parameters globale Variablen übergeben müssen, empfiehlt es sich, den Code neu zu entwerfen.

Nur meine zwei Cent.

Dimos
quelle
"Ich würde niemals globale Variablen verwenden, um Parameter zu reduzieren", stimme vollkommen zu. Es schafft unnötige Kopplung.
Bytedev
2

Ich bin mit Onkel Bob dabei und bin mir einig, dass mehr als 3 Parameter vermieden werden sollten (ich verwende sehr selten mehr als 3 Parameter in einer Funktion). Viele Parameter für eine einzelne Funktion zu haben, verursacht ein größeres Wartungsproblem und ist wahrscheinlich ein Geruch dafür, dass Ihre Funktion zu viel tut / zu viele Aufgaben hat.

Wenn Sie mehr als 3 in einer Methode in einer OO-Sprache verwenden, sollten Sie berücksichtigen, dass die Parameter nicht in irgendeiner Weise miteinander verknüpft sind und dass Sie stattdessen wirklich ein Objekt übergeben sollten.

Wenn Sie mehr (kleinere) Funktionen erstellen, werden Sie auch feststellen, dass Funktionen in der Regel 3 oder weniger Parameter haben. Funktion / Methode extrahieren ist dein Freund :-).

Verwenden Sie keine globalen Variablen, um mehr Parameter zu erhalten! Das ist, eine schlechte Übung gegen eine noch schlechtere zu tauschen!

bytedev
quelle
1

Eine gültige Alternative zu vielen Funktionsparametern ist die Einführung eines Parameterobjekts . Dies ist nützlich, wenn Sie eine zusammengesetzte Methode haben, die (fast) alle Parameter an eine Reihe anderer Methoden übergibt.

In einfachen Fällen ist dies ein einfacher DTO, der nur die alten Parameter als Eigenschaften hat.

Timothy Truckle
quelle
1

Die Verwendung globaler Variablen scheint immer eine einfache Möglichkeit zu sein, Code zu schreiben (insbesondere in einem kleinen Programm), aber es wird schwierig, Ihren Code zu erweitern.

Ja, Sie können die Anzahl der Parameter in einer Funktion reduzieren, indem Sie ein Array verwenden, um die Parameter in einer Entität zu binden.

function <functionname>(var1,var2,var3,var4.....var(n)){}

Die obige Funktion wird bearbeitet und in [using associative array] geändert -

data=array(var1->var1,
           var2->var2
           var3->var3..
           .....
           ); // data is an associative array

function <functionname>(data)

Ich stimme der Antwort von Robert Bristow-Johnson zu : Sie können sogar eine Struktur verwenden, um Daten in einer einzigen Entität zu binden.

Narender Parmar
quelle
1

Schauen Sie sich anhand eines Beispiels aus PHP 4 die Funktionssignatur an für mktime():

  • int mktime ([ int $hour = date("H") [, int $minute = date("i") [, int $second = date("s") [, int $month = date("n") [, int $day = date("j") [, int $year = date("Y") [, int $is_dst = -1 ]]]]]]] )

Findest du das nicht verwirrend? Die Funktion heißt "make time", benötigt jedoch Tages-, Monats- und Jahresparameter sowie drei Zeitparameter. Wie einfach ist es, sich zu erinnern, in welche Reihenfolge sie gehen? Was ist, wenn Sie sehen mktime(1, 2, 3, 4, 5, 2246);? Können Sie das verstehen, ohne sich auf etwas anderes beziehen zu müssen? Wird 2246als 24-Stunden-Zeit "22:46" interpretiert? Was bedeuten die anderen Parameter? Es wäre besser als Objekt.

In PHP 5 gibt es jetzt ein DateTime-Objekt. Unter seinen Methoden sind zwei genannt setDate()und setTime(). Ihre Unterschriften lauten wie folgt:

  • public DateTime setDate ( int $year , int $month , int $day )
  • public DateTime setTime ( int $hour , int $minute [, int $second = 0 ] )

Sie müssen sich immer noch daran erinnern, dass die Reihenfolge der Parameter vom größten zum kleinsten geht, aber es ist eine große Verbesserung. Beachten Sie, dass es keine einzige Methode gibt, mit der Sie alle sechs Parameter gleichzeitig einstellen können. Dazu müssen Sie zwei separate Anrufe tätigen.

Wovon Onkel Bob spricht, ist die Vermeidung einer flachen Struktur. Verwandte Parameter sollten zu einem Objekt zusammengefasst werden. Wenn Sie mehr als drei Parameter haben, ist es sehr wahrscheinlich, dass Sie dort ein Pseudoobjekt haben, mit dem Sie ein geeignetes Objekt für eine größere Trennung erstellen können. Obwohl PHP keine separate haben Dateund Time, Klasse könnte man bedenkt , dass DateTimewirklich ein enthält DateObjekt und ein TimeObjekt.

Sie könnten möglicherweise die folgende Struktur haben:

<?php
$my_date = new Date;
$my_date->setDay(5);
$my_date->setMonth(4);
$my_date->setYear(2246);

$my_time = new Time;
$my_time->setHour(1);
$my_time->setMinute(2);
$my_time->setSecond(3);

$my_date_time = new DateTime;
$my_date_time->setTime($my_time);
$my_date_time->setDate($my_date);
?>

Müssen immer zwei oder drei Parameter eingestellt werden? Wenn Sie nur die Stunde oder den Tag ändern möchten, ist dies jetzt ganz einfach. Ja, das Objekt muss validiert werden, um sicherzustellen, dass jeder Parameter mit den anderen zusammenarbeitet. Dies war jedoch zuvor der Fall.

Das Wichtigste ist, ist es einfacher zu verstehen und deshalb zu pflegen? Der Codeblock am unteren Rand ist größer als eine einzelne mktime()Funktion, aber ich würde behaupten, dass dies viel einfacher zu verstehen ist. Sogar ein Nicht-Programmierer würde nicht viel Mühe haben, herauszufinden, was es tut. Das Ziel ist nicht immer ein kürzerer oder cleverer Code, sondern ein besser wartbarer Code.

Oh, und benutze keine Globalen!

CJ Dennis
quelle
1

Viele gute Antworten hier, aber die meisten sprechen den Punkt nicht an. Warum diese Faustregeln? Es geht um Umfang, es geht um Abhängigkeiten und es geht um die richtige Modellierung.

Globals for argumentes ist schlimmer, weil es nur so aussieht, als hätten Sie es einfacher gemacht, aber in Wirklichkeit haben Sie nur die Komplexität verborgen. Sie sehen es im Prototyp nicht mehr, müssen es aber trotzdem beachten (was schwierig ist, da es nicht mehr für Sie sichtbar ist), und sich mit der Funktionslogik vertraut zu machen, hilft Ihnen möglicherweise nicht weiter Sei eine andere verborgene Logik, die sich hinter deinem Rücken einmischt. Ihr Gültigkeitsbereich ging überall auf und Sie führten eine Abhängigkeit von was auch immer ein, denn was auch immer kann jetzt mit Ihrer Variablen herumspielen. Nicht gut.

Die Hauptsache für eine Funktion ist, dass Sie verstehen können, was sie tut, indem Sie den Prototyp betrachten und aufrufen. Der Name sollte also klar und eindeutig sein. Aber je mehr Argumente es gibt, desto schwieriger wird es, zu verstehen, was es tut. Es erweitert den Spielraum in Ihrem Kopf, zu viele Dinge gehen vor sich, deshalb möchten Sie die Anzahl begrenzen. Es ist wichtig, mit welchen Argumenten Sie es zu tun haben. Einige Argumente sind schlimmer als andere. Ein zusätzlicher optionaler Boolescher Wert, bei dem zwischen Groß- und Kleinschreibung unterschieden werden kann, erschwert das Verständnis der Funktion nicht, sodass Sie keine großen Probleme damit haben möchten. Nebenbei bemerkt, Aufzählungen liefern bessere Argumente als Boolesche Werte, da die Bedeutung einer Aufzählung im Aufruf offensichtlich ist.

Das typische Problem ist nicht, dass Sie eine neue Funktion mit einer enormen Anzahl von Argumenten schreiben. Sie werden mit nur wenigen beginnen, wenn Sie noch nicht erkennen, wie komplex das Problem ist, das Sie wirklich lösen. Je weiter sich Ihr Programm entwickelt, desto länger werden die Argumentlisten. Sobald Sie ein Modell im Kopf haben, möchten Sie es behalten, da es eine sichere Referenz ist, die Sie kennen. Aber im Nachhinein mag das Modell nicht so toll sein. Sie haben einen oder auch einen Schritt in der Logik verpasst und ein oder zwei Entitäten nicht erkannt. "OK ... ich könnte von vorne anfangen und ein oder zwei Tage damit verbringen, meinen Code zu überarbeiten, oder ... ich könnte dieses Argument hinzufügen, damit es schließlich das Richtige tut und damit fertig ist. Vorerst. Für dieses Szenario Um diesen Käfer von meinem Teller zu bekommen, damit ich den Haftnotizzettel zu Ende bewegen kann. "

Je öfter Sie mit der zweiten Lösung arbeiten, desto teurer wird die weitere Wartung und desto schwieriger und unattraktiver wird ein Refaktor.

Es gibt keine Kesselplattenlösung, um die Anzahl der Argumente in einer vorhandenen Funktion zu reduzieren. Nur die Gruppierung in Verbindungen macht die Sache nicht wirklich einfacher, es ist nur eine andere Möglichkeit, die Komplexität unter dem Teppich zu wischen. Wenn Sie es richtig machen, müssen Sie den gesamten Aufrufstapel erneut betrachten und feststellen, was fehlt oder falsch gemacht wurde.

Martin Maat
quelle
0

Ich habe mehrmals festgestellt, dass das Gruppieren vieler Parameter, die zusammen gesendet wurden, die Dinge verbessert hat.

  • Es zwingt Sie, dieser Häufung von Begriffen, die zusammen verwendet werden, einen guten Namen zu geben. Wenn Sie diese Parameter zusammen verwenden, kann es sein, dass sie eine Beziehung haben (oder dass Sie sie überhaupt nicht zusammen verwenden sollten).

  • Einmal mit dem Objekt finde ich in der Regel, dass ein Teil der Funktionalität dieses scheinbar blöden Objekts verschoben werden kann. Es ist normalerweise leicht zu testen und mit großer Kohäsion und geringer Kopplung noch besser zu machen.

  • Wenn ich das nächste Mal einen neuen Parameter hinzufügen muss, habe ich eine gute Möglichkeit, ihn einzuschließen, ohne die Signatur vieler Methoden zu ändern.

Daher funktioniert es möglicherweise nicht immer, aber fragen Sie sich, ob diese Parameterliste in einem Objekt gruppiert werden soll. Und bitte. Verwenden Sie keine untypisierten Klassen wie Tuple, um das Erstellen des Objekts zu vermeiden. Sie verwenden die objektorientierte Programmierung. Es macht Ihnen nichts aus, weitere Objekte zu erstellen, wenn Sie diese benötigen.

Borjab
quelle
0

Bei allem Respekt bin ich mir ziemlich sicher, dass Sie es völlig verpasst haben, eine kleine Anzahl von Parametern in einer Funktion zu haben.

Die Idee ist, dass das Gehirn nur so viele "aktive Informationen" gleichzeitig speichern kann, und wenn Sie n Parameter in einer Funktion haben, haben Sie n weitere "aktive Informationen", die einfach und genau in Ihrem Gehirn sein müssen Verstehen Sie, was der Code tut (Steve McConnell sagt in Code Complete (ein viel besseres Buch, IMO) etwas Ähnliches über 7 Variablen im Körper einer Methode: Selten erreichen wir das, aber mehr und Sie verlieren das Fähigkeit, alles im Kopf zu behalten).

Der Sinn einer geringen Anzahl von Variablen besteht darin, die kognitiven Anforderungen für die Arbeit mit diesem Code gering zu halten, damit Sie effektiver daran arbeiten (oder ihn lesen) können. Eine Nebenursache dafür ist, dass gut faktorisierter Code tendenziell immer weniger Parameter hat (z. B. gruppiert schlecht faktorisierter Code eine Menge Dinge in einem Durcheinander).

Durch die Übergabe von Objekten anstelle von Werten erhalten Sie möglicherweise eine Abstraktionsebene für Ihr Gehirn, da jetzt klar sein muss, dass ich hier mit einem Suchkontext arbeiten muss, anstatt über die 15 Eigenschaften nachzudenken, die sich möglicherweise in diesem Suchkontext befinden .

Bei dem Versuch, globale Variablen zu verwenden, sind Sie völlig in die falsche Richtung gegangen. Jetzt haben Sie nicht nur das Problem nicht gelöst, dass zu viele Parameter für eine Funktion vorhanden sind, sondern Sie haben dieses Problem aufgegriffen und in ein viel, viel besseres Problem geworfen , das Sie jetzt in Ihrem Kopf herumtragen müssen!

Anstatt nur auf der Funktionsebene zu arbeiten, müssen Sie jetzt auch den globalen Umfang Ihres Projekts berücksichtigen (gawd, wie schrecklich! Ich schaudere ...). Sie haben nicht einmal alle Ihre Informationen in der Funktion vor sich (Mist, wie heißt diese globale Variable?) (Ich hoffe, dies wurde durch nichts anderes geändert, seit ich diese Funktion aufgerufen habe).

Variablen mit globalem Gültigkeitsbereich sind eines der schlimmsten Dinge in einem Projekt (groß oder klein). Sie bezeichnen eine Behinderung für eine ordnungsgemäße Bereichsverwaltung, die für die Programmierung von grundlegender Bedeutung ist. Sie. Sind. Böse.

Indem Sie Parameter aus Ihrer Funktion verschieben und in globale Werte einfügen, haben Sie sich selbst in den Boden (oder das Bein oder Gesicht) geschossen. Und Gott bewahre, dass du jemals entscheidest, dass ich dieses Globale für etwas anderes wiederverwenden kann ... meine Gedanken zittern bei dem Gedanken.

Das ganze Ideal ist es, die Dinge einfach zu verwalten, und globale Variablen werden das NICHT tun. Ich würde sogar sagen, dass dies eines der schlimmsten Dinge ist, die Sie tun können, um in die entgegengesetzte Richtung zu gehen.

JLeach
quelle
-1

Ich habe einen sehr effektiven Ansatz (in JavaScript) gefunden, um die Reibung zwischen den Schnittstellen zu minimieren: Verwenden Sie eine einheitliche Schnittstelle für alle Module , insbesondere für einzelne Parameterfunktionen.

Wenn Sie mehrere Parameter benötigen: Verwenden Sie ein einzelnes Objekt / Hash oder Array.

Tragen Sie mit mir, ich verspreche, ich trolle nicht ...

Bevor Sie sagen "Was nützt eine Single-Param-Funktion?" Oder "Gibt es einen Unterschied zwischen 1-Array- und Multi-Arg-Funktionen?"

Nun ja. Es ist vielleicht optisch subtil, aber der Unterschied ist vielfältig - ich erkunde die vielen Vorteile hier

Anscheinend denken einige Leute, dass 3 die richtige Anzahl von Argumenten ist. Einige denken, es ist 2. Nun, das wirft immer noch die Frage auf, "welcher Parameter geht in arg [0]?" Anstatt die Option auszuwählen, die die Schnittstelle mit einer strengeren Deklaration einschränkt.

Ich denke, ich plädiere für eine radikalere Position: Verlassen Sie sich nicht auf Positionsargumente. Ich fühle mich einfach zerbrechlich und führe zu Auseinandersetzungen über die Position der verdammten Argumente. Überspringe es und gehe zum unvermeidlichen Kampf um die Namen von Funktionen und Variablen über. 😉

Im Ernst, nachdem sich der Name gelegt hat, haben Sie hoffentlich den folgenden Code:

function sendMessage({toUser, fromUser, subject, body}) { }

// And call the method like so:
sendMessage({toUser: this.parentUser, fromUser: this.currentUser, subject: ‘Example Alert’})

Dan Levy
quelle
6
Das Fälschen benannter Argumente übergibt nicht wirklich nur ein Argument.
JDługosz
Warum ist es "falsch", wenn ich ein Ziel erreicht habe, das ich mir vorgenommen habe? Ich lege eine höhere Priorität auf benannte Argumente. Da Positionsargumente für den Aufruf von Code nicht offensichtlich sind und bei der Anzahl der benannten Funktionen, die ein Entwickler speichern muss, ist es nicht hilfreich, sich daran zu erinnern, welche Parameter wo und welche optional sind. ... Schließlich möchten Sie nach den Optionen einen erforderlichen Parameter hinzufügen, und viel Glück beim Dokumentieren und Aufrüsten dieses Kartenhauses.
Dan Levy
2
Benannte Params sind auch ein Trick, um das Lernen zu verstärken - Menschen messen Wortsammlungen mehr Bedeutung bei.
Dan Levy