homedukeOOP mit Java: Modell View Controller Architekturmuster Prof. Dr. Uwe Schmidt FH Wedel

Modell View Controller Architekturmuster

weiter

weiter

Model View Controller Architektur und Ereignisse

MVC
Model View Controller Architekturmuster
 
Ein Schema zur Trennung von Eingabe, Verarbeitung und Ausgabe in grafisch orientierter Software
weiter
Idee
übernommen aus dem alten EVA Ansatz:
 
Eingabe -> Verarbeitung -> Ausgabe
weiter
Eingabe
controller
read()
scanf()
weiter
Ausgabe
view
write()
printf()
weiter
Verarbeitung
model
keine Ein- und Ausgabe
weiter
Modularisierung
in Eingabe-, Verarbeitungs- und Ausgabemodul
 
Änderung der Benutzungsschnittstelle ohne Änderung der Verarbeitung
 
Wiederverwendung
weiter
merke
immer wieder schlechte Beispiele, auch in OO-Büchern:
 
Klassisches Beispiel:
Konversion einer Datenstruktur in einen Text und Ausgabe
weiter
grafische Benutzungsschnittstelle
in grafischen Umgebungen wird die Trennung in Eingabe, Verarbeitung und Ausgabe von den Werkzeugen häufig nicht unterstützt.
Beispiel
grafisches Objekt Auswahlliste
model
enthält eine Liste von Werten
view
eine Darstellung, Layout, Höhe, Breite, ...
controller
reagiert auf Eingaben, Ereignisse, markieren, klicken, ...
weiter
merke
keine Trennung von Eingabe, Verarbeitung und Ausgabe
merke
Wiederverwendung, Anpassbarkeit, Veränderbarkeit
weiter
MVC
model
enthält die internen Datenstrukturen und ihre Verarbeitungsroutinen
view
enthält die Darstellung der Daten, die Ausgabe
controller
enthält die grafischen Eingabeelemente
weiter
merke
lose Kopplung zwischen den drei Komponenten
 
Kommunikation über Ereignisse
weiter
merke
bei Programminitialisierung wird festgelegt, welche Komponenten auf welche Ereignisse reagieren.
 
Die Komponenten selbst wissen nichts über die Existenz anderer Komponenten
weiter
merke
Kontrollfluss nicht mehr explizit im Programm sichtbar.
 
Festlegung über event handler
weiter

weiter

Beispiel

Ein Zähler, der inkrementiert und dekrementiert werden kann, und dessen Wert in einem grafischen Objekt angezeigt wird.

0. Versuch: schlecht


Die MVC Variablen

  Button control1control2;
  int    model;
  Label  view;
  ...
 
  control1 = new Button("+1");
  control2 = new Button("-1");
  model    = 0;
  view     = new Label();

Die Ereignisbehandlung

    control1.addActionListener
      (new ActionListener()
       {
         public
         void actionPerformed(ActionEvent e) {
           ++model;
           view.setText(Integer.toString(model));
         }
       }
      );
 
    control2.addActionListener
      (new ActionListener()
       {
         public
         void actionPerformed(ActionEvent e) {
           --model;
           view.setText(Integer.toString(model));
         }
       }
      );
weiter

weiter

Noch schlechter

aber nicht praxisfern:
Das model wird im view versteckt.

Das gleiche Beispiel wie eben
-1. Versuch: noch schlechter


Die MVC Variablen

  Button control1control2;
  Label  view;
  ...
 
  control1 = new Button("+1");
  control2 = new Button("-1");
  view     = new Label();

Die Ereignisbehandlung

    control1.addActionListener
      (new ActionListener()
       {
         public
         void actionPerformed(ActionEvent e) {
           int i = Integer.valueOf(view.getText()
                                   ).intValue();
           view.setText(Integer.toString(i+1));
 
           // oder view.setText("" + (i+1));
         }
       }
      );
 
    control2.addActionListener
      (new ActionListener()
       {
         public
         void actionPerformed(ActionEvent e) {
           int i = Integer.valueOf(view.getText()
                                   ).intValue();
           view.setText(Integer.toString(i-1));
         }
       }
      );
weiter

weiter

merke
Eingabe, Verarbeitung und Ausgabe beliebig gemischt
zur schrittweisen Entkopplung der Komponenten
0. Versuch
keine Entkopplung
1. Verbesserung
controller und model/view getrennt
2. Verbesserung
model und view getrennt
weiter

weiter

Benutzerdefinierte Events

die Basisklasse für alle events.
 
AWT events werden aus AWTEvent abgeleitet.
 
Schema:
 
import java.util.EventObject;
 
public
class MyOwnEvent
  extends EventObject
{
  protected
  MyEventData d;
 
  public
  MyOwnEvent(Object sourceMyEventData d) {
    super(source);
    this.d = d;
  }
 
  public
  int getD() {
    return d;
  }
}
weiter
alle Schnittstellen für neue events werden aus dieser Schnittstelle abgeleitet.
Die Schnittstelle selbst ist leer und dient als Markierung.
 
Eine eigene Schnittstelle legt die Aufrufkonvention für die auszulösenden Methoden fest, im einfachsten Fall reicht eine Methode.
 
Schema:
 
import java.util.EventListener;
 
public
interface MyOwnListener
  extends EventListener
{
  public
  void myOwnMethod(MyOwnEvent e);
}
weiter
merke
Diese Schnittstelle muss von Objekten implementiert werden, die auf die Ereignisse reagieren wollen.
weiter
auf Ereignisse reagieren
Das event listener interface muss implementiert werden.
 
Schema:
 
public
class MyView
  extends ...
  implements MyOwnListener
{
  ...
 
  public
  void myOwnMethod(MyOwnEvent e) {
    // Daten aus e anzeigen
    ...
  }
}
weiter
Ereignisse auslösen
Objekte, die Ereignisse auslösen wollen, müssen eine Liste von event listener verwalten
 
Schema
 
import java.util.Vector;
 
public
class AClass {
  // state variables
  ...
 
  private
  Vector stateChangedListeners;
 
  //--------------------
 
  public
  AClass() {
    // ...
    stateChangedListeners = new Vector();
  }
 
  //--------------------
 
  public
  void aMethod(...) {
    // change some state variables
    ...
 
    notifyStateChanged();
  }
 
  //--------------------
 
  protected
  void notifyStateChanged() {
    Vector l;
    MyOwnEvent e = new MyOwnEvent(this,...);
 
    synchronized (this) {
      l = (Vector)stateChangedListeners.clone();
    }
 
    for ( int i = 0;
          i < l.size();
          ++i ) {
      ((MyOwnListener)l.elementAt(i))
        .myOwnMethod(e);
    }
  }
 
  //--------------------
 
  public
  synchronized
  void addMyOwnListener(MyOwnListener l) {
    stateChangedListeners.addElement(l);
  }
 
  //--------------------
 
  public
  synchronized
  void removeMyOwnListener(MyOwnListener l) {
    stateChangedListeners.removeElement(l);
  }
}
weiter
Namenskonvention
xxxEvent
die Ereignisklasse
xxxListener
die Schnittstelle für die event Verteilung, Methodennamen beliebig
addXxxListener,
removeXxxListener
die Verwaltung der event listener

Letzte Änderung: 14.02.2012
© Prof. Dr. Uwe Schmidt
Prof. Dr. Uwe Schmidt FH Wedel