- Model View Controller
-
Model-View-Controller (englisch "model view controller" (MVC), deutsch auch: Modell-Präsentation-Steuerung) ist ein Architekturmuster zur Strukturierung von Software-Entwicklung in die drei Einheiten Datenmodell (engl. model), Präsentation (engl. view) und Programmsteuerung (engl. controller). Ziel des Musters ist ein flexibler Programmentwurf, der eine spätere Änderung oder Erweiterung erleichtert und eine Wiederverwendbarkeit der einzelnen Komponenten ermöglicht. Es ist dann zum Beispiel möglich, eine Anwendung zu schreiben, die das gleiche Modell benutzt, aber einerseits eine Windows- oder Linux-Oberfläche realisiert, andererseits aber auch eine Weboberfläche beinhaltet. Beides basiert auf dem gleichen Modell, nur Controller und View müssen dabei jeweils neu konzipiert werden.
Das MVC-Konzept wurde 1979 zunächst für Benutzeroberflächen in Smalltalk durch Trygve Reenskaug beschrieben (Seeheim-Modell), der damals an Smalltalk im Xerox PARC arbeitete. Es gilt mittlerweile aber als De-facto-Standard für den Grobentwurf vieler komplexer Softwaresysteme, teils mit Differenzierungen und oftmals mehreren jeweils nach dem MVC-Muster aufgeteilten Modulen.
Inhaltsverzeichnis
- 1 Klassisches Architekturmuster
- 2 Heutige Umsetzungen
- 3 Beispiele
- 4 Literatur
- 5 Weblinks
Klassisches Architekturmuster
Die drei Komponenten hängen je nach Realisierung unterschiedlich stark voneinander ab:
Modell (model)
Das Modell enthält die darzustellenden Daten und gegebenenfalls (abhängig von der Implementierung des MVC-Patterns) auch die Geschäftslogik. Es ist von Präsentation und Steuerung unabhängig. Die Bekanntgabe von Änderungen an relevanten Daten im Modell geschieht nach dem Entwurfsmuster „Beobachter“. Das Modell ist das zu beobachtende Subjekt, auch Publisher, also „Veröffentlicher“, genannt.
Präsentation (view)
Die Präsentationsschicht ist für die Darstellung der benötigten Daten aus dem Modell und die Entgegennahme von Benutzerinteraktionen zuständig. Sie kennt sowohl ihre Steuerung als auch das Modell, dessen Daten sie präsentiert, ist aber nicht für die Weiterverarbeitung der vom Benutzer übergebenen Daten zuständig. Im Regelfall wird die Präsentation über Änderungen von Daten im Modell mithilfe des Entwurfsmusters „Beobachter“ unterrichtet und kann daraufhin die aktualisierten Daten abrufen. Die Präsentation verwendet oft das Entwurfsmuster „Kompositum“.
Steuerung (controller)
Die Steuerung verwaltet eine oder mehrere Präsentationen, nimmt von ihnen Benutzeraktionen entgegen, wertet diese aus und agiert entsprechend. Zu jeder Präsentation existiert ein Modell. Es ist nicht die Aufgabe der Steuerung, Daten zu manipulieren. Die Steuerung entscheidet aufgrund der Benutzeraktion in der Präsentation, welche Daten im Modell geändert werden müssen. Sie enthält weiterhin Mechanismen, um die Benutzerinteraktionen der Präsentation einzuschränken. Präsentation und Steuerung verwenden zusammen das Entwurfsmuster „Strategie“, wobei die Steuerung der Strategie entspricht. Die Steuerung kann in manchen Implementierungen ebenfalls zu einem „Beobachter“ des Modells werden, um bei Änderungen der Daten den View direkt zu manipulieren.
Nicht definierte Funktionalitäten
Da das MVC-Muster in verschiedenen Programmiersprachen unterschiedlich realisiert werden muss, gibt es selbst keine genaue Definition über die Positionierung der Geschäftslogik innerhalb der MVC-Klassen. Diese kann je nach Anwendungsfall besser im Controller aufgehoben sein oder auch in das Modell verlagert werden. In der Praxis finden sich unterschiedliche MVC-Programmiergerüste: Einige schreiben strikt vor, wohin die Geschäftslogik gehört, andere überlassen diese Entscheidung dem Softwareentwickler.
In ähnlicher Weise ist der Ort für die Validierung der Benutzereingaben nicht definiert. Einfache Formatvalidierungen können bereits im View realisiert werden. Validierungen, welche stärker die Geschäftslogik berücksichtigen müssen, werden eher im Model oder im Controller implementiert.
Auch für die Formatierung der Rohdaten und die Internationalisierung ist nicht definiert, wo diese erfolgen. Aus Gründen der Entwicklungseffizienz bietet es sich oft an, diese im Model zu integrieren, so dass man sich beim View auf die Erstellung von Widgets oder Templates beschränken kann. Andererseits werden dadurch Aspekte der Darstellung in das Model verlagert, was zur Grundidee durchaus im Widerspruch steht. Als Variante bietet es sich daher auch an, hierfür eigenständige Funktionsbereiche vorzusehen, die man dann weder Model, View oder Controller zurechnen muss.
Heutige Umsetzungen
Heutige Umsetzungen halten sich in der Regel nicht streng an die drei Komponenten Model, View und Controller. Obwohl sich viele Projekte als Model-View-Controller-Architektur definieren, wird der Begriff sehr verschieden interpretiert. Es etablieren sich neue Begriffe, wie das Model-View-Presenter- oder das Model-View-Adapter-Muster, die versuchen, die Varianten präziser zu beschreiben.
Widget-Bibliotheken für Desktop-Applikationen
Als Widgets werden die einzelnen Komponenten grafischer Oberflächen bezeichnet, wie Menüpunkte oder Editor-Komponenten. Widgets zeichnen sich dadurch aus, dass sie neben der Präsentation auch typische Merkmale des klassischen Controllers in einer Komponente vereinen, wie das Event-Handling. Einige Widgets, wie z. B. Auswahllisten, können sogar über ein eigenes internes Modell verfügen, wobei dieses dann mit dem eigentlichen Modell synchronisiert werden muss.
Obwohl die Widgets die feste Dreiteilung durchbrechen, spricht man trotzdem noch von einer Model-View-Controller-Architektur. Es kommen auch Komponenten wie Filter zur Sortierung oder Bestätigungsdialoge vor, die sich nicht eindeutig in die klassische Dreiteilung einordnen lassen.
Bei der Anwendung der Widget-Bibliotheken überlässt der Controller damit einen Teil der klassischen Controller-Funktion den Widgets und beschränkt sich auf die Steuerung des Models und gegebenenfalls anderer Komponenten des Views.
Die Bedeutung des MVC-Entwurfsmusters wird noch klarer, wenn man sich in die Lage der Entwickler von GUI-Frameworks versetzt. Hier besteht die Herausforderung darin, dass zum Entwicklungszeitpunkt der GUI Widgets (View) nicht feststeht, welche fachliche Daten und Datenstrukturen (Modell) präsentiert und welche fachlichen Abläufe (Control) realisiert werden sollen. Damit besteht die Aufgabe der Entwickler eines GUI-Frameworks auch darin, eine Abstraktion für das Modell in Form von Schnittstellen bereitzustellen. An der Abbildung lässt sich gut erkennen, dass einzelne Teile, wie die Datenspeicherung oder das Aussehen, problemlos ausgetauscht werden können.
Das MVC-Entwurfsmuster definiert auch den Rahmen für die Entwickler von GUI-Frameworks. Ein fertiges GUI-Framework beinhaltet:
- eine Präsentation (view) in Form ausimplementierter GUI-Widgets,
- die Vereinbarung eines zugrundeliegenden Datenmodells in Form von Schnittstellen,
- die Vereinbarung von Ereignissen (engl. events) auf Grund von Benutzerinteraktionen in Form von Schnittstellen und ausimplementierten Klassen, sowie
- die Vereinbarung von Ereignissen auf Grund von Modelländerungen in Form von Schnittstellen und ausimplementierten Klassen.
Webanwendungen
Zusammenspiel von Server und Browser
Im weiteren Sinne verteilt sich das MVC-Muster bei Webanwendungen über Server und Browser und ist damit komplexer als das klassische MVC-Muster. Abstrakt betrachtet übernimmt der Browser dabei die sichtbare Darstellung und unmittelbaren Nutzereingaben, sowie die nicht seitenspezifischen Funktionen von Controller und View. Der Server kümmert sich um spezifische Steuerung des Browsers indem er mit diesem über HTTP kommuniziert.
Im engeren Sinne versteht man darunter aber nur das serverseitige Programm. Dabei kann man noch einmal zwischen dem Webserver für statische Webseiten oder dessen Delegation an spezielle Zusatzprogramme unterscheiden. Der Begriff MVC findet insbesondere im Rahmen solcher Zusatzprogramme zum Webserver Verwendung.
Model
Für den Browser ist die HTML-Seite der Datenkern seines Models. Aus der Perspektive des Gesamtsystems ist sie nur eine Sicht auf das Gesamtmodel, welches auf dem Server lokalisiert ist.
View
Der Browser kümmert sich um die allgemeinen Funktionen, wie die Darstellung von Text, Formularelementen und eingebetteten Objekten. Die Darstellung wird dabei im Speziellen durch den View-Programmteil des Servers per HTTP-Response gesteuert, deren Hauptteil der Darstellungsanweisung aus der HTML-Seite besteht.
Controller
Der Browser akzeptiert Formulareingaben und sendet diese ab oder nimmt das Anklicken eines Links entgegen. In beiden Fällen sendet er einen HTTP-Request an den Server. Der Controller-Programmteil verarbeitet die Daten der HTTP-Requests und stößt schließlich die Erstellung eines neuen Views an.
Javascript
Die Webseite kann Programmcode enthalten, normalerweise Javascript, z.B. für die browserseitige Validierung von Formulareingaben. Dieser Programmcode läßt sich wiederum nach dem MVC-Muster gliedern und so als Teil des Gesamtsystems betrachten.
Verzicht auf das Observer-Muster
Bei Webanwendungen kann der Browser nicht nach dem klassischen Observer-Muster unmittelbar auf Änderungen des Models auf dem Server reagieren. Jede Antwort (HTTP-Response) an den Browser setzt eine Anfrage (HTTP-Request) voraus. Man spricht vom Request-Response-Cycle. Daraus folgt, dass das Observer-Muster auch auf Seiten des Servers seine Vorteile nicht ausspielen kann. Weil es dann nur einen Mehraufwand bedeuten würde, kommt es typischerweise nicht zum Einsatz. Stattdessen tritt meist der Controller als aktiver Vermittler zwischen Model und View im Rahmen eines Request-Response-Cycles auf.
Die besonderen Herausforderungen des Hyperlinks und der Form-Action
Der Hyperlink ist ein herausragendes Merkmal von Webapplikationen. In einer klassischen GUI-Applikation würde hier im View ein Button erzeugt, dessen Klickevent anhand seiner ID im Controller mit dem Wechsel der Ansicht verknüpft wird. Der Hyperlink enthält zwar auch eine ID, es ist aber nicht seine eigene, sondern die Zieladresse der neuen Ansicht. Gleiches gilt für die Action-Adresse eines HTML-Formulars.
Beides sind für den Benutzer eines Browsers Controller-Elemente, deren funktionales Ziel allerdings in der Webseite codiert ist. Hiermit stellt sich die Herausforderung, bei der Erzeugung der Webseite die reine Ansicht von der Funktionalität der URL zu trennen. Der Entwickler des Views soll sich keine Gedanken über die oft komplexe Controller-Funktonalität der URL machen müssen.
Die Aufgabenteilung von View und Controller kann mittels einer ID einfach erreicht werden. In Analogie zur GUI-Applikation wird die ID im Controller mit der Zieladresse verknüpft. Im View kann die URL über eine Schnittstelle anhand der ID abgerufen werden oder die ID tritt als Platzhalter für die URL ein, zum Beispiel innerhalb eines Templates oder in Form von Link-Objekten im Rahmen eines Objektbaums.
Serverseitige Webanwendungen
Der serverseitige Controller wertet in der Regel die eintreffenden Daten (Request) des Browsers aus. Meist tritt er dabei als Moderator zwischen Model und View auf. Serverseitig werden unter dem View diejenigen Programmteile verstanden, die den HTML-Code für die Antwort (Response) erzeugen. Häufig arbeitet der View mit HTML-Templates, deren Platzhalter mit den Daten des Models ersetzt werden.
Der Controller als Mittler zwischen Model, View und Webserver
Ein typischer Funktionsablauf (ohne HTTP-Redirect):
Browser -> HTTP-Request -> Webserver -> Controller <=> (beliebig häufig) Model oder View Browser <- HTTP-Response <- Webserver <- Controller
Der Aufgabenumfang des Controllers kann sehr variabel sein. Im einfachsten Fall ordnet er nur Model und View zu. Er kann aber auch vielfältige weitere Aufgaben übernehmen. Das hängt davon ab, wie aktiv oder passiv sich Model und View jeweils verhalten in Bezug auf die Validierung, die Internationalisierung, die Geschäftslogik, die Iterationen über die Daten beim Einfügen in den View und in Bezug auf zahlreiche andere Aspekte.
Die Praxis variiert in Abhängigkeit vom persönlichen Programmierstil, Webservern, Programmiersprachen, Frameworks, dem Einsatz von Unit-Tests und den Projektanforderungen. Im Fall von PHP-Programmen steht zwischen Webserver und Controller z. B. noch der Programm-Interpreter, der bereits die Daten des HTTP-Requests aufbereitet und damit seinerseits Teilfunktionen des klassischen Controllers übernimmt.
HTTP-Redirect
Nach dem Beschreiben des Models (create oder update) empfiehlt sich ein HTTP-Redirect. Mit dieser Technik wird das irrtümliche mehrfache Absenden durch einen Seitenreload verhindert. Ausserdem wird dadurch das Schreiben des vorherigen Datensatzes vom Lesen des nachfolgenden Datensatzes getrennt, so daß sich die Controller sinnvoller oganisieren lassen.
Bei erfolgreicher Validierung greift die erste Anfrage, die noch den vorherigen Datensatz behandelt, schreibend auf das Model zu. Danach erfolgt ein Redirect. Die zweite Anfrage greift lesend zu und präsentiert bereits den nächsten Datensatz zur Bearbeitung. Für den Benutzer des Browsers fühlt sich das wie ein einziger Aufruf an.
Browser -> HTTP-Request -> Webserver -> Controller -> positive Validierung -> Model (speichern der Daten nach Validierung) Browser <- HTTP-Redirect <- Webserver <- Controller (danach Redirect durch den Controller) Browser -> HTTP-Request -> Webserver -> Controller -> Model -> View (führt zu neuer Formularanfrage ohne Nutzeraktion) Browser <- HTTP-Response <- Webserver <- Controller (reguläre Response)
Bei einer gescheiterten Validierung wird dagegen der empfangene Datensatz direkt wieder im gleichen Formular zur Korrektur präsentiert. Ein Redirect entfällt. In der Regel entfällt auch eine erneute Abfrage des Models.
Browser -> HTTP-Request -> Webserver -> Controller -> negative Validierung -> View (Formular zur Überarbeitung der Eingaben) Browser <- HTTP-Response <- Webserver <- Controller
Controller-Kaskade
Um dem Umfang der Funktionalität professioneller Webauftritte gerecht zu werden muss der Controller strukturiert werden. Häufig wird der Controller kaskadenartig strukturiert. Entweder wird auf der untersten Ebene der Kaskade ein Controller angesteuert oder die Controller verzweigen im Ablauf der Kaskade baumartig und führen zu einer Verschachtelung des resultierenden Views.
Front-Controller, Controller und Actions sind häufig verwendete Benennungen für eine 3-schichtige Controller-Struktur. Diese Benennungen spiegeln den Aufbau von Datenmodellen und die zugehörigen Datenoperationen wieder. Der Front-Controller verzweigt dabei zu einer Sicht auf das Datenmodell, die im Fokus steht und durch einen Controller gesteuert wird. Die Actions als unterste Controller-Ebene führen die Datenoperationen für diese Sicht aus, die man mit Create, Read, Update und Delete (CRUD) zusammenfassen kann.
Ein Beispiel für eine Controller-Schachtelung wäre eine Website, bei welcher der oberste Controller die Anzeige der Seiten steuert. In einer Seite können wiederum spezifisch mehrere MVC-Blöcke gleichzeitig eingesetzt werden, z.B. für einen zentralen Artikel und für unterschiedliche Kontext-Informationen.
Webanwendungen mit JavaScript-Bibliotheken und AJAX-Anbindung
Hier wird ein Teil der Programme der Model-View-Controller-Architektur clientseitig im Browser eingesetzt, während ein anderer Teil, insbesondere das Model, auf dem Server verbleibt. JavaScript-Bibliotheken stellen vielfältige Widgets zur Verfügung. Diese Anwendungen nehmen eine Zwischenstellung zwischen Webanwendungen und desktopartigen Widget-Bibliotheken ein.
Beispiele
MVC realisiert mit Java Server Pages
Die obige Abbildung zeigt das MVC-Modell für eine einfache Web-Registrierung. Der Benutzer (Client) fragt als erstes die Seite register.jsp an. Er bekommt eine Seite mit einem HTML-Formular als Antwort. Als Action ist im Formular die validate.jsp angegeben. Also schickt der Browser nach dem Ausfüllen des Formulars die eingegebenen Daten an das validate.jsp, das in diesem Fall das Control-Modul ist und die eingegebenen Werte prüft. Es ist nur für die Prüfung und Verarbeitung der Daten zuständig. Selbst gibt validate.jsp dem Benutzer kein Feedback. Das Control-Modul gibt dazu die Kontrolle an die entsprechenden Views weiter. In diesem Fall entweder an register.jsp, wenn die Eingaben ungültig waren, sonst an die ok.jsp. Wird die Kontrolle wieder zurück an die register.jsp übergeben, zeigt register.jsp dem Anwender erneut das Formular mit z. B. einem Fehlerhinweis an. Der Browser schickt die korrigierten Daten wieder an die validate.jsp. Sind die Eingaben korrekt, werden die Daten zur Speicherung an die UsersBean übergeben. Die Kontrolle wird daraufhin an die ok.jsp abgegeben. Diese zeigt dem Anwender beispielsweise eine Erfolgsbestätigung.
Literatur
- Hanspeter Mössenböck: Objektorientierte Programmierung. Springer-Verlag, 1993, ISBN 3-540-55690-7
- Erich Gamma, Richard Helm, Ralph Johnson: Entwurfsmuster . Elemente wiederverwendbarer objektorientierter Software, Addison-Wesley; 2. Aufl. ISBN 978-3-8273-1862-6
Weblinks
- Portland Pattern Repository – Model View Controller (englisch)
- Jeff Moore – Model View Controller (englisch)
- Martin Fowler – GUI Architectures (englisch)
Wikimedia Foundation.