In seinem Buch "Saubere Architektur" sagt Onkel Bob, dass der Präsentator die empfangenen Daten in etwas setzen sollte, das er "View Model" nennt.
Ist dies dasselbe wie das 'ViewModel' aus dem Entwurfsmuster Model-View-ViewModel (MVVM) oder handelt es sich um ein einfaches Datenübertragungsobjekt (Data Transfer Object, DTO)?
Wenn es sich nicht um ein einfaches DTO handelt, in welcher Beziehung steht es zur Ansicht? Erhält die Ansicht über eine Beobachterbeziehung Aktualisierungen?
Ich vermute, dass es eher wie das ViewModel von MVVM ist, denn in Kapitel 23 seines Buches sagt Robert Martin:
Die Aufgabe des [Präsentators] besteht darin, Daten aus der Anwendung zu akzeptieren und für die Präsentation zu formatieren, sodass die Ansicht sie einfach auf den Bildschirm verschieben kann. Wenn die Anwendung beispielsweise möchte, dass ein Datum in einem Feld angezeigt wird, übergibt sie dem Presenter ein Datumsobjekt. Der Presenter formatiert diese Daten dann in eine entsprechende Zeichenfolge und platziert sie in einer einfachen Datenstruktur namens View-Modell, in der View sie finden kann.
Dies impliziert, dass die Ansicht in irgendeiner Weise mit dem ViewModel verbunden ist, anstatt sie einfach als Funktionsargument zu erhalten (wie dies bei einem DTO der Fall wäre).
Ein weiterer Grund, warum ich denke, liegt darin, dass der Presenter beim Betrachten des Bildes das Ansichtsmodell verwendet, nicht jedoch die Ansicht. Während der Präsentator sowohl die Ausgabegrenze als auch die Ausgabedaten-DTO verwendet.
Wenn es sich weder um ein DTO noch um das ViewModel von MVVM handelt, erläutern Sie bitte, was es ist.
quelle
ViewModel
ist Wrapper fürController
,Presenter
undViewModel
in Rein Architektur Onkel Bob.Controller
->ICommand
undPresenter
-> seindata-binding mechanism
.Antworten:
Nee.
Das wäre dies :
Das hat Zyklen. Onkel Bob hat Zyklen sorgfältig vermieden .
Stattdessen haben Sie Folgendes:
Welches sicherlich keine Zyklen hat. Sie fragen sich jedoch, woher die Ansicht ein Update kennt. Wir werden gleich darauf zurückkommen.
So zitieren Sie Bob von der vorherigen Seite:
Also sicher, wenn du magst.
Aber ich nehme stark an, was wirklich nervt Sie ist dies :
Dieser niedliche kleine Missbrauch von UML stellt die Richtung der Quellcode-Abhängigkeit der Richtung des Kontrollflusses gegenüber. Hier finden Sie die Antwort auf Ihre Frage.
In einer Nutzungsbeziehung:
Der Steuerungsfluss geht in dieselbe Richtung wie die Quellcode-Abhängigkeit.
In einer Implementierungsbeziehung:
Der Steuerungsfluss verläuft normalerweise in die entgegengesetzte Richtung wie die Quellcode-Abhängigkeit.
Was bedeutet, dass du dir das wirklich ansiehst:
Sie sollten in der Lage sein zu sehen, dass der Kontrollfluss niemals vom Präsentator zur Ansicht gelangen wird.
Wie kann das sein? Was bedeutet es?
Dies bedeutet, dass die Ansicht entweder einen eigenen Thread hat (was nicht so ungewöhnlich ist) oder (wie @Euphoric hervorhebt), dass der Kontrollfluss von etwas anderem in die Ansicht eintritt, das hier nicht dargestellt ist.
Wenn es sich um denselben Thread handelt, weiß die Ansicht, wann das Ansichtsmodell zum Lesen bereit ist. Wenn dies jedoch der Fall ist und die Ansicht eine grafische Benutzeroberfläche ist, fällt es schwer, den Bildschirm neu zu zeichnen, wenn der Benutzer ihn bewegt, während er auf die Datenbank wartet.
Wenn die Ansicht über einen eigenen Thread verfügt, verfügt sie über einen eigenen Steuerungsfluss. Das heißt, um dies zu implementieren, muss die Ansicht das Ansichtsmodell abfragen, um Änderungen zu bemerken.
Da der Präsentator nicht weiß, dass die Ansicht vorhanden ist, und der Präsentator nicht weiß, dass die Ansicht vorhanden ist, können sie sich überhaupt nicht gegenseitig anrufen. Sie können sich nicht gegenseitig angreifen. Alles, was passieren kann, ist, dass der Präsentator in das Ansichtsmodell schreibt und die Ansicht das Ansichtsmodell liest. Wann immer es sich anfühlt.
Nach diesem Diagramm ist das einzige, was View und Presenter gemeinsam haben, die Kenntnis des View-Modells. Und es ist nur eine Datenstruktur. Erwarten Sie also kein Verhalten.
Das mag unmöglich erscheinen, aber es kann auch dann zum Funktionieren gebracht werden, wenn das Ansichtsmodell komplex ist. Ein kleines aktualisiertes Feld ist alles, was die Ansicht abfragen müsste, um eine Änderung zu erkennen.
Jetzt können Sie natürlich darauf bestehen, das Beobachter-Muster zu verwenden, oder Sie müssen sich dieses Problem durch ein Framework verbergen, aber bitte haben Sie Verständnis dafür, dass Sie es nicht müssen.
Hier ist ein bisschen Spaß, den ich hatte, um den Kontrollfluss zu veranschaulichen:
Beachten Sie, dass Sie immer dann, wenn Sie sehen, dass der Fluss gegen die zuvor definierten Richtungen verläuft, einen Rückruf erhalten. Dieser Trick hilft uns nicht, zur Ansicht zu gelangen. Nun, es sei denn, wir kehren zuerst zu dem zurück, was der Controller genannt wird. Oder Sie können einfach das Design ändern , um zur Ansicht zu gelangen. Das behebt auch das Problem, dass mit Data Access und seiner Benutzeroberfläche ein Jojo-Problem begonnen hat .
Das einzige andere, was Sie hier lernen müssen, ist, dass der Use Case Interactor so ziemlich alles in beliebiger Reihenfolge aufrufen kann, solange er den Moderator zuletzt anruft.
quelle
Ich finde dieses Problem zu verwirrend und es würde viel Text und Zeit in Anspruch nehmen, um das Problem richtig zu erklären, da ich glaube, dass Sie sowohl Martins saubere Architektur als auch MVVM falsch verstehen.
Als erstes ist zu beachten, dass das von Ihnen veröffentlichte Diagramm unvollständig ist. Es zeigt nur "Geschäftslogik", aber es fehlt eine Art "Orchestrator", der die Teile tatsächlich in der richtigen Reihenfolge bewegt.
Der Code des Orchestrators wäre so einfach wie
Ich glaube, ich habe Martin darüber in einem seiner Vorträge über saubere Architektur sprechen hören.
Eine andere Sache, auf die man hinweisen sollte, ist, dass die Bemerkung von candied_orange über fehlende Zyklen falsch ist. Ja, das Cycled existiert (und sollte nicht) in der Architektur des Codes. Zyklen zwischen Laufzeitinstanzen sind jedoch häufig und führen häufig zu einem einfacheren Entwurf.
Das ist in MVVM der Fall. In MVVM View ist ViewModel abhängig, und ViewModel benachrichtigt View mithilfe von Ereignissen über Änderungen. Dies bedeutet, dass beim Entwurf der Klassen nur Abhängigkeiten von View- zu Model-Klassen bestehen, während zur Laufzeit jedoch zyklische Abhängigkeiten zwischen View- und ViewModel-Instanzen bestehen. Aus diesem Grund ist Orchestrator nicht erforderlich, da ViewModel die Möglichkeit bietet, in View herauszufinden, wann sich das Update von selbst durchführen lässt. Aus diesem Grund verwenden "Benachrichtigungen" in diesem Diagramm "schnörkellose" und keine direkte Linie. Dies bedeutet, dass View Änderungen in ViewModel beobachtet, nicht, dass ViewModel von View abhängt.
Das Wichtigste, was Sie aus Martins Clean Architecture herausholen sollten, ist nicht das Design selbst, sondern der Umgang mit Abhängigkeiten. Einer der kritischen Punkte, die er in seinen Gesprächen hervorhebt, ist, dass, wenn es eine Grenze gibt, alle Code-Abhängigkeiten, die diese Grenze überschreiten, diese in einer Richtung überschreiten. Im Diagramm wird diese Grenze durch eine Doppellinie dargestellt. Und es gibt viele Abhängigkeit Inversion durch Schnittstellen (
InputBoundary
,OutputBoundary
undDataAccessInterface
) dass Korrekturen der Code Abhängigkeitsrichtung.Im Gegensatz dazu ist die
ViewModel
in Clean Architecture nur einfaches DTO ohne Logik. Dies wird durch das<DS>
Tag deutlich. Und dies ist der Grund, warum diesorchestrator
notwendig ist, daView
nicht bekannt ist, wann die Logik ausgeführt werden soll.Wenn ich das Diagramm so "abflachen" würde, dass es zur Laufzeit wie folgt aussieht:
Während der Laufzeit sind die Abhängigkeiten also in die "falsche" Richtung, aber das ist in Ordnung.
Ich empfehle, sich seinen Vortrag über Clean Architecture anzuschauen , um seine Argumentation besser zu verstehen.
quelle