Ich glaube, ich verstehe die Grundkonzepte von MVC - das Modell enthält die Daten und das Verhalten der Anwendung, die Ansicht ist dafür verantwortlich, sie dem Benutzer anzuzeigen, und der Controller kümmert sich um Benutzereingaben. Ich bin mir nicht sicher, was genau im Controller steckt.
Nehmen wir zum Beispiel an, ich habe eine ziemlich einfache Anwendung (ich denke speziell an Java, aber ich nehme an, dass die gleichen Prinzipien auch anderswo gelten). Ich meinen Code in 3 Pakete genannt organisieren app.model
, app.view
und app.controller
.
Innerhalb des app.model
Pakets habe ich einige Klassen, die das tatsächliche Verhalten der Anwendung widerspiegeln. Diese extends Observable
und verwenden setChanged()
und notifyObservers()
lösen die Ansichten aus, um sie gegebenenfalls zu aktualisieren.
Das app.view
Paket verfügt über eine Klasse (oder mehrere Klassen für verschiedene Anzeigetypen), die javax.swing
Komponenten für die Anzeige verwendet. Einige dieser Komponenten müssen in das Modell zurückgeführt werden. Wenn ich das richtig verstehe, sollte die Ansicht nichts mit dem Feedback zu tun haben - das sollte vom Controller behandelt werden.
Was stelle ich eigentlich in den Controller? Füge ich das public void actionPerformed(ActionEvent e)
in die Ansicht ein, indem ich nur eine Methode im Controller aufrufe? Wenn ja, sollte eine Validierung usw. im Controller durchgeführt werden? Wenn ja, wie kann ich Fehlermeldungen an die Ansicht zurückmelden - sollte dies das Modell erneut durchlaufen oder sollte der Controller es einfach direkt an die Ansicht zurücksenden?
Was füge ich in den Controller ein, wenn die Validierung in der Ansicht erfolgt?
Entschuldigung für die lange Frage, ich wollte nur mein Verständnis des Prozesses dokumentieren und hoffentlich kann jemand dieses Problem für mich klären!
quelle
Das Problem dabei
MVC
ist, dass die Leute denken, dass die Ansicht, der Controller und das Modell so unabhängig wie möglich voneinander sein müssen. Sie denken nicht - eine Ansicht und ein Controller sind oft miteinander verflochten - alsM(VC)
.Der Controller ist der Eingabemechanismus der Benutzeroberfläche, der insbesondere bei GUIs häufig in der Ansicht verwickelt ist. Trotzdem wird die Ansicht ausgegeben und der Controller eingegeben. Eine Ansicht kann oft ohne einen entsprechenden Controller funktionieren, aber ein Controller ist ohne Ansicht normalerweise weitaus weniger nützlich. Benutzerfreundliche Controller verwenden die Ansicht, um die Benutzereingaben aussagekräftiger und intuitiver zu interpretieren. Dies macht es schwierig, das Controller-Konzept von der Ansicht zu trennen.
Stellen Sie sich einen funkgesteuerten Roboter auf einem Erkennungsfeld in einer versiegelten Box als Modell vor.
Das Modell dreht sich alles um Zustand und Zustandsübergänge ohne Konzept der Ausgabe (Anzeige) oder was die Zustandsübergänge auslöst. Ich kann die Position des Roboters auf dem Feld ermitteln und der Roboter weiß, wie er die Position wechselt (einen Schritt vorwärts / rückwärts / links / rechts). Ohne Ansicht oder Steuerung leicht vorstellbar, aber nichts Nützliches
Stellen Sie sich eine Ansicht ohne Controller vor, z. B. jemanden in einem anderen Raum im Netzwerk in einem anderen Raum, der die Position des Roboters als (x, y) -Koordinaten beobachtet, die über eine Bildlaufkonsole gestreamt werden. Diese Ansicht zeigt nur den Status des Modells an, aber dieser Typ hat keinen Controller. Auch diese Ansicht ist ohne Controller leicht vorstellbar.
Stellen Sie sich eine Steuerung ohne Sicht vor, z. B. jemanden, der in einem Schrank eingeschlossen ist und dessen Funksteuerung auf die Frequenz des Roboters abgestimmt ist. Dieser Controller sendet Eingaben und verursacht Zustandsübergänge, ohne zu wissen, was sie mit dem Modell tun (wenn überhaupt). Leicht vorstellbar, aber ohne Feedback aus der Ansicht nicht wirklich nützlich.
Die meisten benutzerfreundlichen Benutzeroberflächen koordinieren die Ansicht mit dem Controller, um eine intuitivere Benutzeroberfläche bereitzustellen. Stellen Sie sich beispielsweise eine Ansicht / Steuerung mit einem Touchscreen vor, der die aktuelle Position des Roboters in 2D anzeigt und es dem Benutzer ermöglicht, den Punkt auf dem Bildschirm zu berühren, der sich gerade vor dem Roboter befindet. Der Controller benötigt Details zur Ansicht, z. B. die Position und den Maßstab des Ansichtsfensters und die Pixelposition des berührten Punkts relativ zur Pixelposition des Roboters auf dem Bildschirm, um dies richtig zu interpretieren (im Gegensatz zu dem Mann, der mit im Schrank eingeschlossen ist) die Funksteuerung).
Habe ich deine Frage schon beantwortet? :-)
Der Controller ist alles, was Eingaben vom Benutzer entgegennimmt, mit denen das Modell in den Übergangszustand versetzt wird. Versuchen Sie, die Ansicht und den Controller getrennt zu halten, stellen Sie jedoch fest, dass sie häufig voneinander abhängig sind. Daher ist es in Ordnung, wenn die Grenze zwischen ihnen verschwommen ist, dh wenn Ansicht und Controller als separate Pakete nicht so sauber voneinander getrennt sind wie Sie wie, aber das ist okay. Möglicherweise müssen Sie akzeptieren, dass der Controller nicht sauber von der Ansicht getrennt wird, da die Ansicht vom Modell stammt.
Ich sage, eine verknüpfte Ansicht und ein Controller sollten frei interagieren, ohne das Modell durchzugehen. Der Controller nimmt die Benutzereingaben entgegen und sollte die Validierung durchführen (möglicherweise unter Verwendung von Informationen aus dem Modell und / oder der Ansicht). Wenn die Validierung jedoch fehlschlägt, sollte der Controller in der Lage sein, die zugehörige Ansicht direkt zu aktualisieren (z. B. Fehlermeldung).
Der Härtetest besteht darin, sich zu fragen, ob eine unabhängige Ansicht (dh der Mann im anderen Raum, der die Roboterposition über das Netzwerk beobachtet) aufgrund eines Validierungsfehlers eines anderen (z. B. des Mannes im Schrank) etwas sehen sollte oder nicht versuchte den Roboter anzuweisen, das Feld zu verlassen). Im Allgemeinen lautet die Antwort nein - der Validierungsfehler hat den Zustandsübergang verhindert. Wenn es keine staatliche Transformation gab (der Roboter bewegte sich nicht), müssen die anderen Ansichten nicht mitgeteilt werden. Der Typ im Schrank hat einfach keine Rückmeldung erhalten, dass er versucht hat, einen illegalen Übergang zu verursachen (keine Ansicht - schlechte Benutzeroberfläche), und niemand sonst muss das wissen.
Wenn der Typ mit dem Touchscreen versuchte, den Roboter vom Feld zu schicken, erhielt er eine nette benutzerfreundliche Nachricht, in der er darum gebeten wurde, den Roboter nicht zu töten, indem er ihn vom Erkennungsfeld schickte, aber auch dies muss niemand anderes wissen.
Wenn andere Ansichten über diese Fehler Bescheid wissen müssen, sagen Sie effektiv, dass die Eingaben des Benutzers und alle daraus resultierenden Fehler Teil des Modells sind und das Ganze etwas komplizierter ist ...
quelle
Hier ist ein guter Artikel über die Grundlagen von MVC.
Es sagt aus ...
Mit anderen Worten, Ihre Geschäftslogik. Der Controller reagiert auf Aktionen des Benutzers, die in der Ansicht ausgeführt wurden, und reagiert. Sie geben hier die Validierung ein und wählen die entsprechende Ansicht aus, wenn die Validierung fehlschlägt oder erfolgreich ist (Fehlerseite, Meldungsfeld, was auch immer).
Es gibt einen weiteren guten Artikel bei Fowler .
quelle
Das MVC-Muster möchte lediglich, dass Sie die Präsentation (= Ansicht) von der Geschäftslogik (= Modell) trennen . Der Controller-Teil ist nur dazu da, Verwirrung zu stiften.
quelle
In der Praxis habe ich das Controller-Konzept nie als besonders nützlich empfunden. Ich verwende in meinem Code eine strikte Modell- / Ansichtstrennung, aber es gibt keinen klar definierten Controller. Es scheint eine unnötige Abstraktion zu sein.
Persönlich scheint eine ausgewachsene MVC das werkseitige Designmuster zu sein, da sie leicht zu verwirrendem und überkompliziertem Design führt. Sei kein Architekturastronaut .
quelle
Aufgrund Ihrer Frage habe ich den Eindruck, dass Sie in Bezug auf die Rolle des Modells etwas verschwommen sind. Das Modell ist auf die mit der Anwendung verknüpften Daten fixiert. Wenn die App über eine Datenbank verfügt, besteht die Aufgabe des Modells darin, mit ihr zu sprechen. Es wird auch jede einfache Logik verarbeiten, die diesen Daten zugeordnet ist. wenn Sie eine Regel haben, die besagt, dass für alle Fälle, in denen TABLE.foo == "Hurra!" und TABLE.bar == "Huzzah!" Setzen Sie dann TABLE.field = "W00t!", und Sie möchten, dass sich das Modell darum kümmert.
Der Controller sollte den Großteil des Verhaltens der Anwendung verarbeiten. Um Ihre Fragen zu beantworten:
Ich würde nein sagen. Ich würde sagen, das sollte im Controller leben; Die Ansicht sollte einfach die von der Benutzeroberfläche kommenden Daten in den Controller einspeisen und den Controller entscheiden lassen, welche Methoden als Antwort aufgerufen werden sollen.
Der Großteil Ihrer Validierung sollte wirklich vom Controller durchgeführt werden. Es sollte die Frage beantworten, ob die Daten gültig sind oder nicht. Wenn dies nicht der Fall ist, geben Sie die entsprechenden Fehlermeldungen an die Ansicht weiter. In der Praxis können Sie einige einfache Überprüfungen der Integrität in die Ansichtsebene integrieren, um die Benutzererfahrung zu verbessern. (Ich denke hauptsächlich an Webumgebungen, in denen möglicherweise eine Fehlermeldung angezeigt wird, sobald der Benutzer auf "Senden" klickt, anstatt auf den gesamten Zyklus "Senden -> Verarbeiten -> Seiten laden" zu warten, bevor er mitteilt, dass er Fehler gemacht hat .) Sei einfach vorsichtig; Sie möchten den Aufwand nicht mehr als nötig duplizieren, und in vielen Umgebungen (ich denke wieder an das Web) müssen Sie Daten, die von der Benutzeroberfläche stammen, häufig als schmutziges, schmutziges Paket behandeln lügt bis du '
Sie sollten ein Protokoll eingerichtet haben, bei dem die Ansicht nicht unbedingt weiß, was als nächstes passiert, bis der Controller dies mitteilt. Welchen Bildschirm zeigen Sie ihnen, nachdem der Benutzer diese Schaltfläche gedrückt hat? Die Ansicht weiß es möglicherweise nicht, und der Controller weiß es möglicherweise auch nicht, bis er die gerade erhaltenen Daten betrachtet. Dies kann "Wie erwartet zu diesem anderen Bildschirm wechseln" oder "Auf diesem Bildschirm bleiben und diese Fehlermeldung anzeigen" sein.
Nach meiner Erfahrung sollte die direkte Kommunikation zwischen dem Modell und der Ansicht sehr, sehr eingeschränkt sein und die Ansicht sollte keine Daten des Modells direkt ändern. Das sollte die Aufgabe des Controllers sein.
Siehe oben; Die eigentliche Validierung sollte im Controller erfolgen. Und hoffentlich haben Sie eine Vorstellung davon, was jetzt in den Controller eingefügt werden soll. :-)
Es ist erwähnenswert, dass an den Rändern alles etwas verschwommen werden kann. Wie bei fast allem, was so komplex ist wie Software-Engineering, wird es eine Fülle von Urteilsforderungen geben. Verwenden Sie einfach Ihr bestes Urteilsvermögen, versuchen Sie, innerhalb dieser App konsistent zu bleiben, und versuchen Sie, die gewonnenen Erkenntnisse auf das nächste Projekt anzuwenden.
quelle
Controller ist wirklich Teil der Ansicht. Seine Aufgabe besteht darin, herauszufinden, welche Dienste zur Erfüllung der Anforderung benötigt werden, Werte aus der Ansicht in Objekte zu entfernen, die für die Dienstschnittstelle erforderlich sind, die nächste Ansicht zu bestimmen und die Antwort wieder in eine Form zu bringen, die die nächste Ansicht verwenden kann . Es behandelt auch alle Ausnahmen, die ausgelöst werden, und rendert sie in Ansichten, die Benutzer verstehen können.
Die Service-Schicht kennt die Anwendungsfälle, Arbeitseinheiten und Modellobjekte. Der Controller ist für jeden Ansichtstyp unterschiedlich. Sie verfügen nicht über denselben Controller für Desktop-, browserbasierte, Flex- oder mobile Benutzeroberflächen. Ich sage also, es ist wirklich Teil der Benutzeroberfläche.
Serviceorientiert: Hier wird gearbeitet.
quelle
Die Steuerung dient in erster Linie der Koordination zwischen Ansicht und Modell.
Leider wird es manchmal mit der Ansicht vermischt - in kleinen Apps, obwohl dies nicht so schlimm ist.
Ich schlage vor, Sie setzen die:
in der Steuerung. Dann sollte Ihr Aktionslistener in Ihrer Ansicht an den Controller delegieren.
Was den Validierungsteil betrifft, können Sie ihn in die Ansicht oder in den Controller einfügen. Ich persönlich denke, er gehört in den Controller.
Ich würde definitiv empfehlen, einen Blick auf Passive View und Supervising Presenter zu werfen (in das Model View Presenter im Wesentlichen unterteilt ist - zumindest von Fowler). Sehen:
http://www.martinfowler.com/eaaDev/PassiveScreen.html
http://www.martinfowler.com/eaaDev/SupervisingPresenter.html
quelle
Hier ist eine Faustregel, die ich verwende: Wenn es sich um eine Prozedur handelt, die ich speziell für eine Aktion auf dieser Seite verwenden werde, gehört sie zum Controller und nicht zum Modell. Das Modell sollte nur eine kohärente Abstraktion für den Datenspeicher bereitstellen.
Ich habe mir das ausgedacht, nachdem ich mit einer großen Webanwendung gearbeitet habe, die von Entwicklern geschrieben wurde, die dachten, sie würden MVC verstehen, aber wirklich nicht. Ihre "Controller" sind auf acht Zeilen reduziert, in denen statische Klassenmethoden aufgerufen werden, die normalerweise nirgendwo anders genannt werden: - / machen ihre Modelle kaum mehr als Möglichkeiten zum Erstellen von Namespaces. Wenn Sie dies richtig umgestalten, werden drei Dinge ausgeführt: Verschiebt das gesamte SQL in die Datenzugriffsschicht (auch bekannt als Modell), macht den Controller-Code etwas ausführlicher, aber viel verständlicher und reduziert die alten "Modell" -Dateien auf nichts. :-)
quelle
Beachten Sie auch, dass jedes Swing-Widget die drei MVC-Komponenten enthält: Jedes verfügt über ein Modell (dh ButtonModel), eine Ansicht (BasicButtonUI) und ein Steuerelement (JButton selbst).
quelle
Sie haben im Wesentlichen Recht mit dem, was Sie in den Controller eingeben. Nur so sollte das Modell mit der Ansicht interagieren. Die ausgeführte Aktion kann in der Ansicht platziert werden, die eigentliche Funktionalität kann jedoch in einer anderen Klasse platziert werden, die als Controller fungieren würde. Wenn Sie dies tun, empfehle ich, das Befehlsmuster zu untersuchen, mit dem alle Befehle mit demselben Empfänger abstrahiert werden können. Entschuldigung für den Exkurs.
Auf jeden Fall hat eine ordnungsgemäße MVC-Implementierung nur die folgenden Interaktionen: Modell -> Ansichtsansicht -> Controller-Controller -> Ansicht
Der einzige Ort, an dem es zu einer anderen Interaktion kommen kann, ist, wenn Sie einen Beobachter zum Aktualisieren der Ansicht verwenden, muss die Ansicht den Controller nach den benötigten Informationen fragen.
quelle
Soweit ich weiß, übersetzt der Controller von Aktionen auf der Benutzeroberfläche in Aktionen auf Anwendungsebene. In einem Videospiel übersetzt der Controller beispielsweise "hat die Maus so viele Pixel bewegt" in "möchte in die eine oder andere Richtung schauen". In einer CRUD-App kann die Übersetzung "auf die eine oder andere Schaltfläche geklickt" werden "print this thing", aber das Konzept ist das gleiche.
quelle
Wir tun dies auf diese Weise, indem wir Controller hauptsächlich verwenden, um benutzergesteuerte Eingaben / Aktionen zu handhaben und darauf zu reagieren (und _Logic für alles andere, außer Ansicht, Daten und offensichtlichen _Model-Dingen):
(1) (Antwort, Reaktion - was die Webanwendung als Antwort auf den Benutzer "tut") Blog_Controller
-> main ()
-> handleSubmit_AddNewCustomer ()
-> verifyUser_HasProperAuth ()
(2) ("Geschäfts" -Logik, was und wie die Webanwendung "denkt") Blog_Logic
-> sanityCheck_AddNewCustomer ()
-> handleUsernameChange ()
-> sendEmail_NotifyRequestedUpdate ()
(3) (Ansichten, Portale, wie die Webanwendung "erscheint") Blog_View
-> genWelcome ()
-> genForm_AddNewBlogEntry ()
-> genPage_DataEntryForm ()
(4) (nur Datenobjekt, erfasst in _ construct () jedes Blogs * -Klasse erfasst wurde und verwendet wird, um alle Webanwendungs- / Speicherdaten als ein Objekt zusammenzuhalten) Blog_Meta
(5) (Basisdatenschicht, liest / schreibt in DBs) Blog_Model
-> saveDataToMemcache ()
-> saveDataToMongo ()
-> saveDataToSql ()
-> loadData ()
Manchmal sind wir ein wenig verwirrt darüber, wo eine Methode im C oder im L platziert werden soll. Aber das Modell ist absolut solide, kristallklar, und da sich alle speicherinternen Daten im _Meta befinden, ist es auch dort ein Kinderspiel . Unser größter Sprung nach vorne war übrigens die Verwendung des _Meta-Einsatzes, da dies den gesamten Rohstoff aus den verschiedenen _C-, _L- und _Model-Objekten entfernte, alles mental einfach zu verwalten machte und uns auf einen Schlag das gab, was ist genannt "Abhängigkeitsinjektion" oder eine Möglichkeit, eine gesamte Umgebung zusammen mit allen Daten zu übertragen (deren Bonus die einfache Erstellung einer "Test" -Umgebung ist).
quelle