Okay, ich habe mir MVVM-Pattern angesehen und jedes Mal, wenn ich es vorher versucht habe, habe ich es aus verschiedenen Gründen aufgegeben:
Ich werde es schon wieder aufgeben und dachte, ich würde fragen, ob jemand die oben genannten Gründe beantwortet.
Ich kann ehrlich gesagt keinen Vorteil darin sehen, dies für eine einzelne/Partner-Codierung zu verwenden. Auch bei komplexen Projekten mit zehn Fenstern. Für mich ist das DataSet eine gute Sicht und Bindung wie in der Antwort von Brent im Anschluss an Frage .
Könnte jemand ein Beispiel zeigen, wo die Verwendung eines MVVM-Musters im Vergleich zu XAML DataBinding Zeit spart.
100% meiner Bindung wird im Moment in XAML gemacht. Und deshalb sehe ich den Punkt von VM nicht als zusätzlichen Code hinter dem ich schreiben muss und auf den ich mich verlassen muss.
EDIT:
Nachdem ich den Nachmittag über MVVM recherchiert hatte, habe ich endlich etwas gefunden, durch das ich die wahren Vorteile dieser Antwort erkennen konnte.
Für eine ausreichend einfache Anwendung ist jedes Designmuster übertrieben. Angenommen, Sie schreiben eine GUI-Anwendung, die eine einzige 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, während sie keinerlei Wertschöpfung bewirken.
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 verringern, indem entweder die Gesamtkomplexität direkt verringert 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.
Verwenden Sie die folgenden 2 Zeichenfolgen, um die vertraute und ungewohnte Komplexität zu erklären:
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, alles nur, weil sie vertrauter ist. Gleiches gilt für bekannte Muster im Code.
Beachten Sie, dass einige Muster möglicherweise nicht allen Entwicklern bekannt sind, die in Zukunft mit dem Code arbeiten werden. In Bezug auf das vorherige Beispiel ist die folgende Sequenz möglicherweise leichter zu merken als eine der obigen Sequenzen, abhängig von der Erfahrung und dem Training der Person, die sich daran erinnert: "3.14159265358979323846264338327950". In einigen Fällen, in denen fortgeschrittenere Entwurfsmuster betroffen sind, ist es nur sinnvoll, ein Entwurfsmuster zu verwenden, wenn die Wartungsentwickler bereits mit ihm vertraut sind.
Lassen Sie uns anhand eines Beispiels auf das Thema MVVM eingehen. In MVVM erfahren Sie, wie Sie die Zuständigkeiten auf Klassen in einer GUI-Anwendung (oder auf Ebenen - dazu später mehr) verteilen, mit dem Ziel, eine kleine Anzahl von Klassen zu haben und gleichzeitig die Anzahl der Zuständigkeiten pro Klasse klein und genau definiert zu halten.
"Richtig" MVVM setzt mindestens eine mäßig komplexe Anwendung voraus, die sich mit Daten befasst, die von "irgendwo" stammen. Möglicherweise werden die Daten aus einer Datenbank, einer Datei, einem Webdienst oder aus einer Vielzahl anderer Quellen abgerufen.
In unserem Beispiel haben wir 2 Klassen View
und Model
name__, aber keine ViewModel
name__. Der Model
umschließt eine csv-Datei, die beim Start gelesen und beim Beenden der Anwendung gespeichert wird. Dabei werden alle Änderungen berücksichtigt, die der Benutzer an den Daten vorgenommen hat. Die View
ist eine Window-Klasse, die die Daten der Model
in einer Tabelle anzeigt und dem Benutzer die Bearbeitung der Daten ermöglicht. 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, unsere Bewerbung zu ändern. Die Daten bestehen aus einem zweidimensionalen Raster, das bereits eine "Preis" -Spalte 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 von uns gesteuert werden.
Eine mögliche Lösung besteht darin, die neue Spalte einfach der Klasse Model
hinzuzufügen. Dies ist nicht die beste Lösung, da in Model
alle Daten gespeichert werden, die für die CSV verfügbar sind - und wir keine neue Euro-Preisspalte in der CSV wünschen. Die Änderung an Model
wäre also nicht trivial, und es wäre auch schwieriger zu beschreiben, was die Model-Klasse tut. Dies ist ein Code-Geruch .
Wir könnten die Änderung auch in View
vornehmen, aber unsere aktuelle Anwendung verwendet die Datenbindung, um die Daten direkt anzuzeigen, wie sie von unserer Klasse Model
bereitgestellt werden. 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 Änderung an View
vornehmen, damit dies funktioniert, wodurch View
sehr viel wird komplexer.
Vorstellung des ViewModel
In der Anwendung gibt es keinen ViewModel
name__, da der Model
die Daten bisher genau so darstellt, wie es der Csv benötigt, und auch der View
benötigt. Ein ViewModel
dazwischen zu haben, hätte die Komplexität ohne Zweck erhöht. Aber jetzt, da Model
die Daten nicht mehr so präsentiert, wie es der View
benötigt, schreiben wir einen ViewModel
namen__. Die Klasse ViewModel
projiziert die Daten der Klasse Model
so, dass die Klasse View
einfach sein kann. Zuvor war die Klasse View
der Klasse Model
zugeordnet. Jetzt abonniert die neue Klasse ViewModel
die Klasse Model
und macht die Daten der Klasse Model
für den Wert View
verfügbar - mit einer zusätzlichen Spalte, in der der Preis in Euro angezeigt wird. Der View
kennt nicht mehr den Model
namen__, sondern nur noch den ViewModel
namen__, der aus der Sicht des View
namens__ genauso aussieht wie der Model
zuvor - mit der Ausnahme, dass die offengelegten Daten eine neue schreibgeschützte Spalte enthalten.
Neue Anforderungen: andere Formatierung der Daten
Die nächste Kundenanforderung ist, dass wir die Daten nicht als Zeilen in einer Tabelle anzeigen, sondern stattdessen die Informationen jedes Elements (auch als Zeile bezeichnet) als Karte/Box und 20 Boxen auf dem Bildschirm in einem 4x5-Raster mit 20 anzeigen Boxen auf einmal. Da wir die Logik der View
einfach gehalten haben, ersetzen wir die View
einfach durch eine neue Klasse, die den Kundenanforderungen entspricht. Natürlich gibt es einen anderen Kunden, der den alten View
vorgezogen hat, daher müssen wir jetzt beide unterstützen. Da sich die gesamte allgemeine Geschäftslogik bereits in ViewModel
befindet, ist dies kein großes Problem. Wir können dies also lösen, indem wir die View-Klasse in TableView
umbenennen und eine neue CardView
name__-Klasse schreiben, 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 ziehen, anstatt einen vordefinierten Wechselkurs zu verwenden. Dies ist der Punkt, an dem wir meine frühere Aussage über "Schichten" überdenken. Wir ändern unsere Klasse Model
nicht, um einen Wechselkurs anzugeben. Stattdessen schreiben (oder finden) wir eine völlig unabhängige zusätzliche Klasse, die den Wechselkurs liefert. Diese neue Klasse wird Teil der Modellschicht, und unser ViewModel
konsolidiert die Informationen des csv-Modells und des Wechselkursmodells, die es dann dem View
präsentiert. 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 CsvModel
umbenennen und wir nennen die neue Klasse ExchangeRateModel
name__.
Wenn wir das ViewModel nicht eingeführt hätten, als wir es getan haben, sondern bis jetzt gewartet hätten, wäre der Arbeitsaufwand für die Einführung des ViewModel jetzt höher, da wir signifikante Mengen an Funktionalität sowohl aus dem View
als auch aus dem Model
entfernen müssen. und verschieben Sie die Funktionalität in den ViewModel
name__.
Der Hauptzweck von MVVM besteht nicht darin, dass der Code in Model und ViewModel unter Unit Test gestellt werden kann. Der Hauptzweck von MVVM besteht darin, den Code in Klassen mit einer kleinen Anzahl klar definierter Verantwortlichkeiten aufzuteilen. Einer der Vorteile von Code, der aus Klassen mit einer kleinen Anzahl klar definierter Verantwortlichkeiten besteht, besteht darin, dass es einfacher ist, den Code einem Komponententest zu unterziehen. Ein viel größerer Vorteil ist, dass der Code einfacher zu verstehen, zu warten und zu ändern ist.
Das Implementieren von Mustern und das Befolgen von Best Practices sind oft sinnlose Verfolgungen, aber Sie werden zu einem Bekehrten, wenn Ihr Chef Sie Monate später bittet, ein Feature hinzuzufügen oder zu optimieren. Mit MVVM (und Mustern im Allgemeinen) können Sie tatsächlich Ihrem eigenen Code folgen und die Anforderung innerhalb weniger Stunden oder Tage erfüllen, im schlimmsten Fall statt Wochen oder Monaten. (Diese Änderung wird wahrscheinlich nur aus wenigen Zeilen Code bestehen, anstatt Wochen damit zu verbringen, herauszufinden, wie Sie das getan haben, was Sie zuerst getan haben, bevor Sie überhaupt versucht haben, neue Funktionen hinzuzufügen.
Follow-up: Muster und bewährte Vorgehensweisen verlangsamen die anfängliche Entwicklung tatsächlich und das ist oft ein schwerer Verkauf für das Management und das Engineering. Die Amortisation (ROI in Business-Begriffen) beruht auf 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 Auslagern einer gesamten Ansicht, ohne Auswirkungen auf die Daten- und Business-Logik.
Ein Gedanke über die Verwendung von Datensätzen für Ihr Modell : (Ich habe mich auch darauf verliebt.) Datensätze scheinen eine vollkommen gültige Möglichkeit zu sein, um Modelldaten in einer Anwendung zu bewegen. 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 Logik bedeutet, dass Sie in Ihrer Anwendung in der Verdrahtungslogik magische Strings und Zahlen verwenden müssen. Die Verwendung eines typisierten Datasets würde einige Probleme beheben, jedoch nicht vollständig. Bei der Verwendung typisierter Datensätze würden Sie sich von MVVM wegbewegen und eine engere Kopplung zwischen der Benutzeroberfläche und der Datenquelle herstellen.
Es hilft Ihnen bei der Trennung von GUI und Programmlogik. Das Mischen dieser Anwendungen kann dazu führen, dass Anwendungen nur schwer gewartet werden können, insbesondere wenn Ihr Projekt mit der Zeit wächst.
Von hier :
Warum sollten Sie als Entwickler sogar kümmern uns um das Model-View-ViewModel Muster? Es gibt eine Reihe von Nutzen dieses Muster für beide WPF- und Silverlight-Entwicklung . Bevor Sie fortfahren, fragen Sie sich:
- Müssen Sie ein Projekt für einen Designer freigeben und über die Flexibilität für die Designarbeit und Entwicklungsarbeit zu geschehen fast gleichzeitig?
- Benötigen Sie gründliche Komponententests für Ihre Lösungen?
- Ist es wichtig, dass Sie wiederverwendbare Komponenten sowohl innerhalb als auch .__ haben. projektübergreifend in Ihrer Organisation?
- Möchten Sie mehr Flexibilität beim Ändern Ihrer Benutzeroberfläche ohne andere Logik in der .__ umgestalten müssen. Code-Basis?
Wenn Sie eine dieser Antworten mit "Ja" beantwortet haben Fragen, das sind nur einige der Vorteile, die das MVVM-Modell verwenden kann Bring für dein Projekt mit.
Von Josh Smiths Artikel über MVVM :
Zusätzlich zu den WPF-Funktionen (und Silverlight 2) machen MVVM ein natürlicher Weg zur Strukturierung eines Anwendung ist das Muster auch beliebt, weil ViewModel-Klassen .__ sind. Einfacher Gerätetest. Wenn ein Die Interaktionslogik der Anwendung lebt In einer Reihe von ViewModel-Klassen können Sie leicht Code schreiben, der es testet. In einem Sinn, Ansichten und Komponententests sind nur zwei verschiedene Arten von ViewModel Verbraucher. Eine Reihe von Tests für ViewModels einer Anwendung enthält kostenlose und schnelle Regressionstests, was hilft, die Kosten von .__ zu reduzieren. Aufrechterhaltung einer Anwendung im Laufe der Zeit.
Für mich ist das der wichtigste Grund, MVVM einzusetzen.
Früher 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? Mit MVVM wird dieses Problem behoben, da die nicht testbare Ansicht vom testfähigen Ansichtsmodell getrennt wird und die Ansichtsebene so dünn wie möglich bleibt.
Ich beschäftige mich noch immer mit dem Muster, aber ich denke, es ist wertvoll. Die größte Herausforderung im Moment ist, 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 ein paar Dinge entdeckt, die mir sehr geholfen haben, das Muster sauberer zu machen:
Ich nutze den RelayCommand von Josh Smiths MVVM Foundation intensiv. Dadurch wird die Bindung von View an ViewModel über Befehle wesentlich sauberer.
Ich verwende AOP, um die Implementierung von INotifyPropertyChanged zu lindern. 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 schon aufgegeben, da der Boilerplate-Code zur manuellen Implementierung mich wirklich nervte.
Ich musste meine Herangehensweise an die Implementierung der Software ändern. Anstatt über eine Diktatorklasse zu verfügen, die allen Schergen sagt, was zu tun ist, was wiederum ihre Schergen einsetzt, wird meine Software eher eine Angelegenheit von lose gekoppelten Diensten, die sagen:
Dies ist, was ich weiß, wie ich es tun soll
Dies sind die Dinge, die ich getan haben muss
Wenn Sie anfangen, Ihren Code auf diese Weise zu strukturieren und Tools zu verwenden, mit denen die Abhängigkeiten leicht miteinander verbunden werden können (es gibt eine große Auswahl an IoC-Frameworks, aus denen Sie wählen können), habe ich festgestellt, dass dies die Unbequemlichkeit von MVVM erleichtert Sie können den Boilerplate-Code reduzieren, der mit dem Einfügen der Modelle in ViewModels und dem Auffinden verschiedener View Services (z. B. Anzeigen von Dateidialogen) für Ihre ViewModels verbunden ist.
Es ist eine enorme Investition, um diesen anderen Ansatz zu erlernen, und wie bei jeder größeren Änderung der Implementierung ist die Produktivität beim ersten Einsatz viel geringer. Ich sehe jedoch am Ende des Tunnels etwas Licht und glaube, dass meine Anwendungen sauberer und viel wartbarer sein werden, sobald ich die unordentlichen Details beherrscht.
Um die Frage zu INotifyPropertyChanged über Postsharp zu beantworten, verwende ich einen Aspect basierend auf dem Beispiel hier . Ich habe es ein bisschen für meinen Gebrauch angepasst, aber das gibt Ihnen den Kernpunkt. Damit markiere ich einfach die Klasse [NotifyPropertyChanged] und bei allen öffentlichen Eigenschaften wird das Muster in ihren Setters implementiert (auch wenn es sich um Auto-Property-Setter handelt). Es fühlt sich für mich viel sauberer an, da ich mir keine Sorgen mehr darüber machen muss, ob ich mir die Zeit nehmen möchte, damit die Klasse INotifyPropertyChanged implementiert. Ich kann das Attribut einfach hinzufügen und fertig sein.
Lesen Sie die Einführung in MVVM in diesem Artikel
Im Jahr 2005 stellte John Gossman, derzeit einer der WPF- und Silverlight-Architekten von Microsoft, das Model-View-ViewModel (MVVM) -Muster in seinem Blog vor. MVVM ist mit dem Darstellungsmodell von Fowler identisch, da beide Muster eine Abstraktion einer Ansicht enthalten, die den Zustand und das Verhalten einer Ansicht enthält. Fowler führte Presentation Model als Mittel zur Erstellung einer UI-plattformunabhängigen Abstraktion einer Ansicht ein, während Gossman MVVM als standardisierte Methode zur Nutzung der Kernfunktionen von WPF einführte, um die Erstellung von Benutzeroberflächen zu vereinfachen. In diesem Sinne halte ich MVVM für eine Spezialisierung des allgemeineren PM - Musters, das auf die Plattformen WPF und Silverlight zugeschnitten ist.
..
Im Gegensatz zum Presenter in MVP benötigt ein ViewModel keinen Verweis auf eine Ansicht. Die Ansicht bindet an Eigenschaften in einem ViewModel, das wiederum die in Modellobjekten enthaltenen Daten und andere für die Ansicht spezifische Zustände verfügbar macht. Die Bindungen zwischen view und ViewModel sind einfach zu erstellen, da ein ViewModel-Objekt als DataContext einer Ansicht festgelegt ist. Wenn sich die Eigenschaftswerte im ViewModel ändern, werden diese neuen Werte automatisch über die Datenbindung in die Ansicht übernommen. Wenn der Benutzer in der Ansicht auf eine Schaltfläche klickt, wird ein Befehl im ViewModel ausgeführt, um die angeforderte Aktion auszuführen. Das ViewModel, niemals die View, führt alle an den Modelldaten vorgenommenen Änderungen aus. Die Ansichtsklassen haben keine Ahnung, dass die Modellklassen vorhanden sind, während ViewModel und Modell die Ansicht nicht kennen. Tatsächlich ist das Modell der Tatsache nicht bewusst, dass ViewModel und View vorhanden sind. Dies ist ein sehr locker gekoppeltes Design, das sich in vielerlei Hinsicht auszahlt, wie Sie bald sehen werden.
In diesem Artikel wird auch erläutert, warum diese GUI-Muster verwendet werden:
Es ist unnötig und kontraproduktiv, Designmuster in einem einfachen "Hallo, Welt!" Programm. Jeder kompetente Entwickler kann einige Codezeilen auf einen Blick verstehen. Wenn jedoch die Anzahl der Merkmale in einem Programm zunimmt, nimmt die Anzahl der Codezeilen und der beweglichen Teile entsprechend zu. Die Komplexität eines Systems und die wiederkehrenden Probleme ermutigen die Entwickler schließlich dazu, ihren Code so zu organisieren, dass er einfacher zu verstehen, zu diskutieren, zu erweitern und zu beheben ist. Wir reduzieren das kognitive Chaos eines komplexen Systems, indem wir bekannte Entitäten auf bestimmte Entitäten im Quellcode anwenden. Wir bestimmen den Namen für einen Code, indem wir dessen funktionale Rolle im System berücksichtigen.
Entwickler gestalten ihren Code oft absichtlich nach einem Entwurfsmuster, anstatt die Muster organisch entstehen zu lassen. Bei beiden Ansätzen gibt es nichts zu beanstanden. In diesem Artikel untersuche ich jedoch die Vorteile der expliziten Verwendung von MVVM als Architektur einer WPF-Anwendung. Die Namen bestimmter Klassen enthalten bekannte Begriffe aus dem MVVM-Muster, z. B. enden mit "ViewModel", wenn die Klasse eine Abstraktion einer Ansicht ist. Dieser Ansatz hilft, das zuvor erwähnte kognitive Chaos zu vermeiden. Stattdessen können Sie glücklich in einem Zustand kontrollierten Chaos leben, wie es in den meisten professionellen Softwareentwicklungsprojekten der Fall ist.
MVVM hat viele gute Dinge, aber das Wichtigste ist vielleicht die Möglichkeit, Ihren Code zu testen (Unit-Test der ViewModels).
Die fehlende Verbindung zwischen Ansicht und Ansichtsmodell hilft auch bei der lockeren Kopplung. Es ist sehr einfach, die von Ihnen codierten Komponenten wiederzuverwenden.
Ich bin damit einverstanden, dass die Verwendung von MVVM den Schultern mehr Gewicht beim Schreiben von Code zuweist, Sehen Sie sich jedoch die helle Seite an, auf der alles isoliert ist. Wenn Sie ein Designer sind, können Sie Ihr Programm entwerfen und andere Programme für Sie und andere erstellen Wenn Sie die Datenbankschicht für Sie verwenden, schauen Sie, in welcher wartungsfähigen Umgebung Sie sich gerade in großen Unternehmensanwendungen befinden werden, wenn Sie MVVM nicht verwenden würden. Dann ist die Wartung fast tödlich .... Ich habe es selbst bei der Entwicklung verwendet ERP jetzt ist die Wartung aufgrund dieses Isolationsniveaus ziemlich einfach
Sie werden auf lange Sicht glücklich sein, wenn Sie ein Muster wie MVVM aus allen Gründen verwenden, die von anderen veröffentlicht wurden. Denken Sie daran, dass Sie nicht den Musteranforderungen Word-for-Word folgen müssen, sondern stellen Sie sicher, dass Sie eine gute Trennung zwischen Ihrem Fenster (Ansicht) und Ihrer Logik (Code-behind) haben.
MVVM ist wirklich übertriebener Code.
Welche Vorteile bietet die MVVM?
Es ist nur Trennung von Bedenken nicht mehr. Sie können auch die ViewModel-Logik in den Controller schreiben. Das ViewModel ist nur für eine Konvertierung zuständig (zum Beispiel und ein Objekt in einen String). Durch die Verwendung von MVVM verwenden Sie einen mehr objektorientierten Programmierstil. Durch das 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 können Sie nicht sagen, dass Sie MVVM verwenden müssen, weil es besser ist als MVC oder so, es ist nur eine persönliche Präferenz.
Nur um 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.
Vorteile von MVVM
Ich hoffe es hilft.