Observer-Pattern

Werbung
Observer-Pattern
(Java vs. .NET vs. Qt)
Seminar Software-Entwurf
Tim Rademacher
Gliederung
• Einführung in Design Patterns
• Das Observer-Pattern – Ein Beispiel
• Das Observer-Pattern in Java
– Das Interface Observer
– Die Klasse Observable
• Events beim Java AWT
• Delegates und Events in .NET
• Signale und Slots in Qt
Tim Rademacher: Observer-Pattern
2
Einführung in Design Patterns
Design Pattern sind
Beschreibungen von Lösungen für Software-Design Probleme
Design Pattern müssen
• den Kontext,
• das Problem
• und die Lösung darstellen.
Beschreibungen der Pattern in festgelegter Form
• Vergleichbarkeit
• Kategorisierbarkeit
Tim Rademacher: Observer-Pattern
3
Einführung in Design Patterns
Nutzen von Design Patterns
• Ein gemeinsames Design Vokabular
– einfache Möglichkeit zu Kommunikation und Dokumentation
• Eine Dokumentations- und Lernhilfe
– schnelles und leichtes Verständnis von Beschreibungen
– Design Patterns für allgemeine oft vorkommende Probleme
• Eine Erweiterung zu existierenden Methoden
– Design Patterns beinhalten Erfahrung von Design Experten
• Ein Ziel für Refactoring
– inflexible Software umorganisiert
Tim Rademacher: Observer-Pattern
4
Das Observer-Pattern – Ein Beispiel
Unsere aktuelle Situation:
Ein aktiver Erzähler
V
●
●
Vortragender
Beobachteter /
ist beobachtbar (engl. Observable)
macht keine Unterscheidung
zwischen den Zuhörern
●
hört auf, wenn keiner zuhört
Anzahl passiver Zuhörer
●
●
Zuhörer 1
Zuhörer 2
Zuhörer 3
Zuhörer x
●
Beobachter (engl. Observer)
interessiert an Informationen des
Erzählers
reagieren auf diese Informationen
Tim Rademacher: Observer-Pattern
5
Das Observer-Pattern in Java
Das Interface Observer
●
●
wird von Beobachtern
implementiert
enthält nur eine MethodenDeklaration
«interface»
Observer
+
update(Observable, Object) : void
Tim Rademacher: Observer-Pattern
6
Das Observer-Pattern in Java
Die Klasse Observable
Observable
●
●
-
changed: boolean = false
obs: Vector
+
+
+
+
+
+
#
#
+
+
Observable()
addObserver(Observer) : void
deleteObserver(Observer) : void
notifyObservers() : void
notifyObservers(Object) : void
deleteObservers() : void
setChanged() : void
clearChanged() : void
hasChanged() : boolean
countObservers() : int
●
●
●
Superklasse von Beobachteten
besitzt Methoden zum hinzufügen,
entfernen von Beobachtern
speichert seine Beobachter in
dem Vector obs
Die notifyObservers-Methoden
rufen die update-Methode der
Beobachter auf
teilt Änderung des Objektzustands nach außen hin mit
Tim Rademacher: Observer-Pattern
7
Das Observer-Pattern in Java
Übersicht und Anmerkung:
Observable
«interface»
Observer
-
changed: boolean = false
obs: Vector
+
+
+
+
+
+
#
#
+
+
Observable()
addObserver(Observer) : void
deleteObserver(Observer) : void
notifyObservers() : void
notifyObservers(Object) : void
deleteObservers() : void
setChanged() : void
clearChanged() : void
hasChanged() : boolean
countObservers() : int
+
update(Observable, Object) : void
Normalerweise enden die Namen von Interfaces
immer auf "able", hier jedoch umgekehrt!
Tim Rademacher: Observer-Pattern
8
Das Observer-Pattern in Java
Zurück zu unserem Beispiel, Erzähler:
Observable
-
changed: boolean = false
obs: Vector
+
+
+
+
+
+
#
#
+
+
Observable()
addObserver(Observer) : void
deleteObserver(Observer) : void
notifyObservers() : void
notifyObservers(Object) : void
deleteObservers() : void
setChanged() : void
clearChanged() : void
hasChanged() : boolean
countObservers() : int
public class Erzaehler extends java.util.Observable {
public void erzaehle(String information){
if(countObservers()>0){
setChanged();
notifyObservers(information);
}
}
}
Erzaehler
+
erzaehle(String) : void
Tim Rademacher: Observer-Pattern
9
Das Observer-Pattern in Java
Zu unserem Beispiel, Zuhörer:
public class Zuhoerer implements java.util.Observer {
«interface»
public Zuhoerer() {
}
Observer
+
update(Observable, Object) : void
public void update(java.util.Observable o,
Object information) {
if(isNeuigkeit(information)){
merken(information);
}
}
Zuhoerer
+
+
-
private void merken(Object information) {
//...
}
Zuhoerer()
update(Observable, Object) : void
merken(Object) : void
isNeuigkeit(Object) : boolean
private boolean isNeuigkeit(Object information) {
//...
}
}
Tim Rademacher: Observer-Pattern
10
Events beim Java AWT
• Benutzer interagiert mit Komponenten der grafischen
Oberfläche
• Events/Ereignisse werden gesendet
• Die Applikation reagiert auf die Events
• Ereignis-Klassen sind kategorisiert
• alle Events der grafischen Oberfläche sind eine Unterklasse
der abstrakten Klasse AWTEvent
Tim Rademacher: Observer-Pattern
11
Events beim Java AWT
java.awt.AWTEvent
java.io.Serializable
java.util.EventObject
~
serialVersionUID: long = 5516075349620653480L
source: Object
+
+
+
EventObject(Object)
getSource() : Object
toString() : String
#
#
~
~
+
+
+
+
+
+
+
+
+
+
+
+
~
+
+
+
+
+
+
+
+
-
bdata[]: byte
id: int
consumed: boolean = false
focusManagerIsDispatching: boolean = false
isPosted: boolean
COMPONENT_EVENT_MASK: long = 0x01
CONTAINER_EVENT_MASK: long = 0x02
FOCUS_EVENT_MASK: long = 0x04
KEY_EVENT_MASK: long = 0x08
MOUSE_EVENT_MASK: long = 0x10
MOUSE_MOTION_EVENT_MASK: long = 0x20
WINDOW_EVENT_MASK: long = 0x40
ACTION_EVENT_MASK: long = 0x80
ADJUSTMENT_EVENT_MASK: long = 0x100
ITEM_EVENT_MASK: long = 0x200
TEXT_EVENT_MASK: long = 0x400
INPUT_METHOD_EVENT_MASK: long = 0x800
INPUT_METHODS_ENABLED_MASK: long = 0x1000
PAINT_EVENT_MASK: long = 0x2000
INVOCATION_EVENT_MASK: long = 0x4000
HIERARCHY_EVENT_MASK: long = 0x8000
HIERARCHY_BOUNDS_EVENT_MASK: long = 0x10000
MOUSE_WHEEL_EVENT_MASK: long = 0x20000
WINDOW_STATE_EVENT_MASK: long = 0x40000
WINDOW_FOCUS_EVENT_MASK: long = 0x80000
RESERVED_ID_MAX: int = 1999
serialVersionUID: long
+
+
+
+
+
+
#
#
~
~
initIDs() : void
AWTEvent(Event)
AWTEvent(Object, int)
setSource(Object) : void
nativeSetSource(ComponentPeer) : void
getID() : int
toString() : String
paramString() : String
consume() : void
isConsumed() : boolean
convertToOld() : Event
copyPrivateDataInto(AWTEvent) : void
Tim Rademacher: Observer-Pattern
java.awt.event.ActionEvent
+
+
+
+
+
+
+
~
~
~
-
SHIFT_MASK: int = Event.SHIFT_MASK
CTRL_MASK: int = Event.CTRL_MASK
META_MASK: int = Event.META_MASK
ALT_MASK: int = Event.ALT_MASK
ACTION_FIRST: int = 1001
ACTION_LAST: int = 1001
ACTION_PERFORMED: int = ACTION_FIRST
actionCommand: String
when: long
modifiers: int
serialVersionUID: long
+
+
+
+
+
+
+
ActionEvent(Object, int, String)
ActionEvent(Object, int, String, int)
ActionEvent(Object, int, String, long, int)
getActionCommand() : String
getWhen() : long
getModifiers() : int
paramString() : String
12
Events beim Java AWT
InputEvent
• Zusammenfassung von ähnlichen
Ereignissen zu Gruppen
• Anzahl der Event-Klassen wird
klein gehalten
• Unterscheidung von Events
innerhalb einer Eventklasse durch
IDs
• Abfrage der ID über Methode
AWTEvent.getID()
MouseEvent
+
+
+
+
+
+
+
+
+
+
+
+
+
+
~
~
~
~
~
-
MOUSE_FIRST: int = 500
MOUSE_LAST: int = 507
MOUSE_CLICKED: int = MOUSE_FIRST
MOUSE_PRESSED: int = 1 + MOUSE_FIRST
MOUSE_RELEASED: int = 2 + MOUSE_FIRST
MOUSE_MOVED: int = 3 + MOUSE_FIRST
MOUSE_ENTERED: int = 4 + MOUSE_FIRST
MOUSE_EXITED: int = 5 + MOUSE_FIRST
MOUSE_DRAGGED: int = 6 + MOUSE_FIRST
MOUSE_WHEEL: int = 7 + MOUSE_FIRST
NOBUTTON: int = 0
BUTTON1: int = 1
BUTTON2: int = 2
BUTTON3: int = 3
x: int
y: int
clickCount: int
button: int
popupTrigger: boolean = false
serialVersionUID: long
+
+
+
+
+
+
+
+
+
+
+
-
initIDs() : void
MouseEvent(Component, int, long, int, int, int, int, boolean, int)
MouseEvent(Component, int, long, int, int, int, int, boolean)
getX() : int
getY() : int
getPoint() : Point
translatePoint(int, int) : void
getClickCount() : int
getButton() : int
isPopupTrigger() : boolean
getMouseModifiersText(int) : String
paramString() : String
setNew Modifiers() : void
setOldModifiers() : void
readObject(ObjectInputStream) : void
Tim Rademacher: Observer-Pattern
13
Events beim Java AWT
• Ereignisquellen (z.B. JButton)
können Events aussenden
• EventListener sind an den Events
interessiert
• EventListener meldet sich bei der
EventSource an
• Bei auftretenden Events Informiert
die EventSource alle registrierten
EventListener
• Es gibt für jedes Event eine eigene
Listener Klasse
«interface»
java.util.EventListener
«interface»
java.awt.event.ActionListener
+
actionPerformed(ActionEvent) : void
Tim Rademacher: Observer-Pattern
14
Das Observer-Pattern in .NET
.NET bietet eigene Programmkonstrukte zum Benutzen des
Observer-Pattern:
• Delegates und
• Events
• Delegates übermitteln Funktionszeiger von
Ereignis-Konsumenten zu -Produzenten
• Schnittstelle des Ereignisproduzenten in Form von Ereignissen
Tim Rademacher: Observer-Pattern
15
Das Observer-Pattern in .NET
//Deklaration eines Delegate-Typs
public delegate void ChangeEvent(object src, string s);
//Deklaration einer Delegate-Variablen
public event ChangeEvent onChangeEvent;
//Zuweisung einer passenden Methode an eine Delegate-Variable
onChangeEvent = new ChangeEvent(Hoere);
public void Hoere(object src, string information) {
...
}
//Aufruf von Hoere(einObj, "string");
onChangeEvent(einObj, "string");
• Delegate-Variable kann mehrere Delegate-Objekte aufnehmen
onChangeEvent += new ChangeEvent(OnChange0);
onChangeEvent += new ChangeEvent(OnChange1);
onChangeEvent -= new ChangeEvent(OnChange1);
Tim Rademacher: Observer-Pattern
16
Das Observer-Pattern in .NET
• Delegate-Felder als event deklariert, da
– Bessere Kapselung, nur die Klasse, die das Event
deklariert, kann es auslösen
– Zugriff von außen nur mit += oder -=
• Anmerkung, Konvention für Event-Handling Delegates:
– Kein Rückgabewert (void)
– 1. Parameter, Sender des Events, Typ object
– 2. Parameter, Event-Parameter, Subklasse von
System.EventArgs (wird im Beispiel nicht beachtet)
Tim Rademacher: Observer-Pattern
17
Das Observer-Pattern in .NET
public class Erzaehler {
//Delegate-Typ
public delegate void ChangeEvent(object src, string s);
//Delegate-Variablen
public event ChangeEvent onChangeEvent;
public void Erzaehle(string information){
if (onChangeEvent != null)
onChangeEvent(this, information);
}
...
Vortragender
}
public class Zuhoerer {
public Zuhoerer {
...
//Anmeldung beim Erzaehler
instanzErzaehler.onChangeEvent += new ChangeEvent(Hoere);
...
}
Zuhörer 1
Zuhörer 2
Zuhörer 3
Zuhörer x
public void Hoere(object src, string information) {
if(IsNeuigkeit(information)){
Merken(information);
}
}
...
}
Tim Rademacher: Observer-Pattern
18
Das Observer-Pattern in Qt
• Qt ist eine C++ Klassenbibliothek und ein GUI-Toolkit für Unixund X11-Systeme
• Signale und Slots
– Schlüsselwort signals: zur Deklaration der Signale, Signale müssen
nicht Implementiert werden
– Schlüsselwort slots: zur Deklaration der Slots
– aussenden von Signalen mit emit, z.B. emit highlighted(5);
– Verbinden von Signal mit einem Slot mit Hilfe der Methode
Qobject::connect
• zusätzlicher Preprozessor, 'Meta Object Compiler' (kurz moc)
extrahiert Informationen über Signale und Slots, erzeugt
Verbindungscode
Tim Rademacher: Observer-Pattern
19
Das Observer-Pattern in Qt
Beispiel:
//Erzähler
//Zuhörer
signals: erzaehleInformation(string s);
...
slots: empfangeInformation(string s);
...
public void erzaehle(string information){
emit erzaehleInformation(information);
}
public void empfangeInformation(string s){
if(isNeuigkeit(s)){
merken(s);
}
}
Qobject::connect(erzaehler, SIGNAL(erzaehleInformation(string)),
zuhoerer, SLOT(empfangeInformation(string)));
Tim Rademacher: Observer-Pattern
20
Events in Qt vs. Java vs. .NET
Java
Implementierung EventListener
und Events
Codelesbarkeit
+, da vertraut
Flexibilität
(-), wegen
Hierachie
.NET
Qt
Delegates und
Signale und
Events
Slots
-, da nicht vertraut +, da simpel
+, nur Konventionen+, nur Parameter
Einhalten
Beachten
Tim Rademacher: Observer-Pattern
21
Das Observer-Pattern
Danke für die Aufmerksamkeit!
Tim Rademacher: Observer-Pattern
22
Herunterladen