Ich habe mir einige Antworten angesehen und bei Google gesucht, konnte aber nichts Hilfreiches finden (dh das hätte keine unangenehmen Nebenwirkungen).
Mein abstraktes Problem ist, dass ich ein Objekt habe und eine lange Abfolge von Operationen daran ausführen muss. Ich betrachte es als eine Art Fließband, als würde man ein Auto bauen.
Ich glaube, diese Objekte würden Methodenobjekte genannt .
In diesem Beispiel hätte ich also irgendwann eine CarWithoutUpholstery, auf der ich dann installBackSeat, installFrontSeat, installWoodenInserts ausführen müsste (die Vorgänge stören sich nicht gegenseitig und könnten sogar parallel ausgeführt werden). Diese Operationen werden von CarWithoutUpholstery.worker () ausgeführt und ergeben ein neues Objekt, das eine CarWithUpholstery wäre, auf der ich dann möglicherweise cleanInsides (), verifyNoUpholsteryDefects () usw. ausführen würde.
Die Operationen in einer einzelnen Phase sind bereits unabhängig, dh ich habe bereits mit einer Teilmenge davon zu kämpfen, die in beliebiger Reihenfolge ausgeführt werden kann (vordere und hintere Sitze können in beliebiger Reihenfolge installiert werden).
Meine Logik verwendet derzeit Reflection, um die Implementierung zu vereinfachen.
Das heißt, sobald ich eine CarWithoutUpholstery habe, überprüft sich das Objekt selbst auf Methoden namens performSomething (). Zu diesem Zeitpunkt werden alle folgenden Methoden ausgeführt:
myObject.perform001SomeOperation();
myObject.perform002SomeOtherOperation();
...
beim Überprüfen von Fehlern und Sachen. Während der Reihenfolge der Operation ist unwichtig, habe ich eine lexikographische Ordnung im Fall zugewiesen immer ich entdecken einige Reihenfolge nach alle wichtig ist. Dies widerspricht YAGNI , kostet aber sehr wenig - eine einfache Sortierung () - und könnte eine massive Umbenennung der Methode (oder die Einführung einer anderen Methode zur Durchführung von Tests, z. B. einer Reihe von Methoden) auf der ganzen Linie ersparen.
Ein anderes Beispiel
Sagen wir, anstatt ein Auto zu bauen, muss ich einen Geheimpolizeibericht über jemanden erstellen und ihn meinem bösen Oberherrn vorlegen . Mein letztes Objekt wird ein ReadyReport sein. Um es zu konstruieren, sammle ich zunächst grundlegende Informationen (Vor- und Nachname, Ehepartner ...). Dies ist meine Phase A. Je nachdem, ob es einen Ehepartner gibt oder nicht, muss ich möglicherweise mit den Phasen B1 oder B2 fortfahren und Sexualitätsdaten für eine oder zwei Personen sammeln. Dies besteht aus mehreren verschiedenen Anfragen an verschiedene Evil Minions, die das Nachtleben, Straßenkameras, Sexshop-Verkaufsbelege und was nicht kontrollieren. Und so weiter und so fort.
Wenn das Opfer keine Familie hat, werde ich nicht einmal in die GetInformationAboutFamily-Phase eintreten, aber wenn ich dies tue, ist es unerheblich, ob ich zuerst den Vater oder die Mutter oder die Geschwister (falls vorhanden) anvisiere. Das kann ich aber nicht, wenn ich keinen FamilyStatusCheck durchgeführt habe, der daher zu einer früheren Phase gehört.
Es funktioniert alles wunderbar ...
- Wenn ich eine zusätzliche Operation benötige, muss ich nur eine private Methode hinzufügen.
- Wenn die Operation mehreren Phasen gemeinsam ist, kann ich sie von einer Oberklasse erben lassen.
- Operationen sind einfach und in sich geschlossen. Kein Wert von einer Operation wird jemals von einer der anderen benötigt (Operationen, die in einer anderen Phase ausgeführt werden).
- Objekte auf der ganzen Linie müssen nicht viele Tests durchführen, da sie nicht einmal existieren könnten , wenn ihre Erstellerobjekte diese Bedingungen überhaupt nicht überprüft hätten. Dh, wenn Einsätze im Armaturenbrett platziert, das Armaturenbrett Reinigen und das Armaturenbrett zu überprüfen, muß ich nicht überprüfen, ob ein Armaturenbrett tatsächlich ist es .
- es ermöglicht ein einfaches Testen. Ich kann ein Teilobjekt leicht verspotten und eine beliebige Methode darauf ausführen, und alle Operationen sind deterministische Blackboxen.
...aber...
Das Problem trat auf, als ich eine letzte Operation in eines meiner Methodenobjekte einfügte, wodurch das Gesamtmodul einen obligatorischen Komplexitätsindex überschritt ("weniger als N private Methoden").
Ich habe die Angelegenheit bereits nach oben gebracht und vorgeschlagen, dass in diesem Fall der Reichtum an privaten Methoden kein Hinweis auf eine Katastrophe ist. Die Komplexität ist da, aber es ist da , weil der Betrieb ist komplex, und es ist eigentlich gar nicht so komplex - es ist nur ist lang .
Am Beispiel des Evil Overlord besteht mein Problem darin, dass der Evil Overlord (auch bekannt als He Who Shall Not Denied ) alle Ernährungsinformationen angefordert hat. Meine Dietary Minions haben mir mitgeteilt, dass ich Restaurants, Küchenzeilen, Straßenverkäufer, nicht lizenzierte Straßenverkäufer und Gewächshäuser abfragen muss Besitzer usw. und der böse (Unter-) Overlord - bekannt als Er, der auch nicht geleugnet werden soll - beschweren sich, dass ich in der GetDietaryInformation-Phase zu viele Abfragen durchführe.
Hinweis : Mir ist bewusst, dass dies unter verschiedenen Gesichtspunkten überhaupt kein Problem darstellt (Ignorieren möglicher Leistungsprobleme usw.). Alles, was passiert, ist, dass eine bestimmte Metrik unglücklich ist, und es gibt eine Rechtfertigung dafür.
Was ich denke, ich könnte tun
Abgesehen von der ersten sind alle diese Optionen machbar und meiner Meinung nach vertretbar.
- Ich habe überprüft, dass ich hinterhältig sein und die Hälfte meiner Methoden deklarieren kann
protected
. Aber ich würde eine Schwäche im Testverfahren ausnutzen und abgesehen davon, dass ich mich rechtfertige, wenn ich erwischt werde, mag ich das nicht. Es ist auch eine Notlösung. Was ist, wenn sich die Anzahl der erforderlichen Operationen verdoppelt? Unwahrscheinlich, aber was dann? - Ich kann diese Phase willkürlich in AnnealedObjectAlpha, AnnealedObjectBravo und AnnealedObjectCharlie aufteilen und habe ein Drittel der Operationen, die in jeder Phase ausgeführt werden. Ich habe den Eindruck, dass dies tatsächlich die Komplexität erhöht (N-1 weitere Klassen), ohne dass dies von Vorteil ist, außer dass ein Test bestanden wird. Ich kann natürlich davon ausgehen, dass ein CarWithFrontSeatsInstalled und ein CarWithAllSeatsInstalled logisch aufeinanderfolgende Stufen sind. Das Risiko, dass Alpha später eine Bravo-Methode benötigt, ist gering und noch geringer, wenn ich sie gut spiele. Aber dennoch.
- Ich kann verschiedene Operationen, die aus der Ferne ähnlich sind, in einer einzigen zusammenfassen.
performAllSeatsInstallation()
. Dies ist nur eine Notlösung und erhöht die Komplexität der einzelnen Operation. Wenn ich die Operationen A und B jemals in einer anderen Reihenfolge ausführen muss und sie in E = (A + C) und F (B + D) gepackt habe, muss ich E und F entbündeln und den Code mischen . - Ich kann eine Reihe von Lambda-Funktionen verwenden und die Prüfung insgesamt ordentlich umgehen, aber ich finde das klobig. Dies ist jedoch die bisher beste Alternative. Es würde das Nachdenken loswerden. Die beiden Probleme, die ich habe, sind, dass ich wahrscheinlich gebeten werde, alle Methodenobjekte neu zu schreiben , nicht nur die hypothetischen
CarWithEngineInstalled
, und obwohl dies eine sehr gute Arbeitsplatzsicherheit wäre, spricht es wirklich nicht allzu viel an. und dass der Code Coverage Checker Probleme mit Lambdas hat (die lösbar sind, aber immer noch ).
Damit...
- Was ist meiner Meinung nach meine beste Option?
- Gibt es einen besseren Weg, den ich nicht in Betracht gezogen habe? ( Vielleicht sollte ich besser sauber kommen und direkt fragen, was es ist? )
- Ist dieses Design hoffnungslos fehlerhaft, und ich gebe besser Niederlage und Graben zu - diese Architektur insgesamt? Nicht gut für meine Karriere, aber wäre es auf lange Sicht besser, schlecht gestalteten Code zu schreiben?
- Ist meine derzeitige Wahl tatsächlich der One True Way, und ich muss kämpfen, um bessere Qualitätsmetriken (und / oder Instrumente) zu installieren? Für diese letzte Option benötige ich Referenzen ... Ich kann nicht einfach mit der Hand auf das @PHB winken, während ich murmle. Dies sind nicht die Metriken, nach denen Sie suchen . Egal wie gerne ich dazu in der Lage wäre