In meinem Programmdesign komme ich oft an den Punkt, an dem ich Objektinstanzen durch mehrere Klassen führen muss. Zum Beispiel, wenn ich einen Controller habe, der eine Audiodatei lädt und sie dann an einen Player weitergibt, und der Player sie an den playerRunnable weitergibt, der sie wieder an eine andere Stelle weitergibt usw. Es sieht irgendwie schlecht aus, aber ich tue es nicht weiß, wie man es vermeidet. Oder ist es in Ordnung, dies zu tun?
EDIT: Vielleicht ist das Player-Beispiel nicht das beste, weil ich die Datei später laden könnte, aber in anderen Fällen funktioniert das nicht.
quelle
Interessant, dass noch niemand über unveränderliche Objekte gesprochen hat. Ich würde argumentieren, dass es eigentlich eine gute Sache ist, ein unveränderliches Objekt durch alle Ebenen zu führen , anstatt für jede Ebene viele kurzlebige Objekte zu erstellen.
Es gibt einige großartige Diskussionen über Unveränderlichkeit von Eric Lippert in seinem Blog
Andererseits würde ich argumentieren, dass das Übergeben von veränderlichen Objekten zwischen Ebenen schlechtes Design ist. Sie erstellen im Wesentlichen eine Ebene mit dem Versprechen, dass die umgebenden Ebenen sie nicht so verändern, dass der Code beschädigt wird.
quelle
Das Weitergeben von Objektinstanzen ist normal. Es reduziert die Notwendigkeit, den Status (dh Instanzvariablen) beizubehalten, und entkoppelt den Code von seinem Ausführungskontext.
Ein Problem, mit dem Sie möglicherweise konfrontiert sind, ist das Refactoring, wenn Sie die Signaturen mehrerer Methoden entlang der Aufrufkette ändern müssen, um auf die sich ändernden Parameteranforderungen einer Methode in der Nähe des unteren Endes dieser Kette zu reagieren. Es kann jedoch durch den Einsatz moderner Softwareentwicklungstools, die beim Refactoring helfen, gemildert werden.
quelle
Möglicherweise geringfügig, aber es besteht die Gefahr, dass diese Referenz irgendwo in einer der Ebenen zugewiesen wird, was möglicherweise später zu einer herabhängenden Referenz oder einem Speicherverlust führt.
quelle
Wenn Sie Objekte einfach deshalb weitergeben, weil sie in einem entfernten Bereich Ihres Codes benötigt werden, kann die Verwendung der Inversion von Steuerungs- und Abhängigkeitsinjektionsentwurfsmustern zusammen mit optional einem geeigneten IoC-Container Probleme beim Transport von Objektinstanzen auf angenehme Weise lösen. Ich habe es für ein mittelgroßes Projekt verwendet und würde nie wieder in Betracht ziehen, einen großen Teil des Servercodes zu schreiben, ohne ihn zu verwenden.
quelle
Das Weitergeben von Daten durch mehrere Ebenen ist keine schlechte Sache, sondern die einzige Möglichkeit, mit der ein geschichtetes System arbeiten kann, ohne die geschichtete Struktur zu verletzen. Das Anzeichen für Probleme ist, dass Sie Ihre Daten an mehrere Objekte in derselben Ebene weitergeben, um Ihr Ziel zu erreichen.
quelle
Schnelle Antwort: Es ist nichts Falsches daran , Instanzen von Objekten zu übergeben. Wie bereits erwähnt, besteht der Punkt darin, die Zuweisung dieser Referenz in allen Ebenen zu überspringen, was möglicherweise zu einer baumelnden Referenz oder zu Speicherlecks führen kann.
In unseren Projekten verwenden wir diese Methode , um DTOs (Datenübertragungsobjekte) zwischen Ebenen zu übertragen. Dies ist eine sehr hilfreiche Methode . Wir verwenden unsere dto-Objekte auch wieder, um einmal komplexer zu konstruieren, beispielsweise für zusammenfassende Informationen.
quelle
Ich bin in erster Linie ein Web-UI-Entwickler, aber für mich scheint es, als würde sich Ihr intuitives Unbehagen weniger auf den Durchgang der Instanz als vielmehr auf die Tatsache auswirken, dass Sie mit diesem Controller ein wenig prozedural vorgehen. Sollte Ihr Controller all diese Details ins Schwitzen bringen? Warum verweist es sogar auf mehr als einen Objektnamen, um Audio abzuspielen?
Beim OOP-Design denke ich eher darüber nach, was immer grün ist und was sich mit größerer Wahrscheinlichkeit ändert. Das Thema, das geändert werden muss, ist das, was Sie in Ihre größeren Objektboxen einfügen möchten, damit Sie konsistente Benutzeroberflächen beibehalten können, selbst wenn sich die Spieler ändern oder neue Optionen hinzugefügt werden. Oder Sie möchten Audioobjekte oder -komponenten im Großhandel austauschen.
In diesem Fall muss Ihr Controller erkennen, dass eine Audiodatei abgespielt werden muss, und dann über eine konsistente / immergrüne Methode verfügen, um sie abzuspielen. Das Audioplayer-Zeug auf der anderen Seite könnte sich leicht ändern, wenn Technologie und Plattformen geändert oder neue Auswahlmöglichkeiten hinzugefügt werden. All diese Details sollten sich unter der Oberfläche eines größeren zusammengesetzten Objekts, IMO, befinden, und Sie sollten Ihren Controller nicht neu schreiben müssen, wenn sich die Details der Audiowiedergabe ändern. Wenn Sie dann eine Objektinstanz mit Details wie dem Speicherort der Datei an das größere Objekt übergeben, wird alles, was ausgetauscht wird, im Inneren eines geeigneten Kontexts ausgeführt, in dem es weniger wahrscheinlich ist, dass jemand etwas Dummes damit macht.
Also in diesem Fall denke ich nicht, dass es diese Objektinstanz ist, die herumgeworfen wird, die dich nerven könnte. Captain Picard rennt zum Maschinenraum, um den Warpkern einzuschalten, rennt zurück zur Brücke, um die Koordinaten zu zeichnen, und drückt dann nach dem Einschalten der Schilde den "Punch-It" -Knopf, anstatt einfach "Take" zu sagen uns zu Planet X bei Warp 9. Mach es so. " und seine Crew die Details aussortieren lassen. Denn wenn er damit umgeht, kann er jedes Schiff in der Flotte steuern, ohne das Layout jedes Schiffs zu kennen und zu wissen, wie alles funktioniert. Und das ist letztendlich der größte OOP-Design-Gewinn, für den es zu drehen gilt, IMO.
quelle
Es ist ein weit verbreitetes Design, das am Ende auftritt, obwohl es möglicherweise zu Latenzproblemen kommen kann, wenn Ihre App für diese Art von Dingen empfindlich ist.
quelle
Dieses Problem kann mit Variablen mit dynamischem Gültigkeitsbereich (sofern diese in Ihrer Sprache verfügbar sind) oder mit thread-lokalem Speicher gelöst werden. Mit diesen Mechanismen können wir einige benutzerdefinierte Variablen einer Aktivierungskette oder einem Steuerthread zuordnen, sodass wir diese Werte nicht an Code weitergeben müssen, der nichts damit zu tun hat, nur damit sie an einen anderen Code weitergegeben werden können was braucht sie.
quelle
Wie die anderen Antworten gezeigt haben, handelt es sich nicht um ein von Natur aus schlechtes Design. Dadurch kann eine enge Kopplung zwischen den verschachtelten Klassen und denen, die sie verschachteln, hergestellt werden. Das Lösen der Kopplung ist jedoch möglicherweise keine gültige Option, wenn das Verschachteln der Referenzen einen Wert für das Design darstellt.
Eine mögliche Lösung besteht darin, die verschachtelten Referenzen in der Controller-Klasse zu "verflachen".
Anstatt einen Parameter mehrmals über verschachtelte Objekte zu übergeben, können Sie in der Controller-Klasse Verweise auf alle verschachtelten Objekte verwalten.
Wie genau dies implementiert wird (oder ob es sich überhaupt um eine gültige Lösung handelt), hängt vom aktuellen Design des Systems ab, z.
Dies ist ein Problem, das ich in einem MVC-Entwurfsmuster für einen GXT-Client festgestellt habe. Unsere GUI-Komponenten enthielten verschachtelte GUI-Komponenten für mehrere Ebenen. Als die Modelldaten aktualisiert wurden, haben wir sie schließlich durch die verschiedenen Ebenen geleitet, bis sie die entsprechenden Komponenten erreicht haben. Dies führte zu einer unerwünschten Kopplung zwischen den GUI-Komponenten, da, wenn eine neue GUI-Komponentenklasse Modelldaten aufnehmen soll, Methoden zum Aktualisieren der Modelldaten in allen GUI-Komponenten erstellt werden müssen, die die neue Klasse enthalten.
Um dies zu beheben, haben wir in der View-Klasse eine Zuordnung von Verweisen auf alle verschachtelten GUI-Komponenten beibehalten, sodass die View die aktualisierten Modelldaten bei jeder Aktualisierung der Modelldaten direkt an die GUI-Komponenten senden konnte, die sie benötigt haben . Dies hat gut funktioniert, da es nur einzelne Instanzen jeder GUI-Komponente gab. Ich sah, dass es nicht so gut funktionierte, wenn es mehrere Instanzen einiger GUI-Komponenten gab, was es schwierig machte, zu identifizieren, welche Kopie aktualisiert werden musste.
quelle
Was Sie beschreiben, ist ein sogenanntes Chain-of-Responsibility- Entwurfsmuster. Apple verwendet dieses Muster für sein Event-Handling-System.
quelle