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 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 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 4
Das Observer-Pattern Ein Beispiel Unsere aktuelle Situation: V Vortragender Zuhörer 1 Zuhörer x Zuhörer 2 Zuhörer 3 Ein aktiver Erzähler Beobachteter / ist beobachtbar (engl. Observable) macht keine Unterscheidung zwischen den Zuhörern hört auf, wenn keiner zuhört Anzahl passiver Zuhörer Beobachter (engl. Observer) interessiert an Informationen des Erzählers reagieren auf diese Informationen 5
Das Observer-Pattern in Java Das Interface Observer wird von Beobachtern implementiert enthält nur eine Methoden- Deklaration «interface» Observer + update(observable, Object) : void 6
Das Observer-Pattern in Java 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 Die Klasse Observable 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 7
Das Observer-Pattern in Java Übersicht und Anmerkung: Observable - changed: boolean = false - obs: Vector «interface» Observer + update(observable, Object) : void + Observable() + addobserver(observer) : void + deleteobserver(observer) : void + notifyobservers() : void + notifyobservers(object) : void + deleteobservers() : void # setchanged() : void # clearchanged() : void + haschanged() : boolean + countobservers() : int Normalerweise enden die Namen von Interfaces immer auf "able", hier jedoch umgekehrt! 8
Das Observer-Pattern in Java Zurück zu unserem Beispiel, Erzähler: Observable public class Erzaehler extends java.util.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 void erzaehle(string information){ if(countobservers()>0){ setchanged(); notifyobservers(information); Erzaehler + erzaehle(string) : void 9
Das Observer-Pattern in Java Zu unserem Beispiel, Zuhörer: public class Zuhoerer implements java.util.observer { «interface» Observer + update(observable, Object) : void Zuhoerer + Zuhoerer() + update(observable, Object) : void - merken(object) : void - isneuigkeit(object) : boolean public Zuhoerer() { public void update(java.util.observable o, Object information) { if(isneuigkeit(information)){ merken(information); private void merken(object information) { //... private boolean isneuigkeit(object information) { //... 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 11
Events beim Java AWT java.util.eventobject java.io.serializable - serialversionuid: long = 5516075349620653480L ~ source: Object + EventObject(Object) + getsource() : Object + tostring() : String java.awt.awtevent - 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 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 - 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 12
Events beim Java AWT 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 InputEvent 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 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 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); 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) 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);... public class Zuhoerer { public Zuhoerer {... //Anmeldung beim Erzaehler instanzerzaehler.onchangeevent += new ChangeEvent(Hoere);... Zuhörer 1 Vortragender Zuhörer 2 Zuhörer 3 Zuhörer x public void Hoere(object src, string information) { if(isneuigkeit(information)){ Merken(information);... 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 19
Das Observer-Pattern in Qt Beispiel: //Erzähler signals: erzaehleinformation(string s);... public void erzaehle(string information){ emit erzaehleinformation(information); //Zuhörer slots: empfangeinformation(string s);... public void empfangeinformation(string s){ if(isneuigkeit(s)){ merken(s); Qobject::connect(erzaehler, SIGNAL(erzaehleInformation(string)), zuhoerer, SLOT(empfangeInformation(string))); 20
Events in Qt vs. Java vs..net Java.NET Qt Implementierung EventListener Delegates und Signale und und Events Events Slots Codelesbarkeit +, da vertraut -, da nicht vertraut +, da simpel Flexibilität (-), wegen +, nur Konventionen+, nur Parameter Hierachie Einhalten Beachten 21
Das Observer-Pattern Danke für die Aufmerksamkeit! 22