Okay, ich habe mich mit MVVM-Mustern befasst und jedes Mal, wenn ich zuvor versucht habe, sie zu untersuchen, habe ich aus mehreren Gründen aufgegeben:
- Unnötige extra lange Wicklung
- Keine offensichtlichen Vorteile für Programmierer (keine Designer in meinem Büro. Derzeit bin nur ich bald ein weiterer Programmierer)
- Nicht viele Ressourcen / Dokumentation bewährter Verfahren! (Oder zumindest schwer zu finden)
- Ich kann mir kein einziges Szenario vorstellen, in dem dies vorteilhaft ist.
Ich werde es gleich wieder aufgeben und dachte, ich würde fragen, ob jemand die oben genannten Gründe beantwortet.
Ich sehe ehrlich gesagt keinen Vorteil darin, dies für eine Einzel- / Partnercodierung zu verwenden. Auch bei komplexen Projekten mit 10 Fenstern. Für mich ist das DataSet eine ausreichend gute Ansicht und verbindlich wie in der Antwort von Brent auf die folgende Frage
Könnte jemand ein Beispiel dafür zeigen, wo die Verwendung von MVVM-Mustern im Vergleich zu XAML DataBinding Zeit spart.
100% meiner Bindung erfolgt derzeit in XAML. Und deshalb sehe ich den Sinn der VM nicht als zusätzlichen Code dahinter, den ich schreiben und auf den ich mich verlassen muss.
EDIT:
Nachdem ich den Nachmittag damit verbracht hatte, über MVVM zu recherchieren, habe ich endlich etwas gefunden, das mich die wahren Vorteile dieser Antwort erkennen ließ .
Antworten:
Zusammenfassung
Wann man Muster verwendet und wann man sie vermeidet
Für eine ausreichend einfache Anwendung ist jedes Entwurfsmuster übertrieben. Angenommen, Sie schreiben eine GUI-Anwendung, die eine einzelne Schaltfläche anzeigt, die beim Drücken "Hallo Welt" anzeigt. In diesem Fall erhöhen Entwurfsmuster wie MVC, MVP und MVVM die Komplexität erheblich, ohne jedoch einen Mehrwert zu bieten.
Im Allgemeinen ist es immer eine schlechte Entscheidung, ein Designmuster einzuführen, nur weil es etwas passt. Entwurfsmuster sollten verwendet werden, um die Komplexität zu reduzieren, entweder indem die Gesamtkomplexität direkt reduziert wird oder indem ungewohnte Komplexität durch vertraute Komplexität ersetzt wird. Wenn das Entwurfsmuster die Komplexität auf keine dieser beiden Arten reduzieren kann, verwenden Sie es nicht.
Um die vertraute und unbekannte Komplexität zu erklären, nehmen Sie die folgenden 2 Zeichenfolgen:
Während die zweite Zeichenfolge doppelt so lang ist wie die erste, ist sie leichter zu lesen, schneller zu schreiben und leichter zu merken als die erste Folge, weil sie vertrauter ist. Gleiches gilt für bekannte Muster im Code.
Dieses Problem gewinnt eine andere Dimension, wenn Sie bedenken, dass die Vertrautheit vom Leser abhängt. Einige Leser werden feststellen, dass "3.14159265358979323846264338327950" leichter zu merken ist als eines der oben genannten Passwörter. Einige werden nicht. Wenn Sie also eine MVVM-Variante verwenden möchten, versuchen Sie, eine zu verwenden, die die häufigste Form in der von Ihnen verwendeten Sprache und dem verwendeten Framework widerspiegelt.
MVVM
Lassen Sie uns anhand eines Beispiels auf das Thema MVVM eingehen. MVVM zeigt uns, wie Verantwortlichkeiten zwischen Klassen in einer GUI-Anwendung (oder zwischen Ebenen - dazu später mehr) verteilt werden, mit dem Ziel, eine kleine Anzahl von Klassen zu haben und gleichzeitig die Anzahl der Verantwortlichkeiten pro Klasse klein und klar zu halten.
'Richtig' MVVM setzt zumindest eine mäßig komplexe Anwendung voraus, die sich mit Daten befasst, die von "irgendwo" stammen. Es kann die Daten aus einer Datenbank, einer Datei, einem Webdienst oder aus einer Vielzahl anderer Quellen abrufen.
Beispiel
In unserem Beispiel haben wir 2 Klassen
View
undModel
, aber neinViewModel
. DerModel
Wraps eine CSV-Datei, die er beim Start liest und beim Herunterfahren der Anwendung speichert, mit allen Änderungen, die der Benutzer an den Daten vorgenommen hat. DiesView
ist eine Window-Klasse, die die Daten ausModel
einer Tabelle anzeigt und es dem Benutzer ermöglicht, die Daten zu bearbeiten. Der CSV-Inhalt könnte ungefähr so aussehen:ID, Name, Price 1, Stick, 5$ 2, Big Box, 10$ 3, Wheel, 20$ 4, Bottle, 3$
Neue Anforderungen: Preis in Euro anzeigen
Jetzt werden wir gebeten, eine Änderung an unserer Anwendung vorzunehmen. Die Daten bestehen aus einem zweidimensionalen Raster, das bereits eine "Preisspalte" enthält, die einen Preis in USD enthält. Wir müssen eine neue Spalte hinzufügen, in der die Preise in Euro zusätzlich zu denen in USD angezeigt werden, basierend auf einem vordefinierten Wechselkurs. Das Format der CSV-Datei darf sich nicht ändern, da andere Anwendungen mit derselben Datei arbeiten und diese anderen Anwendungen nicht unter unserer Kontrolle stehen.
Eine mögliche Lösung besteht darin, die neue Spalte einfach zur
Model
Klasse hinzuzufügen . Dies ist nicht die beste Lösung, daModel
hierdurch alle Daten gespeichert werden, die der CSV zur Verfügung gestellt werden - und wir keine neue Euro-Preisspalte in der CSV wünschen. Die Änderung anModel
wäre also nicht trivial, und es wäre auch schwieriger zu beschreiben, was die Model-Klasse tut, was ein Code-Geruch ist .Wir könnten die Änderung auch in der vornehmen
View
, aber unsere aktuelle Anwendung verwendet Datenbindung, um die Daten direkt anzuzeigen, wie von unsererModel
Klasse bereitgestellt . Da unser GUI-Framework es uns nicht erlaubt, eine zusätzliche berechnete Spalte in eine Tabelle einzufügen, wenn die Tabelle an eine Datenquelle gebunden ist, müssten wir eine wesentliche ÄnderungView
an vornehmen, damit dies funktioniert, was dieView
Komplexität erheblich erhöht .Einführung in das ViewModel
Es gibt keine
ViewModel
in der Anwendung, daModel
die Daten bis jetzt genau so dargestellt werden, wie es die CSV benötigt, und auch so, wie sieView
benötigt werden. EinViewModel
Zwischenraum zu haben, wäre ohne Zweck komplexer geworden. Aber jetzt, da dieModel
Daten nicht mehr so dargestellt werden, wie sieView
benötigt werden, schreiben wir eineViewModel
. DasViewModel
projiziert die Daten derModel
so, dass dieView
einfach sein können. Zuvor hat dieView
Klasse die Klasse abonniertModel
. JetztViewModel
abonniert die neue Klasse dieModel
Klasse und stellt dieModel
Daten der Klasse derView
- zur Verfügung. In einer zusätzlichen Spalte wird der Preis in Euro angezeigt. DasView
weiß der nicht mehrModel
Jetzt kennt es nur noch dasViewModel
, was vom Standpunkt desView
Aussehens aus genauso aussiehtModel
wie zuvor - außer dass die exponierten Daten eine neue schreibgeschützte Spalte enthalten.Neue Anforderungen: andere Art, die Daten zu formatieren
Die nächste Kundenanforderung lautet, dass wir die Daten nicht als Zeilen in einer Tabelle anzeigen sollen, sondern stattdessen die Informationen jedes Elements (auch als Zeile bezeichnet) als Karte / Box anzeigen und 20 Boxen in einem 4x5-Raster auf dem Bildschirm anzeigen sollen, wobei 20 angezeigt werden Boxen auf einmal. Weil wir die Logik des
View
Einfachen beibehalten haben , ersetzen wir das EinfacheView
vollständig durch eine neue Klasse, die den Wünschen des Kunden entspricht. Natürlich gibt es einen anderen Kunden, der den alten bevorzugtView
, also müssen wir jetzt beide unterstützen. Da die gesamte gängige Geschäftslogik bereits vorhandenViewModel
ist, ist dies kein großes Problem. Wir können dieses Problem lösen, indem wir die View-Klasse in umbenennenTableView
und eine neue schreibenCardView
Klasse, die die Daten in einem Kartenformat anzeigt. Wir müssen auch einen Klebercode schreiben, der möglicherweise ein Oneliner in der Startfunktion ist.Neue Anforderungen: dynamischer Wechselkurs
Die nächste Kundenanfrage ist, dass wir den Wechselkurs aus dem Internet beziehen, anstatt einen vordefinierten Wechselkurs zu verwenden. Dies ist der Punkt, an dem wir meine frühere Aussage über "Ebenen" erneut betrachten. Wir ändern unsere
Model
Klasse nicht, um einen Wechselkurs bereitzustellen. Stattdessen schreiben (oder finden) wir eine völlig unabhängige zusätzliche Klasse, die den Wechselkurs liefert. Diese neue Klasse wird Teil der Modellebene, und wirViewModel
konsolidieren die Informationen des CSV-Modells und des Wechselkursmodells, die sie dann dem Modell präsentierenView
. Für diese Änderung müssen die alte Model-Klasse und die View-Klasse nicht einmal berührt werden. Nun, wir müssen die Model-Klasse in umbenennenCsvModel
und rufen die neue Klasse aufExchangeRateModel
.Wenn wir das ViewModel nicht eingeführt hätten, sondern stattdessen bis jetzt darauf gewartet hätten, wäre der Arbeitsaufwand für die Einführung des ViewModel jetzt höher, da wir sowohl vom als auch vom
View
und zumModel
Verschieben erhebliche Mengen an Funktionen entfernen müssen die Funktionalität in dieViewModel
.Nachwort zu Unit Tests
Der Hauptzweck von MVVM besteht nicht darin, dass der Code im Modell und im ViewModel unter Unit Test gestellt werden kann. Der Hauptzweck von MVVM besteht darin, dass der Code in Klassen mit einer kleinen Anzahl genau definierter Verantwortlichkeiten unterteilt wird. Einer von mehreren Vorteilen eines Codes, der aus Klassen mit einer geringen Anzahl genau definierter Verantwortlichkeiten besteht, besteht darin, dass es einfacher ist, den Code einem Unit-Test zu unterziehen. Ein viel größerer Vorteil ist, dass der Code leichter zu verstehen, zu warten und zu ändern ist.
quelle
ViewModel
Klasse eine Art Liste / Sammlung / Tabelle für die bereits vorhandeneView
Klasse verfügbar und füllt den größten Teil mit den Daten in der bereits vorhandenenModel
Klasse. Und je nach Framework wird eine Listenelement-Eigenschaft / Tabellenspalte mit gefülltprice * exchangeRate
.Das Implementieren von Mustern und das Befolgen von Best Practices fühlen sich oft sinnlos an, aber Sie werden zu einem Konvertiten, wenn Ihr Chef Sie Monate später auffordert, eine Funktion hinzuzufügen oder zu optimieren. Mit MVVM (und Mustern im Allgemeinen) können Sie tatsächlich Ihrem eigenen Code folgen und die Anforderung im schlimmsten Fall in wenigen Stunden oder Tagen anstatt in Wochen oder Monaten erfüllen. (Bei dieser Änderung handelt es sich wahrscheinlich nur um ein paar Codezeilen, anstatt Wochen damit zu verbringen, herauszufinden, wie Sie das getan haben, was Sie ursprünglich getan haben, bevor Sie überhaupt versucht haben, neue Funktionen hinzuzufügen.)
Follow-up: Muster und Best Practices verlangsamen die anfängliche Entwicklung und das ist für Management und Engineering oft ein schwerer Verkauf. Die Amortisation (ROI in biz-Begriffen) ergibt sich aus gut strukturiertem Code, der tatsächlich wartbar, skalierbar und erweiterbar ist.
Wenn Sie beispielsweise MVVM ordnungsgemäß befolgen, sollten Sie in der Lage sein, sehr drastische Änderungen an der Anzeigelogik vorzunehmen, z. B. das Austauschen einer gesamten Ansicht, ohne dass dies Auswirkungen auf die Daten- und Geschäftslogik hat.
Ein Gedanke zur Verwendung von Datensätzen für Ihr Modell : (Ich bin auch darauf hereingefallen.) Datensätze scheinen eine absolut gültige Methode zu sein, um Modelldaten in einer Anwendung zu verschieben. Das Problem besteht darin, wie Sie die Datenelemente identifizieren. Da Ihre Daten in Zeilen und Spalten gespeichert sind, müssen Sie nach Spaltennamen oder Index suchen und nach einer bestimmten Zeile filtern. Diese logischen Elemente bedeuten, dass Sie in Ihrer Anwendung magische Zeichenfolgen und Zahlen in der Verdrahtungslogik verwenden müssen. Die Verwendung eines typisierten Datensatzes würde einige dieser Probleme beheben, jedoch nicht vollständig. Mit typisierten Datasets würden Sie sich von MVVM entfernen und eine engere Kopplung zwischen der Benutzeroberfläche und der Datenquelle herstellen.
quelle
Es hilft Ihnen bei der Trennung von GUI und Programmlogik. Das Mischen kann zu sehr schwer zu wartenden Anwendungen führen, insbesondere wenn Ihr Projekt mit der Zeit wächst.
quelle
Von hier aus :
quelle
quelle
Aus Josh Smiths Artikel über MVVM :
Für mich ist dies der wichtigste Grund, MVVM zu verwenden.
Vorher hätte ich Steuerelemente, die die Ansicht und das Ansichtsmodell zusammenfügen. Eine Ansicht enthält jedoch im Wesentlichen Maus- und Tastaturereignisse als Eingabe und gezeichnete Pixel als Ausgabe. Wie testest du so etwas? MVVM behebt dieses Problem, da es die nicht testbare Ansicht vom testbaren Ansichtsmodell trennt und die Ansichtsebene so dünn wie möglich hält.
quelle
Es gibt viele gute Dinge an MVVM, aber vielleicht ist das Wichtigste die Möglichkeit, Ihren Code zu testen (Unit-Test der ViewModels).
Die fehlende Verbindung zwischen Ansicht und Ansichtsmodell hilft auch der losen Kopplung. Es wird sehr einfach, die von Ihnen codierten Komponenten wiederzuverwenden.
quelle
Lesen Sie die Einführung in MVVM in diesem Artikel
..
Der Artikel erklärt auch, warum diese GUI-Muster verwendet werden:
quelle
Ich werde mich immer noch selbst mit dem Muster auseinandersetzen, aber ich denke, es ist wertvoll. Die derzeit größte Herausforderung besteht darin, dass der Ansatz noch recht neu ist und daher viel Verwirrung herrscht und bestimmte Schlüsselkomponenten des Musters immer noch umständlich zu implementieren sind. Ich habe einige Dinge entdeckt, die mir sehr geholfen haben, das Muster sauberer umzusetzen:
Ich benutze den RelayCommand von Josh Smiths MVVM Foundation intensiv . Dies macht die Bindung von View zu ViewModel über Befehle viel sauberer.
Ich verwende AOP, um die Implementierung von INotifyPropertyChanged zu vereinfachen. Ich verwende derzeit Postsharp, obwohl ich glaube, dass es andere Tools gibt, die dies tun können. Wenn ich das nicht entdeckt hätte, hätte ich wahrscheinlich inzwischen aufgegeben, da mich der Boilerplate-Code zur manuellen Implementierung wirklich nervte.
Ich musste meinen Ansatz zur Implementierung der Software umkehren. Anstatt eine Diktatorklasse zu haben, die allen Schergen sagt, was zu tun ist, die wiederum ihre Schergen verwenden, wird meine Software eher zu einer Angelegenheit von lose gekoppelten Diensten, die sagen:
Das weiß ich zu tun
Dies sind die Dinge, die ich getan haben muss
Wenn Sie anfangen, Ihren Code auf diese Weise zu strukturieren und Tools verwenden, mit denen sich die Abhängigkeiten leicht verkabeln lassen (es stehen eine Vielzahl von IoC-Frameworks zur Auswahl), habe ich festgestellt, dass dies die Unbeholfenheit von MVVM erleichtert Sie können den Boilerplate-Code reduzieren, der mit dem Einfügen der Modelle in die ViewModels und dem Auffinden verschiedener View Services (z. B. Anzeigen von Dateidialogen) für Ihre ViewModels verbunden ist.
Es ist eine enorme Investition, diesen anderen Ansatz zu erlernen, und wie bei jeder größeren Änderung der Implementierung ist die Produktivität viel geringer, wenn Sie ihn zum ersten Mal verwenden. Am Ende des Tunnels sehe ich jedoch allmählich etwas Licht und ich glaube, dass meine Anwendungen sauberer und wartbarer sind, sobald ich die unordentlichen Details beherrsche.
Um die Frage zu INotifyPropertyChanged über Postsharp zu beantworten, verwende ich einen Aspekt, der auf dem Beispiel hier basiert . Ich habe es ein wenig für meinen Gebrauch angepasst, aber das gibt Ihnen den Kern davon. Damit tagge ich einfach die Klasse [NotifyPropertyChanged] und in allen öffentlichen Eigenschaften wird das Muster in ihren Setzern implementiert (auch wenn es sich um Setter mit automatischen Eigenschaften handelt). Es fühlt sich für mich viel sauberer an, da ich mir keine Sorgen mehr machen muss, ob ich mir die Zeit nehmen möchte, damit die Klasse INotifyPropertyChanged implementiert. Ich kann einfach das Attribut hinzufügen und damit fertig sein.
quelle
Ich bin damit einverstanden, dass die Verwendung von MVVM durch das Schreiben von Erzcode mehr Gewicht auf unsere Schultern legt. Schauen Sie sich jedoch die gute Seite an, auf der alles isoliert ist. Wenn Sie Designer sind, können Sie Ihr Programm entwerfen und andere können es für Sie und andere für die Datenbank codieren Schicht für Sie, schauen Sie, in welcher wartbaren Umgebung Sie sich gerade in großen Unternehmensanwendungen befinden, wenn Sie MVVM nicht verwenden würden, dann ist die Wartung fast tödlich .... Ich selbst habe sie bei der Entwicklung einer ERP-Lösung verwendet, jetzt ist die Wartung ziemlich einfach, weil dieser Isolationsstufe
quelle
Sie werden auf lange Sicht glücklich sein, wenn Sie ein Muster wie MVVM aus all den Gründen verwenden, die die anderen veröffentlicht haben. Denken Sie daran, dass Sie die Musteranforderungen nicht Wort für Wort befolgen müssen. Stellen Sie lediglich sicher, dass Sie eine gute Trennung zwischen Ihrem Fenster (Ansicht) und Ihrer Logik (CodeBehind) haben.
quelle
Vorteile von MVVM
Ich hoffe es hilft.
quelle
MVVM ist wirklich übermäßiger Code.
Welche Vorteile bietet die MVVM?
Es ist nur eine Trennung von Bedenken, nicht mehr. Sie können auch die ViewModel-Logik in den Controller schreiben. Das ViewModel ist nur für eine Konvertierung verantwortlich (z. B. und Objekt in eine Zeichenfolge). Durch die Verwendung von MVVM verwenden Sie einen objektorientierteren Programmierstil. Durch Schreiben der Konvertierungslogik in den Controller verwenden Sie einen funktionaleren Programmierstil.
Es kommt also darauf an, mehr Code mit besserer Lesbarkeit oder weniger Code mit großen Controller-Dateien zu haben. Zusammenfassend kann man nicht sagen, dass man MVVM verwenden muss, da es besser ist als MVC oder so, es ist nur eine persönliche Präferenz.
Um ganz klar zu sein, warum ich einen Controller erwähne: MVVM hat auch irgendwo Controller-Code. Ich habe keine Ahnung, warum es einen breiten Konsens gibt, das C. zu verlassen.
quelle