
OBSERVER PATTERN Das Observer Pattern gehört zu den Behavioural Patterns. Es dient zur Weitergabe von Änderungen an einem Objekt an davon abhängige Strukturen. Das Pattern besteht aus einem Publisher und einem oder mehreren Subscribern (Observern). Der Publisher besitzt eine Liste von Subscribern die sein Event abonniert haben. Durch das attach Feature des Publishers wird ein Subscriber in die Liste eingefügt. Mit detach wird ein Subscriber entfernt. Jedes Mal wenn ein Event eintritt geht der Publisher durch seine Subscriberliste und ruft auf jedem Subscriber "update" auf. Beispiel: Problemstellung: Auf Druck der Taste "p" soll das Programm "Demo" pausieren. Der Publisher "pub" erkennt dass "p" gedrückt wird, daraufhin geht er durch die Subscriberliste und ruft auf jedem Element "update" auf. "Demo" erbt von Subscriber und hat sich zuvor über "subscribe" / pub.attach in die Liste des Publishers eingetragen. Daher wird demo.update aufgerufen und "Demo" kann sich selber pausieren. Der Sinn von Subscriber.subscribe(...) ist uns nicht ganz klar, da dieses Feature nichts anderes macht als p.attach(...) aufzurufen. VISITOR PATTERN Problem: Assignment Attempts, um typabhängig eine bestimmte Funktion aufzurufen (Dynamic Binding). Solution: Visitor Pattern. Trennung von Daten- und Funktionsklassen. Datenklassen erben von VISITABLE, Funktionen von VISITOR. Visitor vs dynamic binding: Dynamic binding: + Typen hinzufügen einfach - Operationen hinzufügen schwierig - Verwandte Operationen werden getrennt (repair_binding in BOOK, repair_cover in DVD) Visitor: - Typen hinzufügen schwierig + Operationen hinzufügen einfach + Keine assignment attempts (besser für type checking) + Verwandte Operation bleiben in einer Klasse, nicht verwandte werden getrennt Example: Before: /maintain (b : BORROWABLE) is -- Perform maintenance on b. require exists: b /= Void local book : BOOK dvd : DVD do book ?= b if book /= Void then if book.binding_damaged then book.repair_binding end end dvd ?= b if dvd /= Void then if dvd.cover_damaged then dvd.repair_cover end end end end/ Analog für andere Operationen, z.B. display(b: BORROWABLE)... After: BOOK und DVD erben von VISITABLE und implementieren dessen deffered Feature accept* /class BOOK inherit BORROWABLE VISITABLE feature accept (v : VISITOR) is -- Apply to v the book -- visit mechanism. do v.visit_book (Current)??? end end/ Analog für DVD MAINTAINANCE_VISITOR erbt von VISITOR und implementiert dessen deffered Features visit_book*, visit_dvd*,... /class MAINTENANCE_VISITOR inherit VISITOR feature -- Basic operations visit_book (book: BOOK) is -- Perform maintenance operations on b. do if book.binding_damaged then book.repair_binding end end visit_dvd (dvd: DVD) is -- Perform maintenance operations on d. do if dvd.cover_damaged then dvd.repair_cover end end end / STRATEGY PATTERN Klassen Diagramm: Beschreibung: Die ConcreteStrategyA und ConcreteStrategyB Klassen sind von der Selben Algorithmen Familie. Sie berechnen ähnliche Probleme. Die Klasse Strategie definiert das Problem abstrakt, also ohne konkrete Implementierung Die Klasse Context benutzt die konkreten Klassen über STRATEGY via dynamic binding als Client zur Berechnung des Algorithmus. Meist wird die konkrete Strategie von aussen (ROOT_CLASS) dem CONTEXT zugewiesen. Beispiel Schachspiel: CONTEXT: der Spieler STRATEGY : seine Spielstrategie CONCRETE_STRATEGY_A: So schnell wie möglich die Dame schnappen CONCRETE_STRATEGY_B: So gut wie möglich den König verteidigen Vorteile Vermeidung von unübersichtlichen if-statements Erweiterbarkeit mit neuen Strategien ist einfacher (Keine Neuimplementierung von CONTEXT). Freie Wahl von verschiedenen Implementierungen Nachteile Viel mehr Objekte, viel mehr Klassen. Viel mehr Kommunikation zwischen den Objekten. Der Benutzer (ROOT_CLASS) muss die verschiedenen Strategien kennen. STATE PATTERN Das State Pattern ist dann nützlich, wenn man ein Programm hat, welches zwischen verschiedenen Zuständen wechselt (quasi eine finite state machine) und in jedem State jeweils ähliche aber nicht gleiche Funktionalitäten bieten soll. Es wird eine deferred Klasse STATE geschrieben, wo die gewünschten features ohne Implementation definiert sind. Die effektiven States erben dann davon und werden jeweils aktiv wenn sich das Programm in diesem State befindet. Durch dieses Pattern wird der Code übersichtlicher und erweiterbar: Es gibt keine grossen select Blöcke und man kann neue States einfach direkt als neue Klasse schreiben. Ein ausführliches Beispiel zum State Pattern findet ihr im ersten Foliensatz dieses Semesters (beim letzten, "guten" Ansatz für das Flugreservationsprogramm)! Es wird dort zwar nirgends gesagt, dass es sich um das State Pattern handelt, aber genau das ist der Fall. CHAIN OF RESPONSIBILITY PATTERN Ein Sender eines Requests für die Bearbeitung eines Jobs hat mehrere Objekte in einer Kette zur Verfügung, welche diesen Job bearbeiten können. • Falls ein Objekt den Job nicht bearbeiten kann, reicht er ihn weiter an das nächste Objekt in der Kette. • Falls das Objekt den Job bearbeiten kann, wird dies gemacht und dem Sender des Requests gemeldet. Chain of responsibility request PE PE PE PE PE PE Pe: Processing element/Handler • Architektur: next handle can_handle* APPLICATION HANDLER [G]* do_handle* handled set_next FIRST_HANDLER [G]+ SECOND_HANDLER can_handle+ [G]+ do_handle+ can_handle+ do_handle+ handle (r: G) is do if can_handle (r) then do_handle (r); handled := True; elseif next /= Void then next.handle (r); handled := next.handled; else handled := False end end Real World Example Firma hat Präsident, Vice-Präsident und Direktor. Chain: Direktor Æ Vice-Präsident Æ Präsident Æ VR • Falls jetzt ein Auftrag in der Höhe < 25000 Fr. kommt, bearbeitet das der Direktor. • Falls Auftrag < 50000 Fr. wird das vom Vize-Präsident entschieden. • Falls Auftrag < 100000 Fr. übernimmt das der Präsident, weil es bereits eine grosse Summe ist. • Falls Auftrag >= 100000 Fr. muss der gesamte Verwaltungsrat in einer Sitzung entscheiden, weil das eine so riesige Summe ist. COMMAND PATTERN Ziel Implementation von Undo/Redo Mechanismen (Ctrl Z / Ctrl Y). Realisierung Jeder umkehrbare („undoable“) Command wird als eigene Klasse implementiert. Diese Klasse erbt von einer Master-Command-Klasse. Sie muss die deferred features implementieren/enthalten. Die History ist eine FIFO Liste welche sämtliche Commands speichert. Masterklasse deferred class COMMAND feature done: BOOLEAN is -- Has this command been executed? execute is -- Carry out one execution of this command. deferred ensure already: done end undo is -- Cancel an earlier execution of this command. require already: done deferred end redo is -- Restores an earlier execution of this command. require not_already: not done deferred end end Ausführen eines Benutzerbefehls User Request decodieren Fall 1: Normaler Befehl – Command-Object wird erstellt und ausgeführt – in der History werden sämtliche Elemente gelöscht, welche das done-Flag nicht gesetzt haben (alle rechts der aktuellen Cursor-Position). Fall 2: Undo – Sofern an der aktuellen Cursor-Position ein Command existiert, wird dessen Undo Feature aufgerufen und die Cursor-Position um eins nach hinten verschoben. Fall 3: Redo – Sofern an der aktuellen Cursor-Position ein Command existiert, wird dessen Redo Feature aufgerufen und die Cursor-Position um eins nach vorne verschoben. Alternative Implementation Zu jedem Command wird eine Undo- und eine Redofunktion implementiert. Anstatt in der History den Comand zu speichern wird ein Tupel mit den Agents zu Undo und Redo erstellt. Nun werden nicht mehr Execute/Redo und Undo, sondern die entsprechenden Agents aufgerufen. ABSTRACT FACTORY PATTERN Problem Unterschiedliche Objekte vom gleichen Typ abhängig von (evt. „äusseren“) Bedingungen nötig. Klassisches Beispiel: Verschiedenen Buttons, Fenster etc. nötig, je nach Betriebssystem. Lösung Durch Abstract Factory: Eine Abstract Factory liefert ein Interface zur Erstellung von Objekten, ohne dass man deren dynamischen Typ kennen muss. Klassendiagramm: Klassenbeschreibungen: Factory: Deferred Class. Stellt ein generelles Interface für die Erstellung von Produkten dar. Listet die einzelnen Produkte als deferred Features: new_produkt_a (args): PRODUCT_A is deferred end new_produkt_b: PRODUCT_B is deferred end … PRODUCT_A und PRODUCT_B sind selbst ebenfalls deferred. Factory_1 / Factory_2: Erben von Factory und liefern unterschiedliche Implementationen der Instanzierung der einzelnen Produkte. new_produkt_a (args): PRODUCT_A is do create {PRODUCT_A1} Result.make (args) end oder: new_produkt_a (args): PRODUCT_A1 is do create Result.make (args) end Factory Objekt erstellen, Variante 1: feature -- Access factory: FACTORY feature --Something initialize is -- factory initialization do if some_condition then create {FACTORY_1} factory else create {FACTORY_2} factory end end Factory Objekt erstellen, Variante 2 mit Singleton (empfohlen) feature – Singleton factory: FACTORY is -- factory singleton once if some_condition then create {FACTORY_1} Result else create {FACTORY_2} Result end end Factory call my_product := factory.new_product_a SINGLETON PATTERN (Creational) Source: Gamma et al. (1994); also known as „Gang of Four“ (GoF); pages 127ff: Intent „Ensure a class only has one instance, and [to] provide a global point of access to it.“ Motivation and Applications Printer spooler, window manager, accounting system, calendar application, ... all applications that include some components that should only be created once, but will be used throughout the
Details
-
File Typepdf
-
Upload Time-
-
Content LanguagesEnglish
-
Upload UserAnonymous/Not logged-in
-
File Pages11 Page
-
File Size-