[Parameters] Wie viele Konstruktorargumente sind zu viele?


Answers

Ich sehe, dass einige Leute sieben als Obergrenze empfehlen. Anscheinend ist es nicht wahr, dass die Menschen sieben Dinge gleichzeitig in ihrem Kopf halten können; sie können sich nur an vier erinnern (Susan Weinschenk, 100 Dinge, die jeder Designer über Menschen wissen muss , 48). Trotzdem halte ich vier für eine Art Erdumlaufbahn. Aber das liegt daran, dass mein Denken von Bob Martin verändert wurde.

In Clean Code argumentiert Onkel Bob für drei als allgemeine Obergrenze für die Anzahl der Parameter. Er macht den radikalen Anspruch (40):

Die ideale Anzahl von Argumenten für eine Funktion ist Null (niladisch). Als nächstes kommt eins (monadisch), dicht gefolgt von zwei (dyadisch). Drei Argumente (Triaden) sollten nach Möglichkeit vermieden werden. Mehr als drei (polyadisch) erfordern eine ganz besondere Rechtfertigung - und sollten dann sowieso nicht verwendet werden.

Er sagt das wegen der Lesbarkeit; aber auch wegen der Testbarkeit:

Stellen Sie sich die Schwierigkeit vor, alle Testfälle zu schreiben, um sicherzustellen, dass alle verschiedenen Kombinationen von Argumenten ordnungsgemäß funktionieren.

Ich ermutige Sie, eine Kopie seines Buches zu finden und seine vollständige Diskussion der Funktionsargumente zu lesen (40-43).

Ich stimme denen zu, die das Prinzip der Einheitlichen Verantwortung erwähnt haben. Es fällt mir schwer zu glauben, dass eine Klasse, die mehr als zwei oder drei Werte / Objekte ohne vernünftige Vorgaben benötigt, wirklich nur eine Verantwortung hat und nicht besser wäre, wenn eine andere Klasse extrahiert wird.

Nun, wenn Sie Ihre Abhängigkeiten durch den Konstruktor injizieren, gelten die Argumente von Bob Martin darüber, wie einfach es ist, den Konstruktor aufzurufen, nicht so sehr (denn normalerweise gibt es nur einen Punkt in Ihrer Anwendung, wo Sie das verdrahten, oder sogar haben einen Rahmen, der es für Sie tut). Das Prinzip der Einzelverantwortung ist jedoch immer noch relevant: Sobald eine Klasse vier Abhängigkeiten hat, halte ich den Geruch für sehr viel Arbeit.

Wie bei allen Dingen in der Informatik gibt es jedoch zweifellos gültige Fälle für eine große Anzahl von Konstruktorparametern. Verzerren Sie Ihren Code nicht, um die Verwendung einer großen Anzahl von Parametern zu vermeiden. Wenn Sie jedoch eine große Anzahl von Parametern verwenden, halten Sie an und denken Sie darüber nach, da dies möglicherweise bedeutet, dass Ihr Code bereits verzerrt ist.

Question

Angenommen, Sie haben eine Klasse mit dem Namen Kunde, die die folgenden Felder enthält:

  • Nutzername
  • Email
  • Vorname
  • Familienname, Nachname

Nehmen wir außerdem an, dass gemäß Ihrer Geschäftslogik für alle Customer-Objekte diese vier Eigenschaften definiert sein müssen.

Jetzt können wir das ganz einfach tun, indem wir den Konstruktor dazu zwingen, jede dieser Eigenschaften anzugeben. Aber es ist ziemlich einfach zu sehen, wie dies außer Kontrolle geraten kann, wenn Sie gezwungen sind, dem Kundenobjekt mehr erforderliche Felder hinzuzufügen.

Ich habe Kurse gesehen, die mehr als 20 Argumente in ihren Konstruktor aufgenommen haben, und es ist einfach schmerzhaft, sie zu verwenden. Wenn Sie diese Felder jedoch nicht benötigen, laufen Sie Gefahr, nicht definierte Informationen oder, noch schlimmer, Fehler bei der Objektreferenzierung zu haben, wenn Sie sich auf den aufrufenden Code verlassen, um diese Eigenschaften anzugeben.

Gibt es Alternativen dazu oder müssen Sie sich nur entscheiden, ob die X-Anzahl der Konstruktorargumente zu groß ist, um damit zu leben?




Ich denke, es hängt alles von der Situation ab. Für so etwas wie Ihr Beispiel, eine Kundenklasse, würde ich nicht riskieren, dass diese Daten bei Bedarf nicht definiert werden. Auf der anderen Seite würde das Übergeben einer Struktur die Argumentliste aufklären, aber Sie würden noch viele Dinge in der Struktur definieren müssen.




Wenn Sie unhandlich viele Argumente haben, dann packen Sie sie einfach zusammen in structs / POD-Klassen, vorzugsweise als innere Klassen der Klasse, die Sie konstruieren. Auf diese Weise können Sie die Felder immer noch benötigen, während Sie den Code, der den Konstruktor aufruft, vernünftig lesbar machen.




Stil zählt für eine Menge, und es scheint mir, dass, wenn es einen Konstruktor mit 20+ Argumenten gibt, das Design geändert werden sollte. Stellen Sie angemessene Standardwerte bereit.




Ich stimme dem 7-Punkte-Limit zu, das Boojiboy erwähnt. Darüber hinaus kann es sich lohnen, anonyme (oder spezialisierte) Typen, IDictionary oder Indirektionen über den Primärschlüssel zu einer anderen Datenquelle zu betrachten.




Ich denke, Ihre Frage bezieht sich mehr auf das Design Ihrer Klassen als auf die Anzahl der Argumente im Konstruktor. Wenn ich 20 Daten (Argumente) brauchte, um ein Objekt erfolgreich zu initialisieren, würde ich wahrscheinlich überlegen, die Klasse aufzubrechen.




Wenn es nicht mehr als ein Argument ist, verwende ich immer Arrays oder Objekte als Konstruktorparameter und stütze mich auf die Fehlerprüfung, um sicherzustellen, dass die erforderlichen Parameter vorhanden sind.