- 3-Schichten-Architektur
-
Model-View-Controller (MVC, „Modell/Präsentation/Steuerung“) bezeichnet 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 es, einen flexiblen Programmentwurf zu machen, der u. A. eine spätere Änderung oder Erweiterung erleichtert und eine Wiederverwendbarkeit der einzelnen Komponenten ermöglicht.
Das MVC-Konzept wurde 1979 zunächst für Benutzungsoberflä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 aller komplexen Softwaresysteme; teils mit Differenzierungen und oftmals mehreren jeweils nach dem MVC-Muster aufgeteilten Modulen.
Inhaltsverzeichnis
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 Implementation 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 sich daraufhin die aktualisierten Daten besorgen. Die Präsentation verwendet 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. Der Controller kann in manchen Implementierungen ebenfalls zu einem „Beobachter“ des Modells werden, um bei Änderungen der Daten die 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 Entwicklungs-Effizienz 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 so 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 Model verfügen, wobei dieses dann mit dem eigentlichen Model 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, 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
Bei Webanwendungen findet die eigentliche Präsentation und die Auswertung der Benutzereingaben clientseitig durch den Browser statt. Der Browser ist über HTTP oder HTTPS mit dem Server verbunden.
Serverseitige Webanwendungen
Der serverseitige Controller wertet oft die eintreffenden Daten (Request) des Browsers aus, oft tritt er 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.
Serverseitiger Verzicht auf das Observer-Muster
Bei Webanwendungen kann der Browser nicht nach dem 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.
Der einfache Controller als Mittler zwischen Model, View und Webserver
Ein typischer Funktionsablauf kann so aussehen:
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 Projekt-Anforderungen. 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.
Eine wichtige Erweiterung ist die Nutzung einer zweiten Serveranfrage mittels Weiterleitung. Im Falle einer erfolgreichen Validierung von Formulareingaben wird das Model zunächst mit diesen Daten aktualisiert. Daraufhin wird ein Redirect durch den Controller angestoßen, wobei z. B. ein nachfolgendes Formular aufgerufen werden kann. Bei gescheiterter Validierung wird dagegen das vorherige Formular zur Eingabekorrektur erneut angezeigt. Mit dieser Technik wird insbesondere das irrtümliche mehrfache Absenden durch einen Seitenreload verhindert und es ergeben sich weitere Vorteile.
Controller und View als paarweise eigenständige Anfragen mit Http-Redirect
Eine extreme Variante arbeitet grundsätzlich mit einem Weiterleitungsschritt und versteht das Programm des ersten Schrittes als Controller, das Programm des zweiten Schrittes als View. Dabei greift der erste Schritt meist schreibend auf das Model zu, der zweite nur lesend. Je nachdem, wie die Validierung im Controller-Schritt ausfällt, erfolgt die Weiterleitung zurück zum vorherigen View (Formular) oder zu einem nachfolgenden.
Bei erfolgreicher Validierung:
Browser -> HTTP-Request -> Webserver <=> Controller => Model (Speichern der Daten) Browser <- HTTP-Redirect <- Webserver <=> Controller
Browser -> HTTP-Request -> Webserver <=> Controller => View (weitere Seite / weiteres Formular) Browser <- HTTP-Redirect <- Webserver <=> Controller
Bei erfolgloser Validierung:
Browser -> HTTP-Request -> Webserver <=> Controller => View (Formular zur Überarbeitung der Eingaben) Browser <- HTTP-Redirect <- Webserver <=> Controller
Controller und View treten jeweils paarweise auf, rein lesende Funktionen können aber auf den vorgeschalteten Controller verzichten. Im Beispiel einer lesenden Such-Anfrage müssen die Anfrage-Parameter dann entweder direkt durch das Model oder indirekt durch den View ausgelesen werden. Hierbei werden also Teilfunktionen des klassischen Controllers übernommen.
Das MVC-Muster wird bei dieser Variante auf einer anderen Ebene interpretiert. Es sind verschiedene Übergangsformen und Kombinationen möglich.
Konfigurierbare Controller
Diese Controller stehen als Bibliotheken zur Verfügung. Sie arbeiten nach einem fixen Schema und werden im Unterschied zu den vorgenannten Beispielen nicht individuell für jede Anwendung programmiert. In ihrem Funktionsumfang sind sie entsprechend limitiert, so dass weitergehende Funktionalitäten in Model oder View lokalisiert werden müssen. Die Konfiguration legt fest, welche Programmteile jeweils als Model, View und Validatoren zusammenwirken und wohin Weiterleitungen führen. Ein bekanntes Beispiel ist das Struts-Framework.
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 die validate.jsp, welches in diesem Fall das Control-Modul ist, prüft die eingegebenen Werte. 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 User erneut das Formular mit z. B. einem Fehler-Hinweis 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 User beispielsweise eine Erfolgsbestätigung.
Literatur
- Hanspeter Mössenböck: Objektorientierte Programmierung. Springer-Verlag, 1993, ISBN 3-540-55690-7
Weblinks
- Trygve Reenskaug – MVC (englisch)
- Portland Pattern Repository – Model View Controller (englisch)
- Jeff Moore – Model View Controller (englisch)
Wikimedia Foundation.