kurz
—
Das Design-Pattern Model-View-Controller, kurz MVC, kann man sich als objektorientierte Ausprägung des allgemeinen Ablaufs von Eingabe, Verarbeitung und Ausgabe, kurz EVA, denken. Model bedeutet Verarbeitung, View Ausgabe und Controller Eingabe. Der Controller ist vom Model(-Interface) abhängig und der View beobachtet das Model.
Motivation
———
Ich arbeite gerade an einem Projekt, bei dem ein GUI im Spiel sein wird und natürlich auch Unit-Tests. Die Frage der klugen Aufteilung der Aufgaben stellt sich immer, und im Internet findet sich nur wenig wirklich hilfreiches und verständliches zum Thema MVC.
Beispiel für ein Model: Calcer
——————————
Nehmen wir als Beispiel ein taschenrechnerartiges Dings, genannt Calcer. Ein Calcer-Objekt bekommt als Eingabe zwei ganze Zahlen a und b. Ein Calcer habe eine Methode “calc”, die die Verarbeitung besorgt und vier Methoden, die unterschiedliche Ergebnisse aus a und b geben: getMul, getDiv, getAdd, getSub für Multiplikation, Division, Addition und Subtraktion.
Nebenbei: Wie das Modell, Calcer, seine Aufgabe erledigt, das interessiert hier nicht. Vielleicht googlet es, vielleicht implementiert es eigene Arithmetik-Routinen, vielleicht und wahrscheinlich benutzt es Möglichkeiten der zugrundeliegenden Programmiersprache. Man nennt das “Kapselung”.
Calcer ist ein Beispiel für ein Modell. Es nimmt Eingaben entgegen, aber “wer” die Eingaben macht, woher diese Eingaben kommen, das spielt keine Rolle. Man kann auch sagen: Calcer, das Modell, ist von den Eingaben unabhängig. Das ist gut und gewollt: So kann ich das immer dasselbe Modell benutzen, auch wenn ich unterschiedliche Eingabe-Arten benutze.
Und Calcer ist von Ausgaben unabhängig. Ein Calcer stellt Ergebnisse zur Verfügung. Ob diese Ergebnisse abgerufen werden, das “interessiert” einen Calcer nicht. Die Ergebnisse sind da. Basta.
Beispiele für Eingabe-Arten
—————————
Wenn ein Mensch einen Calcer benutzen möchte, dann wird das entweder mit einem GUI geschehen, oder mittels einer Konsole, beispielsweise der bash. Der Einfachheit halber und ohne Beschränkung der Allgemeinheit soll das reichen.
Für jede gewünschte Eingabe-Art werde ich eine eigene Klasse erschaffen. Hier also einen ConsoleController und einen GuiController. Der ConsoleController wird wohl die eingetippten Daten lesen und weitergeben, nachdem der User “Return” gedrückt hat. Der GuiController könnte zwei Felder haben, für jede Zahl eins und dann noch einen Button, der die Berechnung anstößt.
Eine andere Art ist eine Anfrage/ Nachricht die mittels Netzwerk an einen Server gestellt wird. Da wechseln Details, aber das Prinzip bleibt.
Beispiele für Ausgabe-Arten
—————————
Siehe oben “Beispiele für Eingabe-Arten”. Wer ein GUI benutzt, der möchte dort auch das Ergebnis sehen, entsprechendes gilt für die Konsolieros. Und genau wie oben wird es entsprechende unterschiedliche Klassen geben. Ein ConsoleView wird immer wieder vier Zeilen ausgeben, eine für jedes Ergebnis. Ein GuiView könnte vier Felder enthalten, deren Inhalt nach der Verarbeitung erneuert wird.
Konzept getrennt, Realisierung vereint
————————————–
Gleichgültig, ob mit Konsole oder Fenster gearbeitet wird: Der Mensch vor der Maschine merkt nicht, dass intern unterschiedliche Klassen werkeln, eine, die Eingaben entgegen nimmt, eine andere die verarbeitet, eine dritte, die Ausgaben macht. Er benutzt einen Calcer und freut sich über die Ergebnisse.
Wer kennt wen?
————–
Oben habe ich herausgestellt, dass das Model, Calcer, von Eingaben und Ausgaben unabhängig ist. Es “kennt” weder die Eingabe- noch die Ausgabe-Klassen. Aber irgendwelche Abhängigkeiten müssen bestehen, denn sonst ist keine Zusammenarbeit möglich. Also: Wer kennt wen?
Die Eingabe, sprich der Controller, kennt das Model. Denn der Controller “füttert” das Model mit Daten und “bedient” es, leitet User-Wünsche an das Model weiter. Und das ist auch schon alles.
Und – häh?!?! – wie kommen die Ergebnisse der Verarbeitung in die Ausgabe? Gute Frage, junger Padawan, Du hast gestellt. Einfach die Antwort ist: Observer-Pattern.
Fazit
—–
Im Internet finden sich andere Herangehensweisen an MVC. Mich überzeugt der dargestellte Ansatz wegen minimaler Kopplung und klarer Aufgabentrennung. Offene Fragen bleiben. Wer regelt das Zusammenspiel von Model, View und Controller? Oft ist die Antwort: Der Controller. Aber man kann sich auch ein viertes Element denken, etwa in der Art des Mediator-Patterns. Wer “sorgt” sich um die Validierung der Eingabe? Das Model? Der Controller? Vielleicht ein viertes. Wie kann der Controller eine Meldung an den User machen? Muss er das? Mach’ es halt clever. Aber nicht zu clever.