Was ist ein Ausgabeargument, auf das in Martins Clean Code verwiesen wird?

14

Auf Seite 45 von Robert C. Martins Clean Code: A Handbook of Agile Software Craftsmanship schreibt Martin, dass Ausgabeargumente vermieden werden sollten. Ich habe Probleme, die Bedeutung von "Ausgabeargument" zu verstehen und warum sie vermieden werden sollten.

Martins Beispiel für ein Ausgabeargument appendFooter(s);ruft die Funktion auf public void appendFooter(StringBuffer report). Seine Verbesserung des Codes istreport.appendFooter();

Vielleicht liegt es am fehlenden Codekontext, aber ich sehe nicht, wie die Verwendung von Ausgabeargumenten als schlechte Codierung angesehen wird. Könnte jemand das Konzept erklären oder ein zusätzliches Codebeispiel angeben, um dies zu verstehen?

Würde die folgende Funktion nach dem obigen Prinzip auch als Beispiel für unreinen Code angesehen werden?

int[] numberArray = {3, 5, 7, 1};
sortArray(numberArray);

Wenn das oben Gesagte gegen Martins Prinzip verstößt, keine Ausgabeargumente zu verwenden, ist es besser, ein Objekt mit einem Array als Feld und einer Funktion zu haben, die zum Sortieren des Arrays aufgerufen werden kann.

ObjectWithArrayField numberArray = new ObjectWithArrayField(3, 5, 7, 1);
numberArray.sort();
WP0987
quelle

Antworten:

10

Bob Martin spricht einfach über Lesbarkeit .

Das Problem mit dem appendFooterBeispiel ist, wenn Sie die Codezeile appendFooter(s)irgendwo in einem Programm finden, dass es nicht sofort offensichtlich ist, ob dieser Aufruf sals Eingabe genommen und irgendwo angehängt wird oder ob er snur übergeben wird, um die Ausgabe dieser Funktion zu übernehmen. Um sicherzugehen, müssen Sie die Dokumentation der Funktion überprüfen. Ein Anruf wie dieser report.appendFooter()vermeidet dieses Problem: Es ist jetzt viel offensichtlicher, was passiert.

Beachten Sie jedoch, dass Bob Martin nicht sagt, dass "niemals Ausgabeargumente verwendet werden". Er sagt, "im Allgemeinen sollten Sie es vermeiden, weil es Ihnen dabei hilft, Ihren Code ein bisschen sauberer zu halten". Das ist also keine blinde Frachtkultregel, der man blind folgen sollte.

SortDie Methoden für Standardarrays und -sammlungen sind etwas unterschiedlich. Wenn die sortMethode eine Member-Funktion für jeden Standard-Array-Datentyp ist, hat dies aus Sicht des Sprachdesigners einige Nachteile. Wenn Sie beispielsweise über eine Methode wie Array.sortdiese verfügen , können Sie diese Funktion außerhalb der Java-Laufzeit in der Standardbibliothek belassen. Wenn Sie jedoch einen einzelnen Auflistungstyp erstellen würden, der manchmal sortiert werden muss, wäre das Hinzufügen sorteiner Elementfunktion in der Tat eine bessere Idee, als dies in einer separaten Klasse zu tun.

Doc Brown
quelle
2
sortArray(numberArray)Natürlich ist alles numberArrayin Ordnung. Oder wird eine Kopie erstellt numberArray, die Kopie sortiert und die sortierte Kopie zurückgegeben, ohne Änderungen vorzunehmen numberArray?
8bittree
@ 8bittree: Das ist wahr, aber das ist hier nicht der Diskussionspunkt - eine sort()Methode eines Containers kann auch an Ort und Stelle funktionieren, ohne ein "Ausgabeargument" zu verwenden. Nur weil sortArray(numberArray)es sich um eine In-Place-Methode handelt, ist dies absolut kein Grund, der die "Ausgabe-Argument-Form" rechtfertigt.
Doc Brown
1
Mein Punkt war eher, dass es nicht ganz offensichtlich ist, was zu sortArray(numberArray)tun ist. Es kann offensichtlich sein, dass es vorhanden sein muss, wenn es nicht denselben Typ zurückgibt, den es akzeptiert. Aber ohne den Rückgabetyp zu sehen oder wenn der Rückgabetyp mit dem Eingabetyp übereinstimmt, ist dies unklar, ohne die Definition zu betrachten.
8bittree
1
@ 8bittree: Ok, du hast mich erwischt, ich habe die betreffende Aussage aus meiner Antwort entfernt. Das von Ihnen beschriebene Problem verschwindet jedoch nicht, wenn Sie eine Member-Funktion verwenden. Sogar eine Sortier-Member-Funktion könnte sich so verhalten.
Doc Brown
10

Es geht darum, einen unerwarteten Mechanismus für die Rückgabe eines Werts aus der Funktion zu verwenden, der normalerweise darauf zurückzuführen ist, dass in der Funktion zu viel getan oder Verantwortlichkeiten falsch ausgerichtet wurden. Die beste Methode, das Ergebnis einer Funktion zu kommunizieren, ist die Verwendung des Rückgabewerts. Ich hoffe das ist selbstverständlich. In objektorientierten Sprachen besteht die zweitbeste Methode darin, das Objekt zu mutieren.

Zwischen diesen beiden Optionen gibt es so viele klare, offensichtliche Möglichkeiten, das Ergebnis einer Funktion zu kommunizieren, dass, wenn Sie jemals die Argumente als einziges Mittel ändern möchten, etwas in Ihrer Architektur schief gelaufen ist. Sie müssen Ihre Klassenverantwortung neu ordnen, damit derjenige, der die Mutation vornimmt, die Daten besitzt.

Die einzige Ausnahme sind sehr generische Algorithmen. Beispielsweise kann ein Sortieralgorithmus zu Recht von den sortierten Containern getrennt sein, wenn er über seine öffentliche Schnittstelle generisch auf einen beliebigen Containertyp angewendet werden kann. Eine One-Shot- appendFooterFunktion hat diese Entschuldigung nicht.

Karl Bielefeldt
quelle