Sie sind auf Seite 1von 40

Design Pattern

für
Graphische Benutzeroberflächen
Das Observer Design Pattern
DesignPattern Observer Pattern

Jedes Observable kann einen oder mehrere Observer


haben. Sobald ein Observable seinen Zustand ändert,
wird mit notifyObservers die update-Methode
aller Oberserver aufgerufen.

Observable
Observable

Observer1
Observer1 Observer2
Observer2 Observer3
Observer3

update update update

4
DesignPattern Observable

addObserver(Observer)
registriert bei einem Observable einen neuen
Observer.

setChanged()
gibt an, dass sich der Datenteil des Observable
geändert hat.

notifyObservers()
ruft die update-Methode aller Observer auf, falls
sich der Datenteil inzwischen geändert hat.

5
DesignPattern Datenänderung im Observer Pattern

Observable Observer1 Observer2


notifyObservers()
update()
Observable
Object
getData()
redraw()

update()
Observable, Object
getData()
redraw()

6
DesignPattern Observable (Push-Variante)
import java.awt.*; import java.util.*;
class MyModel extends Observable implements Runnable
{
private int counter; private Thread thread;
MyModel() {
counter = 0; thread = new Thread(this);
thread.start();
}
public void run (){
while( true ) {
try { Thread.sleep( 500 ); }
catch( InterruptedException e ) { }
increaseCounter(); }
}
public void increaseCounter() {
counter = counter+1;
setChanged();
notifyObservers( new Integer(counter) );
}
}

7
DesignPattern Observer
import java.awt.*; import java.util.*;
import javax.swing.*;
public class MyObserver extends JFrame
implements Observer
{
private JLabel label;
MyObserver( )
{
label = new JLabel(" 0 ");
getContentPane().add( label );
}
public void update( Observable obs, Object arg )
{
label.setText( ((Integer) arg).toString() );
}
}

8
DesignPattern Main Klasse

class Main
{
public static void main( String argv[] )
{
MyModel mM = new MyModel();
MyObserver mO = new MyObserver();
mM.addObserver( mO );

mO.setSize(150,70);
mO.setVisible(true);
}
}

9
DesignPattern Observable/Observer: Pull-Variante
Im Observable
public void increaseCounter()
{
counter = counter+1;
setChanged();
notifyObservers();
}
public int getCounter()
{ return counter; }

Im Observer
public void update(Observable obs, Object arg )
{
MyModel m = (MyModel) obs;
label.setText(String.valueOf(m.getCounter()));
}

10
Das Model View Controller
Design Pattern
DesignPattern Model-View-Controller Design Pattern
Das MVC-Pattern teilt eine GUI-Applikation in drei
Teile:

Ausgabe
View
Benutzer
Benutzer Model
Model
Eingabe
Controller
Controller

Model Daten und ihre Verarbeitung


View Präsentation der Daten
Controller Benutzer-Eingaben

Entkoppelung der verschiedenen Teile der


Applikation mehr Flexibilität
12
DesignPattern MVC Design Pattern

ASD:
ASD: 9595
CJA:
CJA: 64
64
FBU:
FBU: 109
109
JPQ:
JPQ: 152
152
SGD:
SGD: 204
204

250

ASD 95 15%
200

CJA 64 10%
150

FBU 109 18%


100

JPQ 152 24%


50

SGD 204 33%


0

View 1: Pie Chart View 2: Bar Chart View 3: Spread Sheet

13
DesignPattern Class Responsibility Cards

Model
Model
View
• Stellt den funktionalen Teil der
Applikation zur Verfügung Controller
• Verwaltet die Daten
• Registiert die angemeleten Views
und Controller View
View
• Benachrichtigt die Views über
Datenänderungen • Stellt die nötigen Informa- Model
Model
tionen dar Controller
• Implementiert eine update() Controller
Prozedur
• Liest vom Model die neuen
Daten

Controller
Controller
• Akzeptiert User-Eingaben Model
Model
und sendet sie dem Model View
als Requests View
• Implementiert eine update()
Prozedur (falls nötig)

14
DesignPattern MVC mit Observable/Observer

Observable
Observable Observer
Observer
addObserver(obs)
addObserver(obs) update()
deleteObserver(obs) update() EventListener
deleteObserver(obs) EventListener
setChanged()
setChanged() eventHandler()
notifyObservers() eventHandler()
notifyObservers()
notifyObservers(arg)
notifyObservers(arg)

View
View
Model
Model
display()
display()
myData
myData Controller
Controller
getData()
getData() display()
setData() display()
setData()

MainClass
MainClass

15
DesignPattern Initialisierung des MVC

main Model
Observable
new View
Observer Controller
new
Observer
new
Model
addObserver()
View

addObserver()
Controller

16
DesignPattern Event Handling im MVC-Pattern

Controller Model View

Event setData()
setChanged()

notifyObservers()

update()
update()
getData()
repaint()
getData()

repaint()

17
DesignPattern Model:Observable

import java.util.*;

class MyModel extends Observable


{
private int counter;
MyModel()
{ counter = 0; }
public void increaseCounter()
{
counter = counter+1;
setChanged();
notifyObservers();
}
public int getCounter()
{ return counter; }
}

18
DesignPattern View: Observer
import java.awt.*; import javax.swing.*;
import java.util.*;
public class MyView extends JPanel
implements Observer
{
JLabel label;
MyView( )
{
// create new label
label = new JLabel( "0" );
add( label );
}
public void update( Observable ob, Object arg )
{
MyModel m = (MyModel) ob;
// read new value of counter
label.setText( "" + m.getCounter() );
repaint();
}
}
19
DesignPattern Controller: Observer und ActionListener
import java.awt.event.*; import java.awt.*;
import java.util.*; import javax.swing.*;
public class MyController extends JPanel
implements Observer, ActionListener
{
private JButton push;
private MyModel model;
MyController (MyModel m) {
model = m; push = new JButton("Add Value");
push.addActionListener( this );
add( push );
}
public void actionPerformed( ActionEvent e )
{ model.increaseCounter(); }
public void update(Observable ob, Object arg) {
if( model.getCounter() > 9 )
push.setEnabled(false);
}
} 20
DesignPattern MainFrame: Controller und View
import javax.swing.JFrame; import java.awt.*;
public class MainFrame extends JFrame {
MainFrame() {
Container c = getContentPane();
c.setLayout( new GridLayout(2, 1) );
MyModel model = new MyModel();
MyView mv = new MyView();
MyController mc = new MyController( model );
c.add( mc ); c.add( mv );
model.addObserver( mv );
model.addObserver( mc );
setSize(100,100);
}
static public void main( String args[] ){
(new MainFrame()).setVisible(true);
}
}
21
Das Command Processor
Design Pattern
DesignPattern Ergonomie

Jede Benutzeraktion ist entweder invertierbar oder


der Benutzer erhält eine entsprechende Warnung
Fehleingaben rückgängig machen.

24
DesignPattern Class Responsibility Cards

Command
Command
Command-
Command-
Kapselt
Kapselt eine
eine Befehlsauf-
Befehlsauf- Processor
Processor
forderung
forderung (mit
(mit Argumenten).
Argumenten).
Benutzt Supplier
Benutzt den
den Supplier,
Supplier, um
um die
die
Befehle (Model)
Befehle auszuführen.
auszuführen.

CommandProcessor
CommandProcessor
Aktiviert
Aktiviertdie
dieBefehlsausführung
Befehlsausführung
Verwaltet
Verwaltetdie
die(Liste
(Listeder)
der) Command
Command
Command-Objekte
Command-Objekte
Bietet
Bietetzusätzliche
zusätzlicheDienste
Dienstean
an
für
fürUndo/Redo,
Undo/Redo,...
...
25
DesignPattern Die Beziehung zwischen den Komponenten

CommandProcesssor
CommandProcesssor
commandList
commandList

submit(
submit( cmd
cmd ))
undo()
undo()
Command
Command
0..n
cmd_Arguments
cmd_Arguments

do_it(
do_it( cmd
cmd ))
creates *
undo_it()
undo_it()
Controller
Controller
//// some
some action-functions
action-functions

Supplier (Model)
Supplier (Model)
setData()
setData()
restore()
restore()

26
DesignPattern Message Sequence Chart für Requests
Controller Command Command Supplier
Processor (Model)
User
create()
Request
cmd_args
submit()
cmd do_it()
setData()
args

Undo
Request undo() undo_it() restore()
args

delete()

27
DesignPattern Beispiel: Drawing Application
Die Funktionsweise des CommandProcessor Pattern
betrachten wir anhand dieses kleinen Zeichungs-
programmes.

Damit die zuletzt gezeichnete Linie wieder gelöscht


werden kann, soll der Zeichnungsbefehl in einem
DrawingCommand Objekt gespeichert werden
28
DesignPattern Mouse Events -> Linie Zeichnen

public void mousePressed(MouseEvent e)


{
xCoor = e.getX();
yCoor = e.getY();
line = new Line( xCoor, yCoor,
xCoor, yCoor );
}

public void mouseReleased(MouseEvent e)


{
DrawingCommand dcmd = new
DrawingCommand(line, drawing);
cmdProc.submit(dcmd);
}

29
DesignPattern CommandProcessor...

public class CommandProcessor


{
// the list of commands
private LinkedList cmdList;
CommandProcessor( )
{
cmdList = new LinkedList();
}
boolean canUndo()
{
return (cmdList.size() > 0);
}
void submit( DrawingCommand cmd )
{
// append command to cmdList
cmdList.addLast( cmd );
cmd.do_it();
}

30
DesignPattern ...CommandProcessor

public void undo()


{
// test, whether there are undoable commands
if( canUndo() )
{
// remove last command from command list
DrawingCommand dcmd =
(DrawingCommand)cmdList.removeLast();
// undo command
dcmd.undo_it();
}
}
}

31
DesignPattern DrawingCommand
class DrawingCommand
{
private Line line;
private DrawModel drawing;
DrawingCommand ( Line l, DrawModel d )
{
drawing = d;
line = l;
}
public void do_it()
{
// add new line to drawing (model)
drawing.addLast(line);
}
public void undo_it()
{
// remove last line from drawing (model)
drawing.removeLast();
}
} 32
Der Swing UndoManager
javax.swing.undo
DesignPattern UndoManager
Das Anbieten von undo/redo wird in Swing mit Hilfe
des UndoManagers stark vereinfacht.

UndoableEditListener
UndoableEditListener

UndoManager
UndoManager
addEdit(UndoableEdit
addEdit(UndoableEdit):):boolean
boolean
undo():
undo():
redo():
redo():
canUndo():
canUndo(): boolean
boolean
canRedo(): boolean
canRedo(): boolean
discardAllEdits():
discardAllEdits():
getLimit():
getLimit(): int
int
setLimit(int);
setLimit(int);
getUndoPresentationName():
getUndoPresentationName(): String
String
getRedoPresentationName(): String
getRedoPresentationName(): String
undoableEditHappened(
undoableEditHappened(UndoableEditEvent
UndoableEditEvent) )
....
....
34
DesignPattern Die Methoden des UndoManager
Die wichtigsten Methoden des UndoManagers sind:
UndoManager() erzeugt einen (leeren) UndoManager.
addEdit() fügt den neuen Befehl in die undo-Liste ein.
undo() invertiert (falls möglich) den letzten Befehl.
redo() führt (falls möglich) vom zuletzt invertierten
Befehl ein redo aus.
canUndo() gibt true zurück, falls ein undo möglich ist.
canRedo() gibt true zurück, falls ein redo möglich ist.

getLimit() setzt/liest die Anzahl Befehle, welche im


setLimit() UndoManager maximal gespeichert werden.

undoableEditHappened() wird von der EventSource


aufgerufen, bei welcher der UndoManager (als Event-
Listener) registriert ist.

35
DesignPattern Die Document Klasse
Zu jeder Swing Text-Komponente gehört ein
Document Objekt, welches den Model-Teil des
MVC-Patterns übernimmt.
Das Document speichert sowohl den Text, also auch
die benutzten Styles (Fonts, Farbe, ...).

Jede Änderung im Document erzeugt ein Undoable-


EditEvent. Ein UndoManager, welcher beim
Document als EventListener registriert ist, erhält
Nachricht über sämtliche (invertierbaren)
Änderungen im Document.

36
DesignPattern Undo/Redo

Document UndoableEditListener
UndoableEditListener
Document

addUndoableEditListener

UndoManager
JTextComponent
JTextComponent undoableEditHappened
undoableEditHappened

UndoManager undoMan = new UndoManager();


Document doc = textComponent.getDocument();
doc.addUndoableEditListener(undoMan);

37
DesignPattern Undo/Redo

undoMenuItem
undoMenuItem ActionListener
ActionListener

addActionListener MyUndoAction
MyUndoAction
actionPerformed()
actionPerformed()

class MyUndoAction implements ActionListener


{
public void actionPerformed(ActionEvent event)
{
// undo last undoable edit
undoMan.undo();
}
}
38
DesignPattern Message Sequence Chart

Undo
Document UndoableEdit
Manager
Event
User
create()
Request
UndoableEdit
(Edit)
undoableEditHappened()
getEdit()
editEvent

addEdit()

39
DesignPattern Message Sequence Chart: Undo

Action
Listener
UndoMenuItem Undo
Manager Undoable
Undo Edit Document
action-
Request Performed()
undo() getEdit()

undo()
restore() notify()

40
DesignPattern Literatur

Oktober 1995

Addison Wesley
Publishing Company;

ISBN: 0201633612

41
DesignPattern Literatur

August 1996

John Wiley & Sons;

ISBN: 0471958697

42