Logo Logo
InfoHome Themen Projekte Links Software
Themen
JavaHamster
BlueJ
Java
Sprachelemente
Abstrakte Datentypen
Swing
Composite Pattern
AWT > Swing
GUI-Grundstruktur
Farben und Fonts
Layout-Manager
Komponenten 1
Komponenten 2
Komponenten 3
Container
Observer Pattern
Ereignisverarbeitung
MVC-Pattern
Game Of Life
Threads
Aufgaben
Sortieren
HTML
XHTML
CSS
XML
Datenbanken
MySQL
Theoretische Informatik
PHP
Kara
Lego-Roboter
Algorithmen

Das Model-View-Controller Pattern

Beim MVC-Modell handelt es sich um ein Architekturmuster zur Trennung eines Programms in die drei Einheiten Datenmodell (Model), Präsentation (View) und Programmsteuerung (Controller). Ziel des Modells ist ein flexibles Programmdesign, um u.a. eine spätere Änderung oder Erweiterung einfach zu halten und die Wiederverwendbarkeit der einzelnen Komponenten zu ermöglichen. Außerdem sorgt das Modell bei großen Anwendungen für eine gewisse Übersicht und Ordnung durch Reduzierung der Komplexität. Gleichzeitig bringt die Trennung auch eine Rollenverteilung mit sich. Fachkräfte können so optimal, ihrer Fähigkeit entsprechend, eingesetzt werden: Ein Gestalter oder GUI-Designer erstellt das grafische Erscheinungsbild, der Programmierer erstellt die nötige Geschäftslogik, Datenbankexperten kümmern sich um die optimale Datenverwaltung usw.

Model

Das Datenmodell enthält die dauerhaften (persistenten) Daten der Anwendung. Das Model hat also Zugriff auf diverse Backend-Speicher wie zum Beispiel Datenbanken. Das Model kennt weder die View noch den Controller, es weiß also gar nicht, wie, ob und wie oft es dargestellt und verändert wird. Änderungen im Model werden allerdings über einen Update-Mechanismus bekannt gegeben, indem ein Event ausgelöst wird. Dazu muß sich zumindest die View als abhängiges Objekt am Model registrieren, um über Datenänderungen informiert zu werden.

View

Die Darstellungsschicht präsentiert die Daten in der Regel - jedoch nicht notwendigerweise - zwecks Anzeige. Die Programmlogik sollte aus der View entfernt werden. Die View kennt das Model und ist dort registriert, um sich selbständig aktualisieren zu können.

Controller

Die Steuerungsschicht realisiert die eigentliche Geschäftsintelligenz und bildet mit Hilfe der anderen Schichten die Prozesse ab. Sie steuert den Ablauf, verarbeitet Daten, entscheidet, welche View aufgerufen wird, etc.

[Quelle: de.wikipedia.org]

Beispiel 'Counter'

Am Beispiel eines einfachen Counters soll das MVC-Pattern demonstriert werden.

Die Klasse Counter

Die Klasse Counter repräsentiert unser 'Model'. Bei dieser einfachen Anwendung speichert ein Objekt vom Typ Counter lediglich den derzeitigen Zählerstand. Mit Hilfe der Methode incr() lässt sich der Zählerstand verändern.
Die Klasse Counter ist von der Klasse Observable abgeleitet. Dies bedeutet, dass sich Counter-Objekten von anderen Objekten - den Observern - überwachen lassen können. Die Liste der für ein Counter-Objekt registrierten Observer-Objekte wird in einem dynamischen Array verwaltet, um das wir und nicht weiter kümmern müssen. Bei Änderung des Zählerstands innerhalb der Methode incr() müssen wir nun dafür sorgen, dass alle Observer über die Veränderungen informiert werden. Zunächst markieren wir unser Counter-Objekt mit Hilfe der Methode setChanged() als verändert, und benachrichtigen im zweiten Schritt alle registrierten Observer durch Aufruf der Methode notifyObservers(). Als Argument erhält diese Methode ein Integer-Objekt, in dem der neue Zählerstand gekapselt ist.

import java.util.Observable;

public class Counter extends Observable {

  int cnt;

  public Counter() {
    cnt = 0;
  }

  public void incr(int i) {
    cnt += i;
    setChanged();
    notifyObservers(new Integer(cnt));
  }

}

Die Klasse ViewLabel

Die Klasse ViewLabel repräsentiert eine 'View'-Komponente, die wir als Custom-JPanel realisieren. Views möchten benachrichtigt werden, wenn sich unser model ändert. Aus diesem Grund muss unsere View-Klasse das Observer-Interface - mit seiner einzigen Methode update() - zu implementieren. Innerhalb der Methode update() werden nun die Aktionen programmiert, die bei einer Veränderung des überwachten Objektes ausgelöst werden sollen. Die Parameter dieser Methode sind zum einen eine Referenz auf das überwachte Objekt, das seinen Status verändert hat, und zum anderen das (Integer-)Objekt, das der Methode notifyObservers() innerhalb unserer Counter-Klasse als Argument übergeben worden ist.

import java.awt.*;
import java.util.*;
import javax.swing.*;

public class ViewLabel extends JLabel implements Observer{

  public ViewLabel() {
    setOpaque(true);
    setHorizontalAlignment(SwingConstants.CENTER);
    setBackground(Color.white);
  }

  public void update(Observable n, Object o){
    setText(((Integer)o).toString());
  }
}

Die Klasse ViewColor

Auch die Klasse ViewColor stellt eine 'View'-Komponente im Sinne des MVC-Patterns dar. Anstatt den aktuellen Wert anzuzeigen, zeigt diese View nur eine grün Fläche, falls der aktuelle Counter-Wert größer oder gleich Null ist, oder eine rote Fläche, wenn der Wert kleiner als Null ist. Diese Klasse erbt jetzt von ViewLabel und braucht deswegen das Observer-Interface nicht mehr explizit zu implementieren (das tun ja ViewLabel-Objekte bereits). In diesem Fall überschreiben wir die update()-Methode, die von der Klasse ViewLabel vererbt wird.
Mit Hilfe der Anweisung super() innerhalb des Konstruktors wird der Konstruktor der Oberklasse (hier: ViewLabel) aufgerufen. Da dieser Konstruktor einen weissen Hintergrund setzt, muss nochmals die Methode setBackground() mit dem konstanten Wert für 'Grün' aufgerufen werden.
Innerhalb der update-Methode findet sich ein Sprachkonstrukt, das einer if-then-else Bedingung ähnelt. Falls die erste Bedingung richtig ist, wird der Ausdruck hinter dem Fragezeichen eingesetzt, sonst der Ausdruck hinter dem Doppelpunkt.

import java.awt.Color;
import java.util.*;

public class ViewColor extends ViewLabel {

  public ViewColor() {
    super();
    setBackground(Color.green);
  }

  public void update(Observable n, Object o){
    setBackground( ((Integer)o).intValue() >= 0 ? Color.green : Color.red);
  }

}

Die Klasse ModelViewController

Schließlich bleibt noch der Controller. Innerhalb dieser Klasse bauen wir die gesamte grafische Oberfläche zusammen. Unsere beiden 'Views' werden beim 'Model' als Observer registriert. Mit Hilfe von zwei Action-Listenern werden die Buttons zum Hoch- und Runterzählen überwacht. In den zugehörigen actionPerformed()-Methoden wird der Counter-Stand durch Aufruf der Methode incr() mit entsprechendem Paramter verändert. Zur Initialisierung des Counters wird die Methode incr() zunächst mit dem Argument 0 aufgerufen.
In diesem Beispiel werden die ActionListener-Objekte mit Hilfe von annonymen Klassen erzeugt.

import java.awt.*;
import javax.swing.*;
import java.awt.event.*;

public class ModelViewController extends JPanel{

  JButton control1, control2;
  Counter model;
  ViewLabel view;
  ViewColor view2;

  public ModelViewController() {

    // die MVC Bestandteile initialisieren

    control1 = new JButton("+1");
    control2 = new JButton("-1");
    view = new ViewLabel();
    view2 = new ViewColor();
    model = new Counter();

    // die grafischen Objekte anordnen
    setLayout(new GridLayout(4,1));
    add(control1);
    add(control2);
    add(view);
    add(view2);

    model.addObserver(view);
    model.addObserver(view2);

    // die controller Ereignisse behandeln
    control1.addActionListener(new ActionListener()
      {
        public void actionPerformed(ActionEvent e) {
          model.incr(+1);
        }
      }
    );

    control2.addActionListener(new ActionListener()
      {
        public void actionPerformed(ActionEvent e) {
          model.incr(-1);
        }
      }
    );

    model.incr(0);
  }

  public static void main(String[] args){

    JFrame fenster = new JFrame();
    fenster.setTitle("Counter");
    fenster.setContentPane(new ModelViewController());
    fenster.setSize(170,150);
    fenster.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    fenster.setVisible(true);

  }

}

» drucken: pdf | html

© 2004-2024 M. Blanke · Ursulaschule · Kleine Domsfreiheit 11-18 · 49074 Osnabrück