Ich entschuldige mich für die lange Frage, es liest sich ein bisschen wie ein Scherz, aber ich verspreche, es ist nicht! Ich habe meine Frage (n) unten zusammengefasst
In der MVC-Welt sind die Dinge einfach. Das Modell hat Zustand, wobei die Ansicht zeigt das Modell, und der Controller funktioniert Sachen / mit dem Modell (im Wesentlichen), hat ein Controller keinen Zustand. Um Dinge zu erledigen, hat der Controller einige Abhängigkeiten von Webservices, Repository und dem Los. Wenn Sie einen Controller instanziieren, ist es Ihnen wichtig, diese Abhängigkeiten bereitzustellen, sonst nichts. Wenn Sie eine Aktion (Methode auf dem Controller) ausführen, verwenden Sie diese Abhängigkeiten, um das Modell abzurufen oder zu aktualisieren oder um einen anderen Domänendienst aufzurufen. Wenn es einen Kontext gibt, beispielsweise wenn ein Benutzer die Details eines bestimmten Elements anzeigen möchte, übergeben Sie die ID dieses Elements als Parameter an die Aktion. Nirgendwo im Controller gibt es einen Verweis auf einen Zustand. So weit, ist es gut.
Geben Sie MVVM ein. Ich liebe WPF, ich liebe Datenbindung. Ich liebe Frameworks, die das Binden von Daten an ViewModels noch einfacher machen (mit Caliburn Micro atm). Ich bin der Meinung, dass die Dinge in dieser Welt weniger einfach sind. Machen wir die Übung noch einmal: Das Modell hat einen Status, die Ansicht zeigt das ViewModel und das ViewModel erledigt (im Grunde genommen) Dinge mit dem Modell, ein ViewModel hat einen Status! (zu klären, vielleicht delegiert alle Eigenschaften auf ein oder mehrere Modelle, aber das bedeutet , es muß einen Verweis auf das Modell eine oder andere Weise haben, der Zustand , in sich ist) Zu tunSachen, die das ViewModel hat einige Abhängigkeiten von Webservices, Repository, die Menge. Wenn Sie ein ViewModel instanziieren, müssen Sie diese Abhängigkeiten angeben, aber auch den Status. Und das, meine Damen und Herren, ärgert mich bis zum Äußersten.
Wann immer Sie ein ProductDetailsViewModel
von instanziieren müssen ProductSearchViewModel
(von dem Sie das aufgerufen haben, ProductSearchWebService
das wiederum zurückgekehrt ist IEnumerable<ProductDTO>
, alle noch bei mir?), Können Sie eine der folgenden Aktionen ausführen:
- nennen
new ProductDetailsViewModel(productDTO, _shoppingCartWebService /* dependcy */);
, das ist schlecht, stellen Sie sich 3 weitere Abhängigkeiten vor, dies bedeutetProductSearchViewModel
, dass Sie diese Abhängigkeiten auch übernehmen müssen. Auch das Ändern des Konstruktors ist schmerzhaft. - nennen
_myInjectedProductDetailsViewModelFactory.Create().Initialize(productDTO);
, die Fabrik ist nur eine Func, sie werden leicht von den meisten IoC-Frameworks generiert. Ich denke, das ist schlecht, weil Init-Methoden eine undichte Abstraktion sind. Sie können das Schlüsselwort readonly auch nicht für Felder verwenden, die in der Init-Methode festgelegt sind. Ich bin mir sicher, dass es noch ein paar Gründe gibt. - call
_myInjectedProductDetailsViewModelAbstractFactory.Create(productDTO);
So ... das ist das Muster (abstrakte Fabrik), das normalerweise für diese Art von Problem empfohlen wird. Ich dachte, es war genial, da es mein Verlangen nach statischem Tippen stillt, bis ich es tatsächlich benutzte. Die Menge des Kesselschild-Codes ist meiner Meinung nach zu groß (abgesehen von den lächerlichen Variablennamen, die ich benutze). Für jedes ViewModel, das Laufzeitparameter benötigt, erhalten Sie zwei zusätzliche Dateien (Factory-Schnittstelle und Implementierung), und Sie müssen die Nicht-Laufzeit-Abhängigkeiten wie 4 zusätzliche Male eingeben. Und jedes Mal, wenn sich die Abhängigkeiten ändern, können Sie sie auch im Werk ändern. Es fühlt sich an, als würde ich nicht einmal mehr einen DI-Container verwenden. (Ich denke, Castle Windsor hat eine Lösung dafür [mit seinen eigenen Nachteilen, korrigieren Sie mich, wenn ich falsch liege]). - Machen Sie etwas mit anonymen Typen oder einem Wörterbuch. Ich mag meine statische Eingabe.
Also ja. Das Mischen von Zustand und Verhalten auf diese Weise schafft ein Problem, das in MVC überhaupt nicht existiert. Und ich habe das Gefühl, dass es derzeit keine wirklich angemessene Lösung für dieses Problem gibt. Nun möchte ich einige Dinge beobachten:
- Die Leute benutzen tatsächlich MVVM. Entweder kümmern sie sich nicht um alles, oder sie haben eine brillante andere Lösung.
- Ich habe kein detailliertes Beispiel für MVVM mit WPF gefunden. Zum Beispiel hat mir das NDDD-Beispielprojekt sehr geholfen, einige DDD-Konzepte zu verstehen. Es würde mir sehr gefallen, wenn mich jemand in eine ähnliche Richtung wie MVVM / WPF lenken könnte.
- Vielleicht mache ich MVVM falsch und ich sollte mein Design auf den Kopf stellen. Vielleicht sollte ich dieses Problem überhaupt nicht haben. Nun, ich weiß, dass andere Leute die gleiche Frage gestellt haben, also denke ich, dass ich nicht der einzige bin.
Zusammenfassen
- Bin ich zu Recht der Ansicht, dass das ViewModel als Integrationspunkt für Status und Verhalten der Grund für einige Schwierigkeiten mit dem MVVM-Muster insgesamt ist?
- Ist die Verwendung des abstrakten Factory-Musters die einzige / beste Möglichkeit, ein ViewModel statisch zu instanziieren?
- Gibt es so etwas wie eine ausführliche Referenzimplementierung?
- Ist es ein Designgeruch, viele ViewModels mit beiden Zuständen / Verhaltensweisen zu haben?
Antworten:
Das Problem der Abhängigkeiten beim Einleiten eines neuen Ansichtsmodells kann mit IOC behandelt werden.
Beim Aufstellen des Containers ...
Wenn Sie Ihr Ansichtsmodell benötigen:
Bei der Verwendung eines Frameworks wie Caliburn Micro ist häufig bereits eine Form von IOC-Containern vorhanden.
quelle
Ich arbeite täglich mit ASP.NET MVC und arbeite seit über einem Jahr an einem WPF. Und so sehe ich das:
MVC
Der Controller soll Aktionen orchestrieren (holen Sie dies, fügen Sie das hinzu).
Die Ansicht ist für die Anzeige des Modells verantwortlich.
Das Modell umfasst in der Regel Daten (z. B. Benutzer-ID, Vorname) sowie den Status (z. B. Titel) und ist in der Regel ansichtsspezifisch.
MVVM
Das Modell enthält normalerweise nur Daten (z. B. Benutzer-ID, Vorname) und wird normalerweise weitergegeben
Das Ansichtsmodell umfasst das Verhalten der Ansicht (Methoden), ihrer Daten (Modell) und Interaktionen (Befehle) - ähnlich dem aktiven MVP-Muster, bei dem der Präsentator das Modell kennt. Das Ansichtsmodell ist ansichtsspezifisch (1 Ansicht = 1 Ansichtsmodell).
Die Ansicht ist für die Anzeige von Daten und die Datenbindung an das Ansichtsmodell verantwortlich. Beim Erstellen einer Ansicht wird normalerweise das zugehörige Ansichtsmodell erstellt.
Was Sie beachten sollten, ist, dass das MVVM-Präsentationsmuster aufgrund seiner Datenbindung für WPF / Silverlight spezifisch ist.
Die Ansicht weiß normalerweise, welchem Ansichtsmodell sie zugeordnet ist (oder eine Abstraktion von einem).
Ich würde empfehlen, dass Sie das Ansichtsmodell als Singleton behandeln, auch wenn es pro Ansicht instanziiert wird. Mit anderen Worten, Sie sollten in der Lage sein, es über DI über einen IOC-Container zu erstellen und entsprechende Methoden aufzurufen. Laden Sie das Modell basierend auf Parametern. Etwas wie das:
In diesem Fall würden Sie beispielsweise kein für den zu aktualisierenden Benutzer spezifisches Ansichtsmodell erstellen. Stattdessen würde das Modell benutzerspezifische Daten enthalten, die durch einen Aufruf des Ansichtsmodells geladen werden.
quelle
Kurze Antwort auf Ihre Fragen:
Die lange Version:
Wir stehen vor dem gleichen Problem und haben einige Dinge gefunden, die Ihnen helfen können. Obwohl ich die "magische" Lösung nicht kenne, lindern diese Dinge die Schmerzen ein wenig.
Implementieren Sie bindbare Modelle von DTOs zur Änderungsverfolgung und -validierung. Diese "Data" -ViewModels dürfen nicht von Diensten abhängen und stammen nicht aus dem Container. Sie können einfach "neu" aufgesetzt, weitergegeben und sogar vom DTO abgeleitet werden. Fazit ist, ein für Ihre Anwendung spezifisches Modell (wie MVC) zu implementieren.
Entkoppeln Sie Ihre ViewModels. Caliburn erleichtert das Zusammenkoppeln der ViewModels. Es schlägt es sogar durch sein Screen / Conductor-Modell vor. Diese Kopplung erschwert jedoch den Komponententest der ViewModels, führt zu zahlreichen Abhängigkeiten und ist am wichtigsten: Die Verwaltung des ViewModel-Lebenszyklus wird Ihren ViewModels auferlegt. Eine Möglichkeit, sie zu entkoppeln, ist die Verwendung eines Navigationsdienstes oder eines ViewModel-Controllers. Z.B
öffentliche Schnittstelle IShowViewModels {void Show (Objekt inlineArgumentsAsAnonymousType, Zeichenfolge regionId); }
Noch besser ist es, dies durch irgendeine Form von Nachrichten zu tun. Es ist jedoch wichtig, den ViewModel-Lebenszyklus nicht von anderen ViewModels aus zu verarbeiten. In MVC sind Controller nicht voneinander abhängig, und in MVVM sollten ViewModels nicht voneinander abhängig sein. Integrieren Sie sie auf andere Weise.
INeedData<T1,T2,...>
und typsichere Erstellungsparameter zu erzwingen, lohnt es sich nicht. Auch das Erstellen von Fabriken für jeden ViewModel-Typ lohnt sich nicht. Die meisten IoC-Container bieten hierfür Lösungen. Sie werden zur Laufzeit Fehler bekommen, aber die Entkopplung und die Testbarkeit der Einheiten sind es wert. Sie führen immer noch eine Art Integrationstest durch, und diese Fehler können leicht entdeckt werden.quelle
So wie ich das normalerweise mache (mit PRISM), enthält jede Assembly ein Container-Initialisierungsmodul, in dem alle Schnittstellen und Instanzen beim Start registriert werden.
Und in Anbetracht Ihrer Beispielklassen würde dies so implementiert, dass der Container vollständig durchgereicht wird. Auf diese Weise können neue Abhängigkeiten einfach hinzugefügt werden, da Sie bereits Zugriff auf den Container haben.
Es ist durchaus üblich, eine ViewModelBase-Klasse zu haben, von der alle Ansichtsmodelle abgeleitet sind und die einen Verweis auf den Container enthält. Solange Sie sich angewöhnen, alle Ansichtsmodelle anstelle von
new()'ing
diesen aufzulösen, sollte dies die Auflösung von Abhängigkeiten erheblich vereinfachen.quelle
Manchmal ist es besser, zur einfachsten Definition zu gehen, als zu einem vollständigen Beispiel: http://en.wikipedia.org/wiki/Model_View_ViewModel Vielleicht ist das Lesen des ZK Java-Beispiels aufschlussreicher als das in C #.
Andere Male höre auf deinen Bauchgefühl ...
Sind Ihre Modelle Objekt-pro-Tabelle-Zuordnungen? Möglicherweise hilft ein ORM bei der Zuordnung zu Domänenobjekten, während das Geschäft abgewickelt oder mehrere Tabellen aktualisiert werden.
quelle