Ich bin ein C ++ - Entwickler, der seitdem das MVC-Muster zum Entwerfen von GUIs verwendet.
Vor kurzem wollte ich wieder in C # einsteigen und habe eine Windows Forms-Anwendung eingerichtet, aber jetzt bin ich ein wenig verloren, wie ich sie auf eine MVC-kompatible Struktur übertragen kann.
Was ich derzeit versuche, ist, die Klasse, die ich für die WinForms erhalten habe, als Ansicht zu "deklarieren" und im Hintergrund eine Klasse für das Modell und den Controller hinzuzufügen. Ich bin mir jedoch nicht sicher, wie ich mit Ereignissen wie einem Klick auf eine Schaltfläche interagieren soll. Normalerweise leite ich diese Ereignisse an den Controller um und führe eine Aktion in der Ansicht aus, sobald ich fertig bin.
Dies fühlt sich in dieser Konstellation allerdings ziemlich unbefriedigend an. Wenn ich beispielsweise eine Schaltfläche "Beenden" implementieren möchte, muss ich das Ereignis von der Ansicht zum Controller umleiten und eine zusätzliche öffentliche Methode in meiner Ansicht implementieren, die dann vom Controller aufgerufen werden kann, während ich könnte in der ersten Instanz einfach Close () aus der Ansicht aufrufen.
Hast du einen Rat für mich? Ist mein Verständnis von Windows Forms in C # noch nicht gut genug, um eine MVC-Implementierung auszuprobieren? Gebe ich der Formularklasse eine falsche Rolle? Ist MVC einfach eine unangemessene Architektur für diesen Anwendungsfall?
Antworten:
Zufälligerweise arbeite ich an einem WinForms-Projekt, das MVC nachempfunden ist. Ich würde dies nicht als perfekte Antwort bezeichnen, aber ich werde mein Gesamtdesign erläutern und hoffe, dass dies Ihnen dabei helfen kann, Ihr eigenes zu finden.
Basierend auf der Lektüre, die ich vor Beginn dieses Projekts gemacht habe, scheint es keinen "richtigen" Weg zu geben, dies umzusetzen. Ich folgte einfachen OOP- und MVC-Entwurfsprinzipien und der Rest war Versuch und Irrtum, als ich einen Workflow entwickelte.
Nein ..? Ihre Frage enthält nicht genügend Kontext, um eine direkte Antwort darauf zu geben. Warum verwenden Sie MVC überhaupt? Was sind die nicht funktionalen Anforderungen Ihres Projekts? Wird Ihr Projekt sehr UI-schwer sein? Interessieren Sie sich mehr für Sicherheit und möchten lieber eine mehrschichtige Architektur? Was sind die Hauptkomponenten Ihres Projekts? Möglicherweise benötigt jede Komponente ein anderes Entwurfsmuster. Finden Sie heraus, warum Sie dieses Entwurfsmuster überhaupt verwenden möchten, und beantworten Sie möglicherweise Ihre eigene Frage;)
Mein Grund für die Verwendung von MVC: Meiner Meinung nach ist es ein ziemlich einfaches Entwurfsmuster, und mein Entwurf basiert stark auf Benutzerinteraktion. Die Art und Weise, wie MVC es dem Entwickler ermöglicht, Bedenken zu trennen, ist auch für meine Anwendung ausreichend. Das macht meinen Code viel besser verwaltbar und prüfbar.
Ich nehme auch an, dass ich eher ein Hybrid-Design verwende. Normalerweise spielt sich das in der Softwareentwicklung vorgestellte ideale Konzept in der Praxis nicht ab. Sie können das Design an die Anforderungen Ihres Projekts anpassen. Sie müssen sich nicht auf das einlassen, was richtig oder falsch ist. Es gibt allgemeine Praktiken, aber Regeln können immer verbogen oder gebrochen werden, solange Sie sich nicht in den Fuß schießen.
Meine Implementierung begann mit einem High-Level-Design, das mir eine Vorstellung davon gab, welche Komponenten ich benötigen werde. Beginnen Sie am besten auf diese Weise und arbeiten Sie sich in der Architektur nach unten. Hier ist das Paketdiagramm für das Projekt (erstellt in StarUML):
Beachten Sie, dass jede einzelne Ebene mit Ausnahme der Präsentationsschicht vom Messaging-System abhängt. Dies ist eine übliche "Sprache", mit der die unteren Schichten und Teilsysteme dieser Schichten miteinander kommunizieren. In meinem Fall war es eine einfache Aufzählung basierend auf Operationen, die ausgeführt werden können. Was mich zum nächsten Punkt bringt ...
Stellen Sie sich Operationen oder Befehle als Grundlage für Ihre Implementierung vor. Was soll Ihre Bewerbung tun? Teilen Sie es in die grundlegendsten Operationen auf. Beispiel: CreateProject, WriteNotes, SaveProject, LoadProject usw. In der GUI (oder den Formularklassen) tritt ein Ereignis auf (z. B. ein Tastendruck). Jeder Operation ist eine Controller-Methode zugeordnet. In diesem Fall ist so etwas wie Beenden zu einfach. Die Anwendung kann einfach aus der Form-Klasse geschlossen werden. Angenommen, ich wollte zuerst einige Anwendungsdaten in einer Datei speichern? Ich werde die "Save" -Methode aus der jeweiligen Controller-Klasse innerhalb meiner Tastendruckmethode aufrufen.
Von dort aus ruft der Controller die richtigen Operationen aus den Serviceklassen auf. Die Serviceklassen in meiner Anwendung fungieren als Schnittstelle zur Domänenschicht. Sie validieren die vom Aufruf der Controller-Methode (und damit von der GUI) empfangenen Eingaben und bearbeiten das Datenmodell.
Sobald die Validierung und die entsprechende Objektmanipulation abgeschlossen sind, gibt die Servicemethode einen Nachrichtencode an die Steuerung zurück. Zum Beispiel
MessageCodes.SaveSuccess
. Sowohl die Controller- als auch die Serviceklasse basierten auf den Domänenobjekten und / oder den allgemeinen Operationen, die zusammen gruppiert werden können.Zum Beispiel:
FileMenuController
(Operationen: NewProject, SaveProject, LoadProject) ->ProjectServices
(CreateProject, PersistProjectToFile, LoadProjectFromFile). WoProject
wäre eine Domänenklasse in Ihrem Datenmodell? Controller- und Service-Klassen waren in meinem Fall nicht instanziierbare Klassen mit statischen Methoden.Dann erkennt die Steuerung, dass der Vorgang nicht erfolgreich abgeschlossen wurde. Jetzt verfügt der Controller über ein eigenes Nachrichtensystem, mit dem er mit der Präsentationsschicht interagiert, daher die doppelte Abhängigkeit zwischen der Service- und der Präsentationsschicht. In diesem Fall wird eine
ViewState
imViewModels
Paket aufgerufene Klasse vom Controller immer an die GUI zurückgegeben. Dieser Status enthält Informationen wie: " Ist der Status, in dem Sie versucht haben, die Anwendung in einen gültigen Zustand zu versetzen? ", " Eine für Menschen lesbare Nachricht über den Vorgang, den Sie ausgeführt haben, und warum er erfolgreich war oder nicht (Fehlermeldungen) " und eineViewModel
Klasse.Die
ViewModel
Klasse enthält relevante Daten aus der Domänenschicht, die die GUI zum Aktualisieren der Ansicht verwendet. Diese Ansichtsmodelle sehen aus wie die Domänenklassen, aber in meinem Fall habe ich sehr dünne Objekte verwendet. Grundsätzlich haben sie so gut wie kein Verhalten, sondern geben nur Informationen über den Status der Anwendung auf niedrigerer Ebene weiter. Mit anderen Worten, bin ich nie gehen meine Domain - Klassen an die Präsentationsschicht weg zu geben. Aus diesem Grund teilen die PaketeControllers
undServices
die Serviceschicht in zwei Teile. Controller werden niemals Domänenklassen verarbeiten oder ihren Status überprüfen. Sie dienen lediglich als Grenze, um GUI-relevante Daten in domänenrelevante Daten umzuwandeln, die die Dienste verwenden können, und umgekehrt. Das Einbeziehen der Servicelogik in die Steuerung würde zu sehr Fett führen Controller, die schwerer zu warten sind.Ich hoffe, das gibt Ihnen einen Ausgangspunkt.
quelle