5.2. Model-View-Controller (MVC)
MVC trennt Datenmodell, Darstellung und Steuerung, damit sich Oberfläche und Fachlogik unabhängig ändern lassen.
Das Model hält Zustand und Fachlogik. Es kennt View und Controller nicht. Änderungen meldet es Beobachtern (Observer). Grobe Variante: „es hat sich etwas geändert“. Feiner wäre ein PropertyChangeListener.
Die View zeigt die Daten und nimmt Interaktionen entgegen. Sie kennt das Model, aktualisiert sich bei Änderungen und schreibt Benutzereingaben zurück. Aktionen an den Controller sind Absichten („Beenden“), nicht UI-Details (Button vs. Menü). Manche Frameworks bieten dafür Binding.
Der Controller übersetzt Absichten der View in Änderungen am Model. Er beobachtet die View, nicht umgekehrt die Pixel.
Kein vollständiges UI-Framework, nur die drei Rollen.
CautionDie Listener-Liste ist nicht threadsicher. Während des Iterierens darf niemand gleichzeitig ein- oder austragen.
import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;
class Model {
private final List<Consumer<Model>> listeners = new ArrayList<>();
private String name = "";
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
listeners.forEach(l -> l.accept(this));
}
public void addChangeListener(Consumer<Model> listener) {
listeners.add(listener);
}
public void removeChangeListener(Consumer<Model> listener) {
listeners.remove(listener);
}
}
class View {
private final List<Consumer<String>> actions = new ArrayList<>();
private Model model;
public void setModel(Model model) {
this.model = model;
model.addChangeListener(m -> updateView());
}
public void addActionListener(Consumer<String> listener) {
actions.add(listener);
}
public void init() {
// Controls erzeugen
}
public void show() {
updateView();
}
public void updateView() {
// Anzeige aus model.getName() füllen
}
public void updateModel() {
// Werte aus Controls nach model.setName(...) schreiben
}
public void sendAction(String intent) {
updateModel();
actions.forEach(a -> a.accept(intent));
}
}
class Controller {
private final Model model;
private final View view;
Controller(Model model, View view) {
this.model = model;
this.view = view;
view.setModel(model);
view.addActionListener(this::handleAction);
view.init();
view.show();
}
void handleAction(String intent) {
if ("reset".equals(intent)) {
model.setName("");
}
}
}
Die View trägt sich beim Setzen des Models als Beobachter ein. Vor jeder Aktion ruft sendAction updateModel auf, damit der Controller aktuelle Werte sieht. handleAction arbeitet mit der Intention, nicht mit dem auslösenden Control.