Ich habe einige Rohdaten, für die ich viele Dinge tun muss (verschieben, drehen, entlang einer bestimmten Achse skalieren, bis zur Endposition drehen), und ich bin mir nicht sicher, wie ich dies am besten tun kann, um die Lesbarkeit des Codes zu gewährleisten. Einerseits kann ich eine einzelne Methode mit vielen Parametern (10+) erstellen, um das zu tun, was ich brauche, aber dies ist ein Albtraum beim Lesen von Code. Andererseits könnte ich mehrere Methoden mit jeweils 1-3 Parametern erstellen, aber diese Methoden müssten in einer ganz bestimmten Reihenfolge aufgerufen werden, um das richtige Ergebnis zu erzielen. Ich habe gelesen, dass es für Methoden am besten ist, eine Sache zu tun und sie gut zu machen, aber es scheint, dass viele Methoden aufgerufen werden müssen, um Code für schwer zu findende Fehler zu öffnen.
Gibt es ein Programmierparadigma, mit dem ich Fehler minimieren und das Lesen von Code vereinfachen könnte?
quelle
Antworten:
Vorsicht vor zeitlicher Kopplung . Dies ist jedoch nicht immer ein Problem.
Wenn Sie die Schritte der Reihe nach ausführen müssen, erzeugt Schritt 1 ein für Schritt 2 erforderliches Objekt (z. B. einen Dateistream oder eine andere Datenstruktur). Dies setzt voraus, dass die zweite Funktion nach der ersten aufgerufen werden muss . Es ist nicht einmal möglich, sie versehentlich in der falschen Reihenfolge aufzurufen.
Indem Sie Ihre Funktionalität in mundgerechte Teile aufteilen, ist jedes Teil leichter zu verstehen und auf jeden Fall einfacher für sich zu testen. Wenn Sie eine riesige 100-Zeilen-Funktion und etwas in der Mitte haben, wie sagt Ihnen Ihr fehlgeschlagener Test, was falsch ist? Wenn eine Ihrer fünf Zeilenmethoden unterbrochen wird, werden Sie durch den fehlgeschlagenen Komponententest sofort zu dem Code geleitet, der überprüft werden muss.
So sollte komplexer Code aussehen:
Zu jedem Zeitpunkt während der Konvertierung von Rohdaten in ein fertiges Widget gibt jede Funktion etwas zurück, das für den nächsten Schritt im Prozess erforderlich ist. Man kann aus Schlacke keine Legierung bilden, man muss sie zuerst schmelzen (reinigen). Ein Widget darf nicht ohne die entsprechende Erlaubnis (zB Stahl) als Eingabe erstellt werden.
Die spezifischen Details jedes Schritts sind in einzelnen Funktionen enthalten, die getestet werden können: Anstatt den gesamten Prozess des Gesteinsabbaus und der Erstellung von Widgets als Einheit zu testen, testen Sie jeden einzelnen Schritt. Jetzt können Sie auf einfache Weise sicherstellen, dass Sie den genauen Grund eingrenzen können, wenn der Prozess zum Erstellen eines Widgets fehlschlägt.
Abgesehen von den Vorteilen des Testens und des Beweises der Korrektheit ist das Schreiben von Code auf diese Weise viel einfacher zu lesen. Niemand kann eine riesige Parameterliste verstehen . Zerlegen Sie es in kleine Stücke und zeigen Sie, was jedes kleine Stück bedeutet: das ist grokkable .
quelle
Das Argument "muss in der richtigen Reihenfolge ausgeführt werden" ist umstritten, da so gut wie der gesamte Code in der richtigen Reihenfolge ausgeführt werden muss. Schließlich können Sie nicht in eine Datei schreiben, sondern sie öffnen und schließen, oder?
Sie sollten sich darauf konzentrieren, was Ihren Code am wartungsfreundlichsten macht. Dies bedeutet normalerweise Schreibfunktionen, die klein und leicht verständlich sind. Jede Funktion sollte einen einzigen Zweck haben und keine unerwarteten Nebenwirkungen haben.
quelle
Ich würde einen » ImageProcessor erstellen « (oder einen beliebigen Namen, der zu Ihrem Projekt passt) und ein Konfigurationsobjekt ProcessConfiguration erstellen , das alle notwendigen Parameter enthält.
Innerhalb des Bildprozessors kapseln Sie den gesamten Prozess hinter einer einzigen Methode
process()
Diese Methode ruft die transformierende Methoden in der richtigen Reihenfolge
shift()
,rotate()
. Jede Methode erhält entsprechende Parameter aus den übergebenen ProcessConfiguration .ich benutzte flüssige Schnittstellen verwendet
Dies ermöglicht eine rasche Initialisierung (wie oben gezeigt).
Der offensichtliche Vorteil, notwendige Parameter in einem Objekt zu kapseln. Ihre Methodensignaturen werden lesbar:
private void shift(Image i, ProcessConfiguration c)
Es geht darum , ein Bild zu verschieben und detaillierte Parameter sind irgendwie konfiguriert .
Alternativ können Sie eine ProcessingPipeline erstellen :
Ein Methodenaufruf einer Methode
processImage
würde eine solche Pipeline instanziieren und transparent machen, was und in welcher Reihenfolge getan wird: Verschieben , Drehenquelle
Haben Sie darüber nachgedacht, Currys zu verwenden ? Stellen Sie sich vor, Sie haben eine Klasse
Processee
und eine KlasseProcessor
:Jetzt können Sie die Klasse
Processor
durch zwei Klassen ersetzenProcessor1
undProcessor2
:Anschließend können Sie die Vorgänge in der richtigen Reihenfolge aufrufen:
Sie können dieses Muster mehrmals anwenden, wenn Sie mehr als zwei Parameter haben. Sie können die Argumente auch nach Belieben gruppieren, dh Sie müssen nicht für jede
process
Methode genau ein Argument verwenden.quelle