Wie eng sind in einer MVC-Architektur das Modell und die Ansicht mit dem Controller verbunden?

16

Ich habe eine App, die MVC verwendet, aber ich habe ein wenig Probleme damit, wie der Controller aufgebaut sein soll. In der Ansicht werden beispielsweise nur einige Teilmengen der Modelldaten gleichzeitig angezeigt. Ich bin mir jedoch nicht sicher, wie genau das geregelt werden soll. Ist es normal, dass die Ansicht oder das Modell zum Beispiel Funktionen auf dem Controller direkt aufruft? Über irgendeine Schnittstelle? Oder sind sie vollständig gekapselt und kennen sich nie mit dem Controller aus?

Nur als Bearbeitung; Dies ist eine benutzerdefinierte App, die nicht in einem Webframework geschrieben ist. Daher suche ich hier nicht nach Framework-spezifischen Details und habe die Freiheit, meine eigene Wahl zu treffen.

DeadMG
quelle
1
Ich werde nicht antworten, da meine Erfahrung mit MVC-Architekturen begrenzt ist, aber nach allem, worüber ich gehört und mit anderen gesprochen habe, sind die M & V eng miteinander verbunden, nicht jedoch das C. Das M ruft im Allgemeinen Funktionen für das C und das C auf V bindet oft nur Daten zu einer Teilmenge des M.
Steven Evers
8
@ SnOrfus: Das ist genau das Gegenteil von dem, was ich dachte - die M & V sind an das C gekoppelt, aber nicht aneinander.
DeadMG
1
Wie können so viele Antworten so falsch sein? Lesen Sie hier die MS-Version msdn.microsoft.com/en-us/library/ff649643.aspx
Reactgular
Lesen Sie diesen Artikel: objectmentor.com/resources/articles/taskmast.pdf
Edward Strange

Antworten:

15

Die Steuerung steuert den Aktivitätsfluss. Der Benutzer führt diese Aktion aus, der Controller übergibt die Anzeigedaten an die Domäne, die alles Erforderliche tut. Anschließend teilt der Controller dem Framework anhand der Antwort (en) mit, welche Ansicht als Nächstes angezeigt werden soll (und gibt ihm genügend Daten zur Verfügung so).

Der Controller muss also zum Teil an das Domain-Modell gekoppelt sein. dh Sie könnten eine Service-Schicht dazwischen legen, die jedoch per strenger Definition Teil der Domäne wird.

Es ist auch mit den Ansichtsdaten gekoppelt, jedoch nicht mit der Ansicht selbst. dh Es heißt einfach "Kundenansicht mit diesem Kundendetail anzeigen". Das Framework entscheidet dann, wo es diese Ansicht finden soll.

Jetzt sollte es Ihnen möglich sein, das Domänenmodell von der Ansicht zu entkoppeln, indem Sie ein Ansichtsmodell mit denselben Daten verwenden. Einige Entwickler tun dies, andere nicht, und ich denke, es ist größtenteils eine Frage der persönlichen Präferenz.

In Rails werden Sie sehr ermutigt, die Domänenobjekte (ActiveRecord) in die Ansicht zu verschieben und darauf zu vertrauen, dass die Ansicht diesen Zugriff nicht nutzt (z. B. sollten Sie customer.save nicht aus der Ansicht heraus aufrufen, obwohl dies der Fall ist wäre verfügbar).

In der .NET-Welt neigen wir dazu, das Risiko zu verringern, indem wir Dinge, die nicht passieren sollten, nicht zulassen. Aus diesem Grund scheint mir das Modell der getrennten Ansicht populärer zu sein.

pdr
quelle
1
Modell anzeigen ist eine sehr verbreitete Praxis, wenn es um Unit-Tests geht. Normalerweise ordnen Sie einem Ansichtsmodell automatisch ein Domänenmodell oder ein DTO-Objekt zu. Sie würden dann Ihr Ansichtsmodell in einer Ansicht verwenden. Das Ansichtsmodell ist leicht zu testen und nicht an eine darunter liegende Ebene gebunden.
CodeART
7

Anmerkung: Robert C. Martin (auch bekannt als Onkel Bob) erklärt dies in seiner Keynote „ Architecture the Lost Years“ auf eine viel bessere und humorvollere Weise . Ein bisschen lang, bringt aber viele gute Konzepte bei.

tl; dr: Denken und planen Sie Ihre App nicht in Bezug auf MVC. Das MVC-Framework ist nur ein Implementierungsdetail.

Das verwirrendste an MVC ist, dass die Entwickler versuchen, alle zusammengeklebten Komponenten zu verwenden.

Versuchen Sie, in den Begriffen eines Programms zu denken, nicht in den Begriffen des Frameworks.

Ihr Programm hat einen Zweck. Es nimmt einige Daten auf, erledigt Dinge mit Daten und gibt einige Daten zurück.

Auf diese Weise ist das controllerder Lieferungsmechanismus Ihres Programms.

  1. Ein Benutzer sendet eine Anfrage an Ihr Programm (z. B. ein Produkt in den Warenkorb legen).
  2. Die Steuerung nimmt diese Anfrage entgegen (Produktinfo und Benutzerinfo) und ruft den erforderlichen Teil Ihres Programms auf, der diese Anfrage bearbeiten wird $user->addToCart($product)
  3. Ihr Programm ( in diesem Fall die addToCartFunktion des userObjekts) erledigt die beabsichtigte Arbeit und gibt eine Antwort zurück (sagen wir mal success)
  4. Die Steuerung bereitet die Antwort unter Verwendung der relevanten view: z. im Controller-Objekt$this->render($cartView('success')

Auf diese Weise werden die Steuerungen vom Programm entkoppelt und als Liefermechanismus verwendet. Sie wissen nicht, wie Ihr Programm funktioniert, sondern nur, welcher Teil des Programms für die Anforderungen aufgerufen werden muss.

Wenn Sie ein anderes Framework verwenden möchten, muss Ihre App nicht geändert werden. Sie müssen lediglich relevante Controller schreiben, um Ihr Programm für Anforderungen aufzurufen.

Wenn Sie eine Desktop-Version erstellen möchten, bleibt Ihre App unverändert. Sie müssen lediglich einen Übermittlungsmechanismus vorbereiten.

Und die Model. Stellen Sie es sich als einen Persistenzmechanismus vor.

Auf die OO-Weise gibt es Objekte in Ihrem Programm, die die Daten enthalten.

class User {
    //...
    private $id;
    private $shoppingCart;
    //...
}

class Product {
    //...
    private $id;
    //...
}

Wenn Sie einen Artikel in den Warenkorb zu legen, können Sie das addieren , product::idum die user::shoppingCart.

Wenn Sie die Daten beibehalten möchten, können Sie den modelTeil des Frameworks verwenden, der im Allgemeinen aus einem ORM besteht, um die Klassen den Datenbanktabellen zuzuordnen.

Wenn Sie den von Ihnen verwendeten ORM ändern möchten, bleibt Ihr Programm unverändert, nur die Zuordnungsinformationen ändern sich. Wenn Sie die Datenbanken alle zusammen vermeiden möchten, können Sie die Daten einfach in Nur-Text-Dateien schreiben, und Ihre App bleibt unverändert.


Schreiben Sie also zuerst Ihr Programm. Wenn Sie mit der 'OO'-Methode programmieren, verwenden Sie einfache alte Objekte der Sprache. Denken Sie zunächst nicht an MVC.

Hakan Deryal
quelle
Tolles Video. Vielen Dank. Ich würde Ihrer Interpretation jedoch nicht zustimmen. MVC ist kein Detail in der Bedeutung, die Onkel Bob dort hat. Sie werden feststellen, dass MVC ein Architekturmuster ist, das seinem von ihm erstellten "Interactor / Entity / Boundary" -Muster sehr ähnlich ist. Auf der anderen Seite empfiehlt er, ein bestimmtes MVC-System wie Spring oder was auch immer aufzuschieben. Wie er jedoch erklärt, ist die Bezeichnung "MVC" eine Art Bastardisierung des Begriffs.
Edward Strange
Ja, ich habe das so geschrieben, wie die Leute denken, was ein MVCist. Deshalb habe ich geschrieben MVC Framework.
Hakan Deryal
2

Martin Fowler beschreibt das MVC-Paradigma sehr gut. Hier ist ein Link zu seinem Artikel darüber http://martinfowler.com/eaaDev/uiArchs.html

Beachten Sie sein Zitat zu Separated Presentation "Die Idee hinter Separated Presentation ist eine klare Trennung zwischen Domänenobjekten, die unsere Wahrnehmung der realen Welt modellieren, und Präsentationsobjekten, die die GUI-Elemente darstellen, die wir auf dem Bildschirm sehen."

Johnnie
quelle
1

Hier ist ein einfaches Beispiel, wie MVC in einer typischen Java-Swing-Anwendung verwendet werden kann ...

Angenommen, Sie haben ein Bedienfeld mit einer Schaltfläche und einem Textfeld. Wenn die Taste gedrückt wird, wird ein Ereignis ausgelöst, das zu einer Statusänderung in der Anwendung führt. Sobald die Statusänderung registriert ist, wird das TextField deaktiviert.

Dies wäre dann der typische Ansatz einer einfachen MVC-Anwendung ...

Der Controller registriert sich als Listener der View-Ereignisse. Wenn Sie auf die Schaltfläche klicken, wird das Ereignis von der Ansicht selbst nicht verarbeitet. der Controller tut. Der Controller ist Swing-spezifisch, da er Swing-bezogene Ereignisse verarbeiten muss.

Der Controller erhält diese Benachrichtigung und muss entscheiden, wer damit umgehen muss (Die Ansicht oder das Modell). Da dieses Ereignis den Status der Anwendung ändert, werden die Informationen an das Modell weitergeleitet, das für die Daten- und Programmlogik verantwortlich ist. Einige machen den Fehler, Programmlogik in der Steuerung zu platzieren, aber in OOP repräsentieren Modelle sowohl Daten als auch Verhalten. Lesen Sie dazu Martin Fowler.

Die Nachricht wird vom Modell im richtigen Kontext empfangen. Das heißt, es gibt keinerlei Verweise auf Swing oder andere GUI-spezifische Verweise. Diese Nachricht spricht das Modell und NUR das Modell an. Wenn Sie feststellen, dass Sie javax.swing-Anweisungen in das Modell importieren, codieren Sie das Modell nicht richtig.

Das Modell setzt dann seinen Status auf "deaktiviert" und benachrichtigt alle interessierten Parteien über diese Modelländerung. Die Ansicht, die an dieser Veranstaltung interessiert ist, hat sich bereits als Beobachter für Modelländerungen registriert. Sobald das Model-Statusänderungsereignis von der Ansicht erfasst wurde, wird das TextField deaktiviert. Es ist auch zulässig, dass die Ansicht schreibgeschützte Informationen direkt von ihrem Modell abruft, ohne dass der Controller (in der Regel über eine bestimmte Schnittstelle, die vom Modell für solche Aktivitäten verfügbar gemacht wird) darauf zugreifen muss.

Wenn Sie eine solche lose Kopplung zwischen der Präsentations- und der Geschäftslogik- und der Datenebene fördern, können Sie Ihren Code viel besser verwalten. Wenn die Systeme wachsen, wächst auch Ihre Einstellung zu MVC. Beispielsweise ist Hierarchical MVC eine Erweiterung, die häufig verwendet wird, um MVC-Triaden zu großen unternehmensweiten Systemen zu verbinden, ohne Subsysteme miteinander zu koppeln

Constantin
quelle
0

Die Kopplung (die Art, die Sie vermeiden möchten) beinhaltet eine gegenseitige Abhängigkeit zwischen zwei Klassen. Das heißt, ein Foo hängt von einem Balken ab, und ein Balken hängt von einem Foo ab, sodass Sie einen nicht wirklich ändern können, ohne den anderen zu ändern. Das ist eine schlechte Sache.

Sie können es jedoch nicht wirklich vermeiden, einige Abhängigkeiten zu haben. Die Klassen müssen ein wenig voneinander wissen, sonst würden sie nie kommunizieren.

Im MVC-Muster steuert der Controller die Kommunikation zwischen dem Domänenmodell und der Präsentationsansicht. Als solches muss der Controller genug über das Modell wissen, um es aufzufordern, das zu tun, was es tun soll. Der Controller muss auch genug über die Ansicht wissen, um sie dem Client oder den Benutzern präsentieren zu können. Der Model Controller hat also Abhängigkeiten von beiden. Die Ansicht kann jedoch auch ohne den Controller existieren - es besteht keine Abhängigkeit. Ebenso hat das Modell keine Abhängigkeiten zum Controller - es ist einfach das, was es ist. Schließlich sind das Modell und die Ansicht vollständig voneinander getrennt.

Im Wesentlichen ist der Controller die Indirektionsebene, die die Ansicht vom Modell entkoppelt, sodass sie sich nicht gegenseitig kennen müssen.

Matthew Flynn
quelle
Ah, deshalb habe ich die Abstimmungen falsch geschrieben. Ich meinte, der Controller hat Abhängigkeiten von beiden. D'oh!
Matthew Flynn
-5

Nach meiner Erfahrung hängt das Modell im Allgemeinen nur von einer Ansicht ab, nicht von einer bestimmten, oft als Beobachter ... wenn es überhaupt eine solche Kopplung aufweist.

Die Ansicht ist in der Regel mit dem verbunden, was gerade angezeigt wird, was Sinn macht. Es ist schwer, eine Ansicht zu finden, die von der Ansicht abgekoppelt werden kann ... aber manchmal kann es zu einer partiellen Kopplung kommen.

Der Controller neigt häufig dazu, mit beiden zu koppeln. Dies ist auch sinnvoll, da es die Aufgabe ist, Ansichtsereignisse in Modelländerungen umzuwandeln.

Natürlich ist dies nur eine Tendenz, die ich beobachtet habe und zu keinem konkreten Beispiel wirklich etwas aussagt.

Um zu verstehen, was MVC ist und wie die Kopplungsbeziehung aussehen könnte, sollten Sie untersuchen, wie MVC entstanden ist. In der Umgebung, in der MVC erstellt wurde, gab es keine "Widgets" als Formularelemente, mit denen Sie Dialoge erstellen können. Eine "Ansicht" war eine Schachtel und es zeichnete Sachen. Eine Textansicht wäre ein Feld, das Text zeichnet. Eine Listenansicht war eine Box, die eine Liste zeichnen würde. Der "Controller" hat alle Maus- und Tastaturereignisse vom UI-System empfangen, die in dieser Ansicht stattgefunden haben. Es gab keine "textChanged" - oder "selectionChanged" -Ereignisse. Der Controller würde all diese Low-Level-Ereignisse aufnehmen und eine Interaktion mit dem Modell erzeugen. Das Modell würde, wenn es geändert wird, seine Ansichten mitteilen; wir sind seitdem gekommen, um diese Beziehung als "Beobachter" zu sehen und es '

DAS ist die Essenz des MVC-Musters. Da diese Art der UI-Programmierung auf niedriger Ebene im Allgemeinen nicht mehr durchgeführt wird, hat sich die MVC in viele verschiedene Richtungen entwickelt. Manche Dinge, die heute so heißen, sind kaum etwas wie die MVC und sollten eigentlich etwas anderes heißen. Es kann dennoch im Sinne eines Dialogs als Ganzes verwendet werden, der mit einem größeren Objekt interagiert. Es gibt jedoch viele bessere Alternativen.

Grundsätzlich geschieht alles, was die MVC lösen sollte, jetzt in Widgets und wir müssen es nicht mehr verwenden.


Für diejenigen, die glauben, es besser zu wissen:

http://www.codeproject.com/Articles/42830/Model-View-Controller-Model-View-Presenter-and-Mod

http://msdn.microsoft.com/en-us/library/ff649643.aspx

Ich bin mir sicher, dass es noch mehr gibt, aber diese stehen bei Google nur ganz oben auf der Liste. Wie Sie sehen, hängt das Modell in vielen Implementierungen stark von einer Ansichtsschnittstelle ab. Im Allgemeinen ist ein Modell beobachtbar und die Ansicht ist ein Beobachter.

Aber warum sollten Fakten im Weg stehen ...

Ein Artikel, der bereits in einer anderen Antwort veröffentlicht wurde, unterstützt auch meine Aussagen:

http://martinfowler.com/eaaDev/uiArchs.html

Wenn die Leute weiterhin sagen wollen, dass JEDER in der Designbranche Unrecht hat, dann ist das in Ordnung.

Edward Strange
quelle
4
Das ist eindeutig falsch. Ein Model darf niemals auf eine Ansicht angewiesen sein! Auch wenn diese Ansicht abstrakt oder eine Schnittstelle ist. Ein Modell sollte vollständig von der Präsentation entkoppelt sein!
Falcon
3
Die Antwort ist falsch. Das Modell hängt nicht von einer Ansicht oder einem Controller ab.
CodeART
2
@ Crazy Eddie Sie sagten: "Nach meiner Erfahrung hängt das Modell im Allgemeinen nur von einer Ansicht ab, nicht von einer bestimmten, oft als Beobachter." Ihre zitierte Referenz besagt: "Das Modell hängt jedoch weder von der Ansicht noch von der Steuerung ab." Hast du den zitierten Artikel überhaupt gelesen? Sieht nicht so aus.
CodeART
2
@ Crazy Eddie: Es ist mir egal, was jemand über beschissenes Codeprojekt schreibt. Dies ist ein schreckliches Design. Die Verwendung eines Beobachters zum Abhören von Änderungen ist in Ordnung, aber das Einfügen einer Präsentationsschnittstelle in ein Domänenmodell ist absolut falsch. Der zitierte Code aus dem Artikel ist in Bezug auf MVC in einigen grundlegenden Punkten fehlerhaft. Es lässt sogar zu, dass das Modell implizit vom Controller abhängt. Was für ein Mist.
Falcon
3
@ Crazy Eddie: lol @ Downvote Amoklauf. Habe ich dich verärgert?
Falcon
-7
  • Der Controller sendet das Modell an eine Ansicht und verarbeitet das übermittelte Modell aus den Ansichten, ist jedoch nicht eng mit einer Ansicht oder einem Modell verbunden.

Wenn der Controller eng mit einer Ansicht verbunden war, befinden wir uns in einer Welt von Webformularen. Sie verfügen über einen Code, der an eine Vorlagendatei gebunden ist (gilt für ASP.NET-Webformulare).

Aus diesem Grund ist der Controller nicht an ein Modell oder eine Ansicht gekoppelt. Es ist nur ein Mechanismus zum Verarbeiten von Anfragen und zum Senden von Antworten.

  • Die Ansicht ist eng an ein Modell gekoppelt. Wenn Sie Änderungen an Ihrem Modell vornehmen (z. B. die Eigenschaft ändern), müssen Sie Änderungen an Ihrer Ansicht vornehmen.

  • Das Modell ist nicht eng mit einer Ansicht verbunden. Wenn Sie Änderungen an einer Ansicht vornehmen, hat dies keine Auswirkungen auf ein Modell.

  • Das Modell weiß nichts über Controller oder Ansichten, in denen es verwendet werden kann. Daher ist das Modell nicht eng an eine Ansicht oder einen Controller gekoppelt.

Eine andere Art, darüber nachzudenken:

  • Nehmen Sie Änderungen an einem Controller vor - Ansicht und Modell bleiben davon unberührt

  • Vornehmen von Änderungen an einem Modell - Die Ansicht wird unterbrochen, da sie von einem Modell abhängt

  • Nehmen Sie Änderungen an einer Ansicht vor - Modell und Controller bleiben davon unberührt

Diese lose Kopplung in MVC-Projekten erleichtert den Komponententest.

CodeART
quelle
1
Das ist so falsch, dass es nicht lustig ist. Nicht einmal eine Erklärung wert. Ignoriere diese Antwort einfach komplett.
Reactgular
1
@MathewFoscarini Hör auf zu weinen und hinterlasse eine "richtige Antwort"
CodeART
2
lol, die ganze Designtheorie hinter MVC ist, dass sie nicht voneinander abhängig sind.
Reactgular
Ich habe mehr Informationen für Sie hinterlassen, hoffentlich macht es Sinn
CodeART