Vorlesung „Softwaretechnologie“ Wintersemester 2010 ROOTS Kapitel 7 Entwurfsmuster (“Design Patterns”) Stand: 6.12.2010 30.11.2010: Ergänzt um „Dynamic Proxy Classes“ in Java 06.12.2010: Ergänzt um Hinweisfolie auf Entwurfsmusterbeschreibungen in weiteren Kapiteln Einführung: Die Grundidee von Pattern Grundlegende Idee Alle Ingenieurdisziplinen benötigen eine Terminologie ihrer wesentlichen Konzepte sowie eine Sprache, die diese Konzepte in Beziehung setzt. Pattern (Muster) wurden zuerst im Bereich der Architektur beschrieben. Ziele von Pattern in der Welt der Software: Dokumentation von Lösungen wiederkehrender Probleme, um Programmierer bei der Softwareentwicklung zu unterstützen. Schaffung einer gemeinsamen Sprache, um über Probleme und ihre Lösungen zu sprechen. Bereitstellung eines standardisierten Katalogisierungsschemas um erfolgreiche Lösungen aufzuzeichnen. Bei Pattern handelt es sich weniger um eine Technologie (wie z.B. bei UML), als um eine Kultur der Dokumentation und Unterstützung guter Softwarearchitektur. © 2000-2010 Dr. G. Kniesel Vorlesung „Softwaretechnologie“ (SWT) Seite 7-2 ROOTS Einführung: Literatur zu Pattern und Software Erich Gamma, Richard Helm, Ralph Johnson, John Vlissides (Gang of Four): "Design Patterns - Elements of Reusable Object-Oriented Software" Addison-Wesley, 1995 Frank Buschmann, Regine Meunier, Hans Rohnert, Peter Sommerlad, Michael Stal (Gang of Five): "Pattern-Oriented Software Architecture - A System of Patterns" John Wiley & Sons, 1996 Serge Demeyer, Stephane Ducasse, Oscar Nierstrasz: "Object Oriented Reengineering Patterns", Morgan Kaufman, 2002 Patterns im WWW Portland Pattern Repository: http://c2.com/ppr/ Hillside Group Patterns Library: http://www.hillside.net/patterns/ Brad Appleton: „Patterns and Software: Essential Concepts and Terminology“ http://www.bradapp.net/docs/patterns-intro.html Doug Lea, Patterns-Discussion FAQ, http://gee.oswego.edu/dl/pd-FAQ/pd-FAQ.html Buchliste: http://c2.com/cgi/wiki?PatternRelatedBookList © 2000-2010 Dr. G. Kniesel Vorlesung „Softwaretechnologie“ (SWT) Seite 7-3 ROOTS Einführung: Das MVC-Framework in Smalltalk als Beispiel a = 50% b = 30% c = 20% 2. Änderungen am Modell werden propagiert - Model - X 1. Views melden sich an View + Controller © 2000-2010 Dr. G. Kniesel X a = 50% b = 30% c = 20% View + Controller Vorlesung „Softwaretechnologie“ (SWT) Seite 7-4 ROOTS Einführung: Das MVC-Framework in Smalltalk als Beispiel Model a = 50% b = 30% c = 20% - X - X - X a = 50% b = 30% c = 20% View + Controller View + Controller Neue Views können ohne Änderung des Modells oder der anderen Views hinzugefügt werden © 2000-2010 Dr. G. Kniesel Vorlesung „Softwaretechnologie“ (SWT) Seite 7-5 ROOTS Einführung: Das MVC-Framework in Smalltalk als Beispiel a = 50% b = 30% c = 20% Propagierung von Änderungen: Observer Pattern Kommt z.B. auch bei Client/Server-Programmierung zur Benachrichtigung der Clients zum Einsatz X - Geschachtelte Views: Composite Pattern - View enthält weitere Views, wird aber wie ein einziger View behandelt. Kommt z.B. auch bei Parsebäumen im Compilerbau zum Einsatz (Ausdrücke). X Reaktion auf Events im Controller: Strategy Pattern Eingabedaten können validiert werden (Daten, Zahlen, etc.). Controller können zur Laufzeit gewechselt werden. Kommt z.B. auch bei der Codeerzeugung im Compilerbau zum Einsatz (Code für verschiedene CPUs). © 2000-2010 Dr. G. Kniesel Vorlesung „Softwaretechnologie“ (SWT) Seite 7-6 - X ROOTS Überblick 1. Einführung 2. Einstiegsbeispiel: "Observer" im Detail 3. Was also sind Patterns? 4. Wichtige Patterns 5. Zusammenspiel verschiedener Patterns 6. Fazit: Nutzen von Patterns 7. Zusammenfassung und Ausblick © 2000-2010 Dr. G. Kniesel Vorlesung „Softwaretechnologie“ (SWT) Seite 7-7 ROOTS Kapitel 6: Entwurfsmuster Das Observer Pattern ROOTS Das Observer Pattern: Einführung Absicht Stellt eine 1-zu-n Beziehung zwischen Objekten her Wenn das eine Objekt seinen Zustand ändert, werden die davon abhängigen Objekte benachrichtigt und entsprechend aktualisiert Andere Namen "Dependents", "Publish-Subscribe", "Listener" Motivation Verschiedene Objekte sollen zueinander konsistent gehalten werden Andererseits sollen sie dennoch nicht eng miteinander gekoppelt sein. (bessere Wiederverwendbarkeit) Diese Ziele stehen in einem gewissen Konflikt zueinander. Man spricht von „conflicting forces“, also gegenläufig wirkenden Kräften. © 2000-2010 Dr. G. Kniesel Vorlesung „Softwaretechnologie“ (SWT) Seite 7-10 ROOTS Das Observer Pattern: Beispiel Trennung von Daten und Darstellung Wenn in einer Sicht Änderungen vorgenommen werden, werden alle anderen Sichten aktualisiert – Sichten sind aber unabhängig voneinander. a = 50% b = 30% c = 20% - X - X - X a = 50% b = 30% c = 20% © 2000-2010 Dr. G. Kniesel Vorlesung „Softwaretechnologie“ (SWT) Seite 7-11 ROOTS Das Observer Pattern: Anwendbarkeit Das Pattern ist im folgenden Kontext anwendbar: a = 50% b = 30% c = 20% - Abhängigkeiten - - a = 50% b = 30% c = 20% Ein Aspekt einer Abstraktion ist abhängig von einem anderen Aspekt. Aufteilung dieser Aspekte in verschiedene Objekte erhöht Variationsmöglichkeit und Wiederverwendbarkeit. Folgeänderungen Änderungen an einem Objekt erfordert Änderungen an anderen Objekten. Es ist nicht bekannt, wie viele Objekte geändert werden müssen. Lose Kopplung Objekte sollen andere Objekte benachrichtigen können, ohne Annahmen über die Beschaffenheit dieser Objekte machen zu müssen. © 2000-2010 Dr. G. Kniesel Vorlesung „Softwaretechnologie“ (SWT) Seite 7-12 ROOTS Das Observer Pattern: Struktur (N:1, Pull-Modell) 1 * <<interface>> Observer subject observers {abstract} Subject observers.add(o) update() :void attach(o:Observer):void detach(o:Observer):void notify() : void observers.remove(o) for all o in observers { o.update(); } ConcreteObserver ConcreteSubject {redefines subject} subjectState:State 1 return subjectState; update() :void … subject.getState(); … subjectState = s; notify() getState() : State setState(State s): void Rollenaufteilung / Verantwortlichkeiten (Pull Modell) Observer („Beobachter“) -- auch: Subscriber, Listener update() -- auch: handleEvent Reaktion auf Zustandsänderung des Subjects Subject („Subjekt“) -- auch: Publisher attach(Observer o) -- auch: register, addListener Observer registrieren detach(Observer o) -- auch: unregister, removeListener registrierte Observer entfernen notify() update-Methoden aller registrierten Observer aufrufen setState(…) zustandsändernde Operation(en) für internen Gebrauch und beliebige Clients getState() abfrage des aktuellen Zustands damit Observer feststellen können was sich wie geändert hat © 2000-2010 Dr. G. Kniesel Vorlesung „Softwaretechnologie“ (SWT) Seite 7-14 ROOTS Das Observer Patterns: Implementierung Wie werden die Informationen über eine Änderung weitergegeben: „push“ versus „pull“ Pull: Subjekt übergibt in „update()“ keinerlei Informationen, aber die Beobachter müssen sich die Informationen vom Subjekt holen + Geringere Kopplung zwischen Subjekt und Beobachter. – Berechnungen werden häufiger durchgeführt. Push: Subjekt übergibt in Parametern von „update()“ detaillierte Informationen über Änderungen. + Rückaufrufe werden seltener durchgeführt. – Beobachter sind weniger wiederverwendbar (Abhängig von den Parametertypen) Zwischenformen sind möglich © 2000-2010 Dr. G. Kniesel Vorlesung „Softwaretechnologie“ (SWT) Seite 7-15 ROOTS Das Observer Pattern: Struktur (N:1, Push-Modell) <<interface>> Observer 1 * subject observers {abstract} Subject observers.add(o) update(StateA) :void observers.remove(o) ConcreteObserver attach(o:Observer):void detach(o:Observer):void notify() : void ConcreteSubject subjectStateA:StateA subjectStateB:StateB update(StateA) :void for all o in observers { o.update(subjectStateA); } notify() : void setState(State s): void Das Observer Pattern: Implementierung Vermeidung irrelevanter Notifikationen durch Differenzierung von Ereignissen Bisher: Notifikation bei jeder Änderung Alternative: Beobachter-Registrierung und Notifikation nur für spezielle Ereignisse Realisierung: Differenzierung von attach(), detach(), update() und notify() in jeweils ereignisspezifische Varianten Vorteile: Notifikation nur für relevante Ereignisse höhere Effizienz Weniger „Rückfragen“ pro Ereignis höhere Effizienz Nachteil: Mehr Programmieraufwand, wenn man sich für viele Ereignistypen interessiert Aber: Werkzeugunterstützung möglich © 2000-2010 Dr. G. Kniesel Vorlesung „Softwaretechnologie“ (SWT) Seite 7-19 ROOTS Das Observer Patterns: Implementierung ChangeManager Verwaltet Beziehungen zwischen Subjekt und Beobachter. (Speicherung in Subjekt und Beobachter kann entfallen.) Definiert die Aktualisierungsstrategie Benachrichtigt alle Beobachter. Verzögerte Benachrichtigung möglich Insbesondere wenn mehrere Subjekte verändert werden müssen, bevor die Aktualisierungen der Beobachter Sinn macht Wer ruft notify() auf? a) "setState()"-Methode des Subjekts: + Klienten können Aufruf von "notify()" nicht vergessen. – Aufeinanderfolgende Aufrufe von "setState()" führen zu evtl. überflüssigen Aktualisierungen. b) Klienten: + Mehrere Änderungen können akkumuliert werden. – Klienten vergessen möglicherweise Aufruf von "notify()". © 2000-2010 Dr. G. Kniesel Vorlesung „Softwaretechnologie“ (SWT) Seite 7-20 ROOTS Das Observer Pattern: Implementierung Konsistenz-Problem Zustand eines Subjekts muss vor Aufruf von "notify()" konsistent sein. Vorsicht bei Vererbung bei Aufruf jeglicher geerbter Methoden die möglicherweise „notify()“ -aufrufen : public class MySubject extends SubjectSuperclass { public void doSomething(State newState) { super.doSomething(newState); // ruft "notify()" auf this.modifyMyState(newState); // zu spät! } } Lösung Dokumentation von „notify()“-Aufrufen erforderlich (Schnittstelle!) Besser: In Oberklasse „Template-Method Pattern“ anwenden um sicherzustellen, dass „notify()“-Aufrufe immer am Schluss einer Methode stattfinden s. nächste Folie. © 2000-2010 Dr. G. Kniesel Vorlesung „Softwaretechnologie“ (SWT) Seite 7-21 ROOTS Das Observer Pattern: Implementierung Verwendung des „Template Method Pattern“ Template Method public class SubjectSuperclass { ... final public void doSomething(State newState) { this.doItReally(newState); this.notify(); // notify immer am Schluß } public void doItReally(State newState) { } } Hook Method public class MySubject extends SubjectSuperclass { public void doItReally(State newState) { this.modifyMyState(newState); } } © 2000-2010 Dr. G. Kniesel Vorlesung „Softwaretechnologie“ (SWT) Seite 7-22 ROOTS Kapitel 6: Entwurfsmuster Konsequenzen von Observer für Abhängigkeiten Für Abhängigkeitsreduzierung allgemein Für Presentation-Application-Data (PAD) Für Boundary-Controller-Entity (BCE) Für Model-View-Kontroller (MVC) PAD versus BCE versus MVC ROOTS Abhängigkeiten mit und ohne Observer Ohne Observer: Abhängigkeit View Model Ein konkretes Model kennt das Interface eines jeden konkreten View und steuert was genau jeder der Views nach einem update tun soll: myGraphView1.setGraph(this.toPieChart()); myGraphView1.draw(); myGraphView2.setGraph(this.toBarChart()); myGraphView2.draw(); … myTextViewN.print(myState.toString()); :TextViewN GraphView1 GraphView… GraphViewJ setGraph(BarChart p) draw() TextView1 TextView… print() TextViewN print() print() … :GraphView1 :Model setState(…) Model update() setState(…) update() toPieChart() toBarChart() toString() pie=toPieChart() setGraph(pie) draw() s = toString() print(s) Abhängigkeiten mit und ohne Observer Mit Observer: Abhängigkeit View Model Ein konkretes Model kennt nur das abstrakte Observer-Interface Ein konkreter View kennt die zustandsabfragenden Methoden des konkreten Models model.getState1(); model.getState2(); <<interface>> Observer 1 * observers Subject subject :Model :View attach(this) attach(o:Observer) detach(o:Observer) notify() update() :void setState() for all o in observers { o.update(); } notify() update() View Model {redefines subject} 1 update() :void subject.getState(); … subjectState:State getState() : State setState(State s) getState() Nettoeffekt: Abhängigkeits- und Kontrollumkehrung Abhängigkeitsumkehrung („Dependency Inversion“) Kontrollumkehrung („Inversion of Control“) Ohne Observer Ohne Observer Abhängigkeit Model Views Mit Observer Model steuert alle updates Mit Observer Abhängigkeit Model Views Jeder View steuert sein update Vergleich Ablauf ohne / mit Observer :TextViewN … :GraphView1 :Model :Model :View setState(…) attach(this) setState() update() pie=toPieChart() setGraph(pie) notify() update() draw() getState() s = toString() print(s) Das Observer Pattern: Konsequenzen Unabhängigkeit Konkrete Beobachter können hinzugefügt werden, ohne konkrete Subjekte oder andere konkrete Beobachter zu ändern. Konkrete Subjekte können unabhängig voneinander und von konkreten Beobachtern variiert werden. Konkrete Subjekte können unabhängig voneinander und von konkreten Beobachtern wiederverwendet werden. „Broadcast“-Nachrichten Subjekt benachrichtigt alle angemeldeten Beobachter Beobachter entscheiden, ob sie Nachrichten behandeln oder ignorieren Unerwartete Aktualisierungen Kleine Zustandsänderungen des Subjekts können komplexe Folgen haben. Auch uninteressante Zwischenzustände können unnötige Aktualisierungen auslösen. © 2000-2010 Dr. G. Kniesel Vorlesung „Softwaretechnologie“ (SWT) Seite 7-27 ROOTS Das Observer Pattern: Bekannte Anwendungen Bekannte Anwendungen Model-View-Controller-Framework in Smalltalk Java Foundation Classes / Swing Oberon System Diverse Client/Server-Modelle, z.B. Java RMI © 2000-2010 Dr. G. Kniesel Vorlesung „Softwaretechnologie“ (SWT) Seite 7-28 ROOTS Kapitel 6: Entwurfsmuster Was also sind Patterns? ROOTS Bestandteile einer Pattern-Beschreibung Name(n) des Patterns Problem, das vom Pattern gelöst wird Anforderungen, die das Pattern beeinflussen Kontext, in dem das Pattern angewendet werden kann Lösung. Beschreibung, wie das gewünschte Ergebnis erzielt wird Varianten der Lösung Beispiele der Anwendung der Lösung Konsequenzen aus der Anwendung des Patterns Bezug zu anderen Patterns Bekannte Verwendungen des Patterns © 2000-2010 Dr. G. Kniesel Vorlesung „Softwaretechnologie“ (SWT) Seite 7-35 ROOTS Bestandteile eines Patterns: Kontext, Problem, Randbedingungen Problem Beschreibung des Problems oder der Absicht des Patterns Anforderungen (Forces) Die relevanten Anforderungen und Einschränkungen, die berücksichtigt werden müssen. Wie diese miteinander interagieren und im Konflikt stehen. Die daraus entstehenden Kosten. Typischerweise durch ein motivierendes Szenario illustriert. Anwendbarkeit (Context) − Applicability Die Vorbedingungen unter denen das Pattern benötigt wird. © 2000-2010 Dr. G. Kniesel Vorlesung „Softwaretechnologie“ (SWT) Seite 7-36 ROOTS Bestandteile eines Patterns: Lösung Die Lösung (Software Configuration) wird beschrieben durch: Rollen Funktionen die Programmelemente im Rahmen des Patterns erfüllen. Interfaces, Klassen, Methoden, Felder / Assoziationen Methodenaufrufe und Feldzugriffe Sie werden bei der Implementierung aufg konkrete Programmelemente abgebildet (‚Player‘) Statische + dynamische Beziehungen Klassendiagramm, dynamische Diagramme, Text Meistens ist das Verständnis des dynamischen Verhaltens entscheidend Denken in Objekten (Instanzen) statt Klassen (Typen)! Teilnehmer − Participants Rollen auf Typebene (Klassen und Interfaces) © 2000-2010 Dr. G. Kniesel Vorlesung „Softwaretechnologie“ (SWT) Seite 7-37 ROOTS Kapitel 6: Entwurfsmuster Klassifikation Danach, was sie modellieren Danach, wie sie es modellieren Danach, wo sie meist eingesetzt werden ROOTS "Gang of Four"-Patterns: Überblick und Klassifikation Verhalten Struktur Visitor Composite Observer Flyweight Command Bisher Template Method Chain of Responsibility Decorator State Proxy Strategy Adapter Multiple Vererbung Bridge Facade Split Objects Factory Method Prototype Abstract Factory Singleton Builder Objekt-Erzeugung Jetzt Klassifikation: „Was“ und „Wie“ Verhaltens-Patterns Verhalten leicht erweiterbar, komponierbar, dynamisch änderbar oder explizit manipulierbar machen Was? Struktur-Patterns Objekte mit fehlendem Zustand, rekursive Strukturen Verschiedenste Formen der Entkopplung (Schnittstelle / Implementierung, Identität / physikalische Speicherung, ...) Erzeugungs-Patterns Flexibilität indem die Festlegung von konkret zu erzeugenden Objekte (new XYZ()) so weit wie möglich verzögert wird und evtl. sogar zur Laufzeit immer noch verändert werden kann. Wie? Split Object Patterns Ziel: Dynamisch änderbares Verhalten, gemeinsame Verwendung oder Entkopplung von Teilobjekten Weg: Aufteilung eines konzeptionellen Gesamtobjektes in modellierte Teilobjekte die kooperieren um das Verhalten des konzeptionellen Gesamtobjektes zu realisieren © 2000-2010 Dr. G. Kniesel Vorlesung „Softwaretechnologie“ (SWT) Seite 7-40 ROOTS Klassifikation: „Was“ und „Wie“ (Fortsetzung) Klassifikation danach was modelliert wird (vorherige Folien) Struktur, Verhalten, Objekterzeugung Klassifikation danach, wie etwas modelliert wird (vorherige Folien) Whole Objects: 1:1-Entsprechung von konzeptuellen Objekten und Implementierungs-Objekten Split Objects: Aufteilung eines konzeptuellen Objektes in verschiedene Implementierungs-Objekte, dynamisch veränderbare Anteile oder Gemeinsamkeiten verschiedener konzeptueller Objekte darstellen © 2000-2010 Dr. G. Kniesel Vorlesung „Softwaretechnologie“ (SWT) Seite 7-41 ROOTS Klassifikation: „Wo“ Klassifikation danach, wo sie meist eingesetzt werden Systementwurf, zur Verbindung / Abgrenzung von Subsystemen Facade, Adapter, Bridge, Proxy, Singleton (zusammen mit Facade) , Observer Objektentwurf Observer, Command, Factory Method, Abstract Factory, Composite, Visitor © 2000-2010 Dr. G. Kniesel Vorlesung „Softwaretechnologie“ (SWT) Seite 7-42 ROOTS Kapitel 6: Entwurfsmuster Wichtige Entwurfsmuster, Teil 1 - System Design Patterns Facade Singleton Adapter Proxy Bridge ROOTS Kapitel 6: Entwurfsmuster Das Singleton Pattern ROOTS Singleton: Motivation Beschränkung der Anzahl von Exemplaren zu einer Klasse Meist: nur ein einzelnes Exemplar Motivation: Zentrale Kontrolle Z.B. Facade, Repository, Abstract Factory Aber auch: feste Menge von Exemplaren Motivation 1: begrenzte Ressourcen (z.B. auf mobilen Geräten) Motivation 2: Teure Objekterzeugung durch „Object Pool“ vermeiden z.B. 1000 Enterprise Java Beans vorhalten, nach Nutzung zurück in den Pool © 2000-2010 Dr. G. Kniesel Vorlesung „Softwaretechnologie“ (SWT) Seite 7-46 ROOTS Singleton: Struktur + Implementierung Besitzt nur private Konstruktoren: Singleton getInstance() instanceOperation() -instancePool -instanceData private Singleton() { this.Singleton(arg1, ..., argN); } Liefert eine Instanz (typischerweise immer die private Singleton(...) { Selbe): ... } public static Singleton getInstance() { if (instancePool == null) Speichert die einzige instancePool = new Singleton(); return instancePool; Instanz oder begrenzte } Menge an Instanzen Nur private Konstruktoren dadurch wird verhindert, dass Clients beliebig viele Instanzen erzeugen können in Java muss explizit ein privater Konstruktor mit leerer Argumentliste implementiert werden, damit kein impliziter öffentlicher Konstruktor vom Compiler erzeugt wird instancePool als Registry für alle Singleton-Instanzen lookup-Mechanismus erforderlich um gezielt eine Instanz auszuwählen © 2000-2010 Dr. G. Kniesel Vorlesung „Softwaretechnologie“ (SWT) Seite 7-47 ROOTS Kapitel 6: Entwurfsmuster Das Proxy Pattern ROOTS Proxy Pattern (auch: Surogate, Smart Reference) Absicht Stellvertreter für ein anderes Objekt bietet Kontrolle über Objekt-Erzeugung und -Zugriff Motivation kostspielige Objekt-Erzeugung verzögern (zB: große Bilder) verzögerte Objekterzeugung soll Programmstruktur nicht global verändern Idee Bild-Stellvertreter (Proxy) verwenden Bild-Stellvertreter verhält sich aus Client-Sicht wie Bild Bild-Stellvertreter erzeugt Bild bei Bedarf :TextDocument image :ImageProxy file :Image Hauptspeicher © 2000-2010 Dr. G. Kniesel Vorlesung „Softwaretechnologie“ (SWT) Platte Seite 7-52 ROOTS Proxy Pattern: Beispiel <<interface>> * Graphic DocumentEditor draw() getExtent() store() load() Image <<creates>> fileName extent imageData extent draw() getExtent() store() load() © 2000-2010 Dr. G. Kniesel ImageProxy image draw() getExtent() store() load() Vorlesung „Softwaretechnologie“ (SWT) if (image == 0){ image = loadImage(filename); } image.draw() if (image == 0){ return extent; } else { return image.getExtent(); } Seite 7-53 ROOTS Proxy Pattern: Schema <<interface>> * Client Subject request() ... RealSubject realSubject Proxy request() ... request() ... :RealSubject :Proxy request() © 2000-2010 Dr. G. Kniesel ... realSubject.request(); ... request() Vorlesung „Softwaretechnologie“ (SWT) :Client Seite 7-54 ROOTS Proxy Pattern: Verantwortlichkeiten Proxy bietet gleiches Interface wie "Subject" referenziert eine "RealSubject"-Instanz kontrolliert alle Aktionen auf dem "RealSubject" Subject definiert das gemeinsame Interface RealSubject das Objekt das der Proxy vertritt eigentliche Funktionalität Zusammenspiel selektives Forwarding © 2000-2010 Dr. G. Kniesel Vorlesung „Softwaretechnologie“ (SWT) Seite 7-55 ROOTS Proxy Pattern: Anwendbarkeit Virtueller Proxy verzögerte Erzeugung "teurer" Objekte bei Bedarf Beispiel: Bilder in Dokument, persistente Objekte Remote Proxy Zugriff auf entferntes Objekt Objekt-Migration Beispiele: CORBA, RMI, mobile Agenten Concurrency Proxy nur eine direkte Referenz auf RealSubject locking des RealSubjects vor Zugriff (threads) Copy-on-Write kopieren erhöht nur internen "CopyCounter" wirkliche Kopie bei Schreibzugriff und "CopyCounter">0 Verzögerung teurer Kopier-Operationen © 2000-2010 Dr. G. Kniesel Vorlesung „Softwaretechnologie“ (SWT) Seite 7-56 ROOTS Proxy Pattern: Anwendbarkeit Protection Proxy (Zugriffskontrolle) Schmaleres Interface "Kritische" Operationen ausgeblendet andere via Forwarding implementiert ganz anderes Interface Autorisierung prüfen direkten Zugriff gewähren oder Forwarding Beispiel: "CHOICES" Betriebssystem, JDK © 2000-2010 Dr. G. Kniesel Vorlesung „Softwaretechnologie“ (SWT) Seite 7-57 ROOTS Protection-Proxy im JDK (ab 1.2): GuardedObject Problem Sichere Weitergabe eines schützenwerten Objektes an unbekannten Empfänger Objektspezifische Zugriffsrechte Verzögerte Überprüfung der Zugriffsrechte Idee: GuardedObject Enthält "bewachtes Objekt" und "Wächter" (Guard) Guard-Interface enthält nur die Methode checkGuard(Object) Referenz auf bewachtes Objekt wird nur dann herausgegeben, wenn checkGuard(Object)erfolgreich ist (sonst SecurityException) checkGuard(...) requestor : Object getObject() : Guard proxy : GuardedObject guarded : Object Verbleibendes Problem Man muß sich darauf verlassen, daß der "Requestor" das "bewachte Objekt" selbst nur in ein GuardedObject verpackt weitergibt! © 2000-2010 Dr. G. Kniesel Vorlesung „Softwaretechnologie“ (SWT) Seite 7-58 ROOTS Proxy Pattern: Implementierung „Consultation“ = Weiterleiten von Anfragen Allgemein: manuell erstellte Forwarding-Methoden C++: Operator-Overloading Proxy redefiniert Dereferenzierungs-Operator:*anImage Proxy redefiniert Member-Accesss-Operator:anImage->extent() Smalltalk: Reflektion Proxy redefiniert Methode "doesNotUnderstand: aMessage" Lava: eigenes Sprachkonstrukt Proxy deklariert "consultee"-Variable class Proxy { private consultee RealImage realImage; ... } Falls der Typ von "RealSubject„ dem Proxy bekannt sein muß: Je eine spezifische Proxy-Klasse für jeden RealSubject-Typ ... dem Proxy nicht bekannt sein muß: Nur eine Proxy-Klasse für verschiedene RealSubject-Typen Beispiel: „Guarded Object“ (vorherige Folie) © 2000-2010 Dr. G. Kniesel Vorlesung „Softwaretechnologie“ (SWT) Seite 7-59 ROOTS Proxy Pattern: Implementierung mit „Dynamic Proxies“ in Java Problem: Herkömliche Proxies, mit vielen für den „Subject“-Type spezifischen Weiterleitungsmethoden zu schreiben ist aufwendig und wartungsintensiv Wunsch: Nur eine Proxy-Klasse und nur eine Weiterleitungs-Methode für beliebige „Subject“-Typen an die weitergeleitet wird Nutzen Generische Anfrageweiterleitung Dynamische Erstellung von Stellvertretern für entfernte Objekte © 2000-2010 Dr. G. Kniesel Vorlesung „Softwaretechnologie“ (SWT) Seite 7-60 ROOTS Proxy Pattern: Implementierung mit „Dynamic Proxies“ in Java Eine Dynamic Proxy Class ist eine zur Laufzeit erzeugte Klasse, die eine bei ihrer Erzeugung angegebene Liste von Interfaces implementiert Methode in // Creates a proxy class and an instance of the proxy: java.lang.reflect.Proxy public static Object newProxyInstance( ClassLoader loader, Class[] interfaces, InvocationHandler handler) throws IllegalArgumentException Jede ihrer Instanzen aggregiert ein Objekt dessen Klasse das Interface InvocationHandler implementiert Jeder Aufruf an die Proxy-Instanz wird (automatisch) per Reflektion explizit als Objekt dargestellt und an die invoke()-Method des zugehörigen InvocationHandler übergeben. © 2000-2010 Dr. G. Kniesel Vorlesung „Softwaretechnologie“ (SWT) Seite 7-61 ROOTS Proxy Pattern: Implementierung mit „Dynamic Proxies“ in Java API und Tutorials Official JDK API: "Dynamic Proxy Classes" http://download.oracle.com/javase/1.3/docs/guide/reflection/proxy.html Brian Goetz: "Java theory and practice: Decorating with dynamic proxies", http://www.ibm.com/developerworks/java/library/j-jtp08305.html Bob Tarr: "Dynamic Proxies In Java", http://userpages.umbc.edu/~tarr/dp/lectures/DynProxies-2pp.pdf Mark Davidson: "Using Dynamic Proxies to Generate Event Listeners Dynamically" http://java.sun.com/products/jfc/tsc/articles/generic-listener2/index.html © 2000-2010 Dr. G. Kniesel Vorlesung „Softwaretechnologie“ (SWT) Seite 7-62 ROOTS Proxy Pattern: Implementierung Refenrenzierung des RealSubject vor Instantiierung Orts- und Zeit-unabhängige "Ersatz-Referenzen" Beispiele Dateinamen CORBA IOR (Interoperable Object Reference) © 2000-2010 Dr. G. Kniesel Vorlesung „Softwaretechnologie“ (SWT) Seite 7-63 ROOTS Kapitel 6: Entwurfsmuster Das Adapter Pattern ROOTS Adapter Pattern (auch: Wrapper) Absicht Schnittstelle existierender Klasse an Bedarf existierender Clients anpassen Motivation Graphik-Editor bearbeitet Shapes Linien, Rechtecke, ... durch "BoundingBox" beschrieben Textelemente sollen auch möglich sein Klasse TextView vorhanden bietet keine "BoundingBox"-Operation Integration ohne Änderung der gesamten Shape-Hierarchie und ihrer Clients Änderung der TextView-Klasse Idee Adapter-Klasse stellt Shape-Interface zur Verfügung ... implementiert Shape-Interface anhand der verfügbaren TextViewMethoden © 2000-2010 Dr. G. Kniesel Vorlesung „Softwaretechnologie“ (SWT) Seite 7-65 ROOTS Adapter Pattern: Beispiel Existierende Klassen DrawingEditor * Shape Adapter-Klasse BoundingBox() CreateManipulator() Line TextShape BoundingBox() CreateManipulator() BoundingBox() CreateManipulator() text TextView getExtent() ... return text.getExtent() return new TextManipulator() © 2000-2010 Dr. G. Kniesel Vorlesung „Softwaretechnologie“ (SWT) Seite 7-66 ROOTS Adapter Pattern (Objekt-Adapter): Schema adaptee Client Target Adaptee request() other() f() f() Adaptee_N … Adapter request() f() :Client … adaptee.other() :Adapter request() :Adaptee_N other() f() © 2000-2010 Dr. G. Kniesel Vorlesung „Softwaretechnologie“ (SWT) Seite 7-67 ROOTS Adapter Pattern (Objekt-Adapter): Konsequenzen adaptee Client Target Adaptee request() other() f() f() Adaptee_N … Adapter request() f() … adaptee.other() Adaptiert eine ganze Klassenhierarchie Beliebige Adapter-Subtypen können mit beliebigen Adaptee-Subtypen kombiniert werden ( siehe Objektdiagram auf vorheriger Folie) Kombination wird erst zur Laufzeit, auf Objektebene, festgelegt Overriding nicht möglich Die f()-Definition aus Adapter wird nicht anstelle der f()-Definition aus Adaptee für den f()-Aufruf aus der Methode other() verwendet ( siehe Objektdiagram auf vorheriger Folie) © 2000-2010 Dr. G. Kniesel Vorlesung „Softwaretechnologie“ (SWT) Seite 7-68 ROOTS Adapter Pattern (Object Adapter): Variante Client Target request() Adapter adaptee Adaptee other() f() f() … Adaptee_N … …‘ Adaptee_N‘ …‘ f() f() f() request() f() Object Adapter mit Overriding zu Adaptee und jede Unterklasse des Adaptees eine weitere Unterklasse einfügen, in die das redefinierte Verhalten eingefügt wird (also z.B. f()) Warum neue Unterklassen? Weil die vorhandene Adaptee-Hierarchie nicht veränderbar ist! Problem: Redundanz! Was konzeptionell nur ein mal in „Adapter“ stehen sollte wird in jeder neuen Unterklasse von „Adaptee“ redundant eingefügt Wartungsprobleme! © 2000-2010 Dr. G. Kniesel Vorlesung „Softwaretechnologie“ (SWT) Seite 7-69 ROOTS Class Adapter Idiom „Vererbung ohne Subtyping“: Erbender erbt Methoden die nicht als Teil seines Interface sichtbar werden. "private inheritance" in C++ "closed inheritance" in Eiffel Client Target Adaptee request() other() f() f() Adaptee_N … <<implementation inheritance>> Adapter request() f() :Client … anAdaptedAdaptee:Adapter request() other() f() © 2000-2010 Dr. G. Kniesel Vorlesung „Softwaretechnologie“ (SWT) Seite 7-70 ROOTS Class Adapter Idiom: Konsequenzen Client Target Adaptee request() other() f() f() Adaptee_N … <<implementation inheritance>> Adapter request() f() :Client … anAdaptedAdaptee:Adapter Overriding des Adaptee-Verhaltens leicht möglich Da Adapter eine Unterklasse von Adaptee ist, funktioniert das Overriding von f() Keine zusätzliche Indirektion nur ein Objekt statt zwei Adaptiert nur eine Klasse Die gelben Unterklassen von Adaptee werden nicht mit adaptiert © 2000-2010 Dr. G. Kniesel Vorlesung „Softwaretechnologie“ (SWT) Seite 7-71 ROOTS Adapter Pattern: Konsequenzen Class Adapter Client adaptiert nur eine Klasse ... nicht ihre Unterklassen Overriding des Adaptee-Verhaltens leicht möglich keine zusätzliche Indirektion (nur ein Objekt) Object Adapter adaptiert eine ganze Klassenhierarchie Overriding schwieriger :Client Target request() Adapter request() Adaptee f() m() Adapt_N f() m() :Adapter :Adaptee redefiniertes Verhalten in spezifische Unterklasse des Adaptees einfügen Adapter benutzt diese Unterklasse Kombinierbarkeit mit anderen Unterklassen geht verloren Object Adapter mit Delegation (roots.iai.uni-bonn.de/research/darwin) adaptiert eine ganze Klassenhierarchie Overriding des Adaptee-Verhaltens leicht möglich © 2000-2010 Dr. G. Kniesel Vorlesung „Softwaretechnologie“ (SWT) Seite 7-72 ROOTS Kapitel 6: Entwurfsmuster Das Bridge Pattern ROOTS Bridge Pattern (auch: Handle / Body) Absicht Schnittstelle und Implementierung trennen ... unabhängig variieren Motivation portable "Window"-Abstraktion in GUI-Toolkit mehrere Variations-Dimensionen Fenster-Arten: – normal / als Icon, – schließbar / nicht schließbar, – ... Implementierungen: – – – – – © 2000-2010 Dr. G. Kniesel X-Windows, IBM Presentation Manager, MacOS, Windows XYZ, ... Vorlesung „Softwaretechnologie“ (SWT) Seite 7-84 ROOTS Bridge Pattern: Warum nicht einfach Vererbung einsetzen? Neue Fenster-Art: "iconifizierbare" Fenster Window XWindow PMWindow Window XWindow Probleme dieses Lösungsversuchs PMWindow IconWindow XIconWindow PMIconWindow Eigene Klasse für jede Kombination Fenster-Art / Plattform unwartbar Client wählt Kombination Fenster-Art / Plattform (bei der Objekterzeugung) plattformabhängiger Client-Code © 2000-2010 Dr. G. Kniesel Vorlesung „Softwaretechnologie“ (SWT) Seite 7-85 ROOTS Bridge Pattern: Idee Trennung von Konzeptueller Hierarchie Implementierungs-Hierarchie bridge imp Window WindowImp drawText() drawRect() devDrawText() devDrawLine() imp.devDrawLine() imp.devDrawLine() imp.devDrawLine() imp.devDrawLine() IconWindow TransientWindow XWindowImp PMWindowImp drawBorder() drawCloseBox() devDrawText() devDrawLine() devDrawLine() devDrawText() XDrawLine() XDrawString() drawRect() drawText() drawRect() Bridge Pattern: Schema Client Abstraction imp Implementor operation() basicOperation() imp.basicOperation() RefinedAbstraction © 2000-2010 Dr. G. Kniesel ConcreteImplementorA ConcreteImplementorB basicOperation() basicOperation() Vorlesung „Softwaretechnologie“ (SWT) Seite 7-87 ROOTS Bridge Pattern: Anwendbarkeit Dynamische Änderbarkeit Implementierung erst zur Laufzeit auswählen Unabhängige Variabilität neue Unterklassen in beiden Hierarchien beliebig kombinierbar Implementierungs-Transparenz für Clients Änderungen der Implementierung erfordern keine Änderung / Neuübersetzung der Clients Vermeidung von "Nested Generalisations" keine Hierarchien der Art wie in der Motivations-Folie gezeigt keine kombinatorische Explosion der Klassenanzahl Sharing mehrere Clients nutzen gleiche Implementierung z.B. Strings © 2000-2010 Dr. G. Kniesel Vorlesung „Softwaretechnologie“ (SWT) Seite 7-89 ROOTS Bridge Pattern: Implementierung Client Abstraction Implementor imp Instantiierung des richtigen ConcreteImplementors ... Falls Abstraction alle ConcreteImplementor-Klassen kennt: Fallunterscheidung im Konstruktor der ConcreteAbstraction Auswahl des ConcreteImplementor anhand von Parametern des Konstruktors Alternativ: Default-Initialisierung und spätere situationsbedingte Änderung Falls Abstraction völlig unabhängig von ConcreteImplementor-Klassen sein soll: Entscheidung anderem Objekt überlassen Abstract Factory Pattern © 2000-2010 Dr. G. Kniesel Vorlesung „Softwaretechnologie“ (SWT) Seite 7-90 ROOTS Kapitel 6: Entwurfsmuster Wichtige Entwurfsmuster, Teil 2 - Object Design Patterns Command Factory Method Abstract Factory Composite Visitor ROOTS "Gang of Four"-Patterns: Überblick und Klassifikation Verhalten Visitor Struktur Composite Observer Flyweight Command Template Method Chain of Responsibility Decorator State Proxy Strategy Adapter Multiple Vererbung Bridge Facade Jetzt Split Objects Factory Method Prototype Abstract Factory Singleton Builder Objekt-Erzeugung Kapitel 6: Entwurfsmuster Das Factory Method Pattern ROOTS Factory Method Ziel Entscheidung über konkreter Klasse neuer Objekte verzögern Motivation Framework mit vordefinierten Klassen "Document" und "Application" Template-Methode, für das Öffnen eines Dokuments: 1. Check ob Dokument-Art bekannt 2. Erzeugung einer Document-Instanz !?! Erzeugung von Instanzen noch nicht bekannter Klassen! Idee aktuelle Klasse entscheidet wann Objekte erzeugt werden Aufruf einer abstrakten Methode Subklasse entscheidet was für Objekte erzeugt werden implementiert abstrakte Methode passend © 2000-2010 Dr. G. Kniesel Vorlesung „Softwaretechnologie“ (SWT) Seite 7-94 ROOTS Factory Method: Beispiel Framework Document MyDocument * docs Application newDocument() doCreateDocument() Document doc = doCreateDocument(); docs.add(doc); doc.open(); MyApplication doCreateDocument() Applikation return new MyDocument() Factory Method: Schema Creator Product anOperation() factoryMethod() ConcreteProduct ... product = factoryMethod(); ... ConcreteCreator factoryMethod() return new ConcreteProduct() Factory Method kann abstrakt sein kann Default-Implementierung haben Creator (Aufrufer der Factory Method) kann Klasse sein, die die Factory Method definiert kann Client-Klasse sein Beispiel: parallele Vererbungs-Hierarchien © 2000-2010 Dr. G. Kniesel Vorlesung „Softwaretechnologie“ (SWT) Seite 7-96 ROOTS Factory Method: Anwendbarkeit Klasse neuer Objekte unbekannt Verzögerte Entscheidung über Instantiierung erst in Subklasse erst beim Client Mehrere Hilfsklassen Wissen über konkrete Hilfsklassen an einer Stelle lokalisieren Beispiel: Parallele Hierarchien (nächste Folie) © 2000-2010 Dr. G. Kniesel Vorlesung „Softwaretechnologie“ (SWT) Seite 7-97 ROOTS Factory Method: Anwendbarkeit Figure Client Manipulator createManipulator() ... downClick() drag() upClick() LineFigure TextFigure createManipulator() ... createManipulator() ... LineManipulator Textmanipulator downClick() drag() upClick() downClick() drag() upClick() Verbindung paralleler Klassenhierarchien Factory Method lokalisiert das Wissen über zusammengehörige Klassen Restlicher Code der Figure-Hierarchie und Client-Code ist völlig unabhängig von spezifischen Manipulators (nur vom Manipulator-Interface) © 2000-2010 Dr. G. Kniesel Vorlesung „Softwaretechnologie“ (SWT) Seite 7-98 ROOTS Factory Method: Implementierung Fester "Produkt-Typ" jede Unterklasse erzeugt festgelegte Produkt-Art Codierter "Produkt-Typ" Parameter oder Objekt-Variable kodiert "Produkt-Typ" Fallunterscheidung anhand Code mehrere Produkte mehr Flexibilität Klassen-Objekt als "Produkt-Typ" Parameter oder Objekt-Variable ist "Produkt-Typ" direkte Instantiierung mehr Flexibilität bessere Wartbarkeit kein statischer Typ-Check © 2000-2010 Dr. G. Kniesel class Creator { Product create(){ MyProduct(); } } class Creator { Product create(int id) { if (id==1) return MyProduct1(); if (id==2) return MyProduct2(); ... } } Idiom reflektiver Sprachen • Smalltalk • Java class Creator { Object create(Class prodType) { return prodType.getInstance(); } } Reflektiver Aufruf des parameterelosen Vorlesung „Softwaretechnologie“ (SWT) Default-Konstruktors Seite 7-99 ROOTS Factory Method: Konsequenzen Code wird abstrakter / wiederverwendbarer keine festen Abhängigkeiten von spezifischen Klassen Verbindung paralleler Klassenhierarchien Factory Method lokalisiert das Wissen über Zusammengehörigkeiten evtl. künstliche Subklassen nur zwecks Objekterzeugung © 2000-2010 Dr. G. Kniesel Vorlesung „Softwaretechnologie“ (SWT) Seite 7-100 ROOTS Factory Method: Anwendungen überall in Toolkits, Frameworks, Class Libraries Unidraw: Beispiel "Figure und Manipulator" MacApp und ET++: Beispiel "Document und Application" Smalltalk's Model-View-Controller Framework FactoryMethoden-Template: defaultController Hook-Methode: defaultControllerClass Orbix Erzeugung des richtigen Proxy leichte Ersetzung von Standard-Proxy durch Caching Proxy © 2000-2010 Dr. G. Kniesel Vorlesung „Softwaretechnologie“ (SWT) Seite 7-101 ROOTS Kapitel 6: Entwurfsmuster Das Abstract Factory Pattern ROOTS Abstract Factory Ziel zusammengehörige Objekte verwandter Typen erzeugen ... ohne deren Klassenzugehörigkeit fest zu codieren Motivation GUI-Toolkit für mehrere Plattformen Anwendungsklassen nicht von plattformspezifischen Widgets abhängig machen Trotzdem soll die Anwendung alle Widgets konsistent zu einem "look and feel" erzeugen können "look and feel" umschalten können © 2000-2010 Dr. G. Kniesel Vorlesung „Softwaretechnologie“ (SWT) Seite 7-103 ROOTS Abstract Factory: Beispiel WidgetFactory Client createWindow() createScrollBar() Window MotifWidgetFactory createWindow() createScrollBar() PMWidgetFactory PMWindow MotifWindow createWindow() createScrollBar() Scrollbar PMScrollbar © 2000-2010 Dr. G. Kniesel Vorlesung „Softwaretechnologie“ (SWT) MotifScrollBar Seite 7-104 ROOTS Abstract Factory: Schema AbstractFactory Client createProductA() createProductB() AbstractProductA ConreteFactory1 createProductA() createProductB() ConreteFactory2 ProductA2 ProductA1 createProductA() createProductB() AbstractProductB ProductB2 © 2000-2010 Dr. G. Kniesel Vorlesung „Softwaretechnologie“ (SWT) ProductB1 Seite 7-105 ROOTS Abstract Factory: Implementierung ConcreteFactories sind Singletons Produkt-Erzeugung via Factory-Methods fester Produkt-Typ (eine Methode für jedes Produkt) Nachteil neues Produkt erfordert Änderung der gesamten Factory-Hierarchie Codierter "Produkt-Typ" (eine parametrisierte Methode für alle Produkte) Vorteil leichte Erweiterbarkeit um neues Produkt Nachteile: alle Produkte müssen gemeinsamen Obertyp haben Clients können nur die Operationen des gemeinsamen Obertyps nutzen Verzicht auf statische Typsicherheit Klassen-Objekt als "Produkt-Typ" (eine parametrisierte Methode) Vorteil neues Produkt erfordert keinerlei Änderungen der Factory Nachteil Verzicht auf jegliche statische Typinformation / Typsicherheit Abstract Factory: Implementierung Produktfamilie = Subklasse Vorteil Konsistenz der Produkte Nachteil neue Produktfamilie erfordert neue Subklasse, auch bei geringen Unterschieden Produktfamilie = von Clients konfigurierte assoziative Datenstruktur Varianten Prototypen und Cloning Klassen und Instantiierung Vorteil keine Subklassenbildung erforderlich Nachteil Verantwortlichkeit an Clients abgegeben konsistente Produktfamilien können nicht mehr garantiert werden © 2000-2010 Dr. G. Kniesel Vorlesung „Softwaretechnologie“ (SWT) Seite 7-107 ROOTS Abstract Factory: Konsequenzen Abschirmung von Implementierungs-Klassen Namen von Implementierungsklassen erscheinen nicht im Code von Clients Clients benutzen nur abstraktes Interface Leichte Austauschbarkeit von Produktfamilien Name einer ConcreteFactory erscheint nur ein mal im Code bei ihrer Instantiierung Leicht austauschbar gegen andere ConcreteFactory Beispiel: Dynamisches Ändern des look-and-feel andere ConcreteFactory instantiieren alle GUI-Objekte neu erzeugen Konsistente Benutzung von Produktfamilien Keine Motif-Scrollbar in Macintosh-Fenster Schwierige Erweiterung um neue Produktarten Schnittstelle der AbstractFactory legt Produktarten fest Neue Produktart = Änderung der gesamten Factory-Hierarchie Abstract Factory: Anwendbarkeit System soll unabhängig sein von Objekt-Erzeugung Objekt-Komposition Objekt-Darstellung System soll konfigurierbar sein Auswahl aus verschiedenen Produkt-Familien konsistente Produktfamilien nur Objekte der gleichen Familie "passen zusammen" Library mit Produktfamilie anbieten Clients sollen nur Schnittstelle kennen ... nicht die genauen Teilprodukt-Arten / -Implementierungen © 2000-2010 Dr. G. Kniesel Vorlesung „Softwaretechnologie“ (SWT) Seite 7-109 ROOTS "Gang of Four"-Patterns: Überblick und Klassifikation Jetzt Verhalten Visitor Struktur Composite Observer Flyweight Command Template Method Chain of Responsibility Decorator State Proxy Strategy Adapter Multiple Vererbung Bridge Facade Split Objects Factory Method Prototype Abstract Factory Singleton Builder Objekt-Erzeugung Kapitel 6: Entwurfsmuster Das Command Pattern ROOTS Das Command Pattern: Motivation Kontext GUI-Toolkits mit Buttons, Menüs, etc. Forces Vielfalt trotz Einheitlichkeit Einheitlicher Code in allen GUI-Elementen .. trotzdem verschiedene Effekte Wiederverwendung Über verschiedene GUI-Elemente ansprechbare Operationen nur ein mal programmieren Dynamik dynamische Änderung der Aktionen von Menu-Einträgen kontext-sensitive Aktionen Das Command Pattern: Idee Operationen als Objekte mit Methode execute() darstellen In den GUI-Elementen speichern Einheitlicher Aufruf Application Menu MenuItem add(Document) add(Menuitem) clicked() command.execute(); command Command execute() Document open() close() cut() copy() paste() document PasteCommand execute() document.paste(); Verschiedene Implementierungen Command Pattern: Schema und Rollen setCommand() Command execute() Receiver ConcreteCommand action() execute() Command Interface Schnittstelle, die festlegt, was Commands tun können Mindestens Execute, optional auch Undo, Redo Concrete Command Implementiert Command Interface „Controllers“ sind oft „ConcreteCommands“ <<interface>> Invoker Client Execute-Methode Ausführen von Kommandos Undo-Methode Rückgängig machen von Kommandos Redo-Methode Rückgängig gemachtes Kommando wieder ausführen Das Command Pattern: Konsequenzen Entkopplung von Aufruf einer Operation und Spezifikation einer Operation. Kommandos als Objekte Command-Objekte können wie andere Objekte auch manipuliert und erweitert werden. Komposition Folgen von Command-Objekte können zu weiteren Command-Objekten zusammengefasst werden. Erweiterbarkeit Neue Command-Objekte können leicht hinzugefügt werden, da keine Klassen geändert werden müssen. Das Command Pattern: Anwendbarkeit Operationen als Parameter Variable Aktionen referenziertes Command-Objekt austauschen Zeitliche Trennung Befehl zur Ausführung, Protokollierung, Ausführung Speicherung und Protokollierung von Operationen History-Liste Serialisierung "Undo" von Operationen Command-Objekte enthalten neben execute() auch unexecute() werden in einer History-Liste gespeichert Recover-Funktion nach Systemabstürzen History-Liste wird gespeichert Zustand eines Systems ab letzter Speicherung wiederstellbar Unterstützung von Transaktionen Transaktionen können sowohl einfache ("primitive"), als auch komplexe CommandObjekte sein. Implementierung des Command Patterns Unterschiedliche Grade von Intelligenz Command-Objekte können "nur" Verbindung zwischen Sender und Empfänger sein, oder aber alles selbstständig erledigen. Unterstützung von "undo" Semantik Undo (unexecute()) und redo (execute()) müssen den exakt gegenteiligen Effekt haben! Problem: In den wenigsten Fällen gibt es exact inverse Operationen Die Mathematik ist da eine Ausnahme... Daher Zusatzinfos erforderlich Damit ein Command-Objekt "undo" unterstützen kann, müssen evtl. zusätzliche Informationen gespeichert werden. Typischerweise: Kopien des alten Zustands der Objekte die wiederhergestellt werden sollen. History-Liste Für mehrere Levels von undo/redo Klonen vor Speicherung in der History-Liste Es reicht nicht eine Referenz auf die Objekte zu setzen! Man muss das Objekt "tief" klonen, um sicherzustellen dass sein Zustand nicht verändert wird. Patterns-Überblick Verhalten Struktur Visitor Composite Observer Flyweight Command Template Method Chain of Responsibility Decorator State Adapter Strategy Proxy Multiple Vererbung Bridge Facade Split Objects Factory Method Prototype Abstract Factory Singleton Builder Objekt-Erzeugung Kapitel 6: Entwurfsmuster Verbindung von Command und Observer im JDK ROOTS Verbindung von Observer und Command in Java <<interface>> ActionListener void actionPerfomed(ActionEvent evt) <<implements>> MyPasteCommand :MenuItem void actionPerfomed(ActionEvent evt) :Button addActionListener(ActionListener) :JComponent actionPerformed(ActionEvent) : MyPasteCommand registerKeyboardAction(ActionListener, KeyStroke, ...) Observer Buttons, Menue-Einträge und Tasten generieren "ActionEvents" Interface "ActionListener" ist vordefiniert "ActionListener" implementieren ... und Instanzen davon bei Buttons, MenuItems, etc registrieren Command & Observer gleiche Methode (z.B. actionPerformed) spielt die Rolle der run() Methode eines Commands und die Rolle der update() Methode eines Observers implementierende Klasse (z.B. MyPasteCommand) ist gleichzeitig ein Command und ein Observer Verbindung von Observer und Command in Java verbindet auch Push und Pull <<interface>> ActionListener void actionPerfomed(ActionEvent evt) <<implements>> MyPasteCommand :MenuItem void actionPerfomed(ActionEvent evt) :Button addActionListener(ActionListener) :JComponent actionPerformed(ActionEvent) : MyPasteCommand registerKeyboardAction(ActionListener, KeyStroke, ...) Push Observer Subject „pushed“ eine „Event“-Instanz Der „Event“-Typ kann selbst definiert werden In dieser Instanz können somit weitere Informationen mit „gepushed“ werden (als Werte von Instanzvariablen) Pull Observer Die als Parameter übergebene „Event“-Instanz enthält immer eine Referenz auf die Quelle des Events Somit ist es möglich von dort weitere Informationen zu anzufragen („pull“) Verbindung von Observer und Command in Java (2) Zusätzliche Unterstützung für <<interface>> ActionListener "Command" Aktivierung / Deaktivierung von MenuItems denen diese "Action" zugeordnet ist ... Parameter können allerdings auch direkt als InstanzVariablen realisiert werden. void actionPerfomed(ActionEvent evt) <<extends>> <<interface>> Action void putValue(String key, Object value) Object getValue(String key) Einheitliche Schnittstelle zur Speicherung von Parametern für "Action" ... boolean isEnabled() void setEnabled(boolean b) void addPropertyChangeListener(PropertyChangeListener listener) void removePropertyChangeListener(PropertyChangeListener listener) <<implements>> AbstractAction // alles ausser void actionPerfomed(ActionEvent evt) <<extends>> MyPasteCommand void actionPerfomed(ActionEvent evt) im JDK enthalten Interface "Action" und Klasse "AbstractAction" Beispiel: Änderung der Hintergrundfarbe (1) class ColorAction extends AbstractAction { public ColorAction(..., Color c, Component comp) { ... color = c; target = comp; } public void actionPerformed(ActionEvent evt) { target.setBackground(color); target.repaint(); } private Component target; private Color color; } ColorAction class ActionButton extends JButton { public ActionButton(Action a) { ... addActionListener(a); } } Ändern der Hintergrundfarbe einer GUI-Komponente ActionButton Buttons die sofort bei Erzeugung mit einer Action verknüpft werden Beispiel: Änderung der Hintergrundfarbe (2) Nutzung der ColorAction Erzeugung einer Instanz Registrierung class SeparateGUIFrame extends JFrame { public SeparateGUIFrame() { ... JPanel panel = new JPanel(); Action blueAction = new ColorAction("Blue", ...,..., panel); panel.registerKeyboardAction(blueAction,...); panel.add(new ActionButton(blueAction)); JMenu menu = new JMenu("Color"); menu.add(blueAction); ... } } Beispiel und Erläuterung siehe: "Core Java 2", Kapitel 8, Abschnitt "Separating GUI and Application Code". Fazit Elegante Verbindung von Observer und Command Commands sind ActionListener von Buttons, Menus, etc. Einheitlicher Aufru via actionPerformed(ActionEvent evt) Buttons und Menus sind PropertyChangeListener von Commands Aktivierung / Deaktivierung Wiederverwendung gleiche Action für Menu, Button, Key Dynamik Wie ändert man die aktuelle Aktion? ... konsistent für alle betroffenen MenuItems, Buttons, etc.??? Strategy Pattern! Kapitel 6: Entwurfsmuster Das Composite Pattern ROOTS Composite Pattern Ziel rekursive Aggregations-Strukturen darstellen ("ist Teil von") Aggregat und Teile einheitlich behandeln Motivation Gruppierung von Graphiken © 2000-2010 Dr. G. Kniesel Vorlesung „Softwaretechnologie“ (SWT) Seite 7-128 ROOTS Composite Pattern: Beispiel Graphic draw() add(Graphic) remove(Graphic) getChildren() children Line Text Picture draw() draw() draw() add(Graphic) remove(Graphic) getChildren() :Line :Text :Text :Picture © 2000-2010 Dr. G. Kniesel Vorlesung „Softwaretechnologie“ (SWT) draw() { for all c in children c.draw() } :Picture Seite 7-129 ROOTS Composite Pattern: Struktur * Client Component operation() add(Component) remove(Component) getChildren() children Leaf Composite operation() add(Component) remove(Component) getChildren() operation() add(Component) remove(Component) getChildren() operation() { for all c in children c.operation() } add() {} oder add() {throw new MessageNotSupportedException()} © 2000-2010 Dr. G. Kniesel Vorlesung „Softwaretechnologie“ (SWT) Seite 7-130 ROOTS Composite Pattern: Verantwortlichkeiten * Component Component (Graphic) operation() add(Component) remove(Component) getChildren() gemeinsames Interface aller Teilobjekte default-Verhalten Interface für Zugriff auf Teilobjekte (!) children evtl. Interface für Zugriff auf Elternobjekte Leaf (Rectangle, Line, Text) Leaf Composite "primitive" Teil-Objekte operation() operation() add(Component) remove(Component) getChildren() implementieren gemeinsames Interface leere Implementierungen für Teilzugriffs-Interface Composite (Picture) speichert Teilobjekte implementiert gemeinsames Interface durch forwarding implementiert Teilzugriffs-Interface © 2000-2010 Dr. G. Kniesel Vorlesung „Softwaretechnologie“ (SWT) Seite 7-131 ROOTS Composite Pattern: Implementierung Wenn Composites wissen sollen wovon sie Teil sind * Component operation() add(Component) remove(Component) getChildren() Explizite Referenzen auf Composite in Component Klasse children Schließt explizite Referenz der Components 1 gemeinsam nutzen sollen parent Wenn mehrere Composites Components Leaf Composite operation() operation() add(Component) remove(Component) getChildren() auf Composite aus oder erfordert, dass Components wissen, dass sie Teile mehrerer Composites sind Component Interface "Sauberes Design": Verwaltungs-Operationen (add, remove) in Composite, da sie für Leafs nicht anwendbar sind. Wunsch nach einheitlicher Behandlung aller Graphic-Objekte durch Clients Verwaltungs-Operationen in Component mit default-Implementierung die nichts tut Leaf-Klassen sind damit zufrieden, Composites müssen die Operationen passend implementieren. © 2000-2010 Dr. G. Kniesel Vorlesung „Softwaretechnologie“ (SWT) Seite 7-132 ROOTS Composite Pattern: Alternative Struktur (add / remove nicht in „Component“) * Client Component children operation() getChildren() Leaf Composite operation() getChildren() operation() add(Component) remove(Component) getChildren() operation() { for all c in children c.operation() } Component getChildren() { return null } © 2000-2010 Dr. G. Kniesel Vorlesung „Softwaretechnologie“ (SWT) Seite 7-133 ROOTS Composite Pattern: Konsequenzen Einheitliche Behandlung Teile Ganzes Einfache Clients Dynamisches Binden statt Fallunterscheidungen Leichte Erweiterbarkeit neue Leaf-Klassen neue Composite-Klassen ohne Client-Änderung Evtl. zu allgemein Einschränkung der Komponenten-Typen schwer „run-time type checks“ (instanceof) © 2000-2010 Dr. G. Kniesel Vorlesung „Softwaretechnologie“ (SWT) Seite 7-134 ROOTS Kapitel 6: Entwurfsmuster Das Visitor Pattern ROOTS Das Visitor Pattern Absicht Repräsentation von Operationen auf Elementen einer Objektstruktur Neue Operationen definieren, ohne die Klassen dieser Objekte zu ändern © 2000-2010 Dr. G. Kniesel Vorlesung „Softwaretechnologie“ (SWT) Seite 7-136 ROOTS Visitor Pattern: Motivation Beispiel: Compiler enthält Klassenhierarchie für Ausdrücke einer Programmiersprache Problem Code einer Operation (z.B. Typüberprüfung) ist über mehrere Klassen einer Datenstruktur verteilt Hinzufügen oder ändern einer Operation erfordert Änderung der gesamten Hierarchie Node TypeCheck() GenerateCode() PrettyPrint() VariableRefNode TypeCheck() GenerateCode() PrettyPrint() © 2000-2010 Dr. G. Kniesel Vorlesung „Softwaretechnologie“ (SWT) AssignmentNode TypeCheck() GenerateCode() PrettyPrint() Seite 7-137 ROOTS Visitor Pattern: Idee (1) Visitor Klasse die alle visit...-Methoden zusammenfasst, die gemeinsam eine Operation auf einer Objektstruktur realisieren Visit...-Methode Ausprägung der Operation auf einem bestimmtem Objekttyp Hat Parameter vom entsprechenden Objekttyp Kann somit alle Funktionalitäten des Typs nutzen um das zu besuchende Objekt zu bearbeiten Visitor visitAssignment(AssignmentNode) visitVariableRef(VariableRefNode) TypeCheckingVisitor CodeGeneratingVisitor visitAssignment(AssignmentNode) visitVariableRef(VariableRefNode) visitAssignment(AssignmentNode) visitVariableRef(VariableRefNode) © 2000-2010 Dr. G. Kniesel Vorlesung „Softwaretechnologie“ (SWT) Seite 7-138 ROOTS Visitor Pattern: Idee (2) Accept-Methoden in allen Klassen der betroffenen Klassenhierarchie Haben Visitor als Parameter „Diese Operation soll auf mir ausgeführt werden!“ Rufen die jeweils zu ihnen passende visit...-Methode auf „Diese Variante der Operation muss auf mir ausgeführt werden!“ Übergeben „this“ als Parameter Program * Node accept(NodeVisitor) AssignmentNode VariableRefNode accept(NodeVisitor v) accept(NodeVisitor v) v.visitAssignment(this) © 2000-2010 Dr. G. Kniesel Vorlesung „Softwaretechnologie“ (SWT) v.visitVariableRef(this) Seite 7-139 ROOTS Visitor Pattern: Schema (Statisch) Client Visitor visitConcreteElementA(ConcreteElementA) visitConcreteElementB(ConcreteElementB) ConcreteVisitor1 ConcreteVisitor2 visitConcreteElementA(ConcreteElementA) visitConcreteElementB(ConcreteElementB) visitConcreteElementA(ConcreteElementA) visitConcreteElementB(ConcreteElementB) ObjectStructure * Element accept(Visitor) ConcreteElementA accept(Visitor v) operationA() v.visitConcreteElementA(this) © 2000-2010 Dr. G. Kniesel Vorlesung „Softwaretechnologie“ (SWT) ConcreteElementB accept(Visitor v) operationB() v.visitConcreteElementB(this) Seite 7-140 ROOTS Visitor Pattern: Verantwortlichkeiten / Implementation Objektstruktur-Hierarchie Einheitliche accept-Methode Visitor-Hierarchie Je eine visit-Methode für jede Klasse der Objektstruktur mit Parameter vom Typ der jeweilige Klasse Traversierung der Objektstruktur kann definiert sein in der besuchten Objektstruktur (Methode accept(...)) oder dem Visitor-Objekt (Method visit...(...)) © 2000-2010 Dr. G. Kniesel Vorlesung „Softwaretechnologie“ (SWT) Seite 7-141 ROOTS Visitor Pattern: Zusammenarbeit welche Operation :ObjectStructure accept(v) auf welchem Objekt ... ist wie implementiert a:ConcreteElementA b:ConcreteElementB v:ConcreteVisitor accept(v) visitConcreteElementA(a) operationA() accept(v) visitConcreteElementB(b) operationB() © 2000-2010 Dr. G. Kniesel Double dispatch Vorlesung „Softwaretechnologie“ (SWT) Seite 7-142 ROOTS Das Visitor Pattern: Konsequenzen Hinzufügen neuer Operationen ist einfach. Neue Visitor-Klasse Hinzufügen neuer Objektklassen ist sehr aufwendig. Neue Objekt-Klasse Neue visit... - Methode in allen Visitors Sammeln von Zuständen Visitor-Objekte können Zustände der besuchten Objekte aufsammeln und (evtl. später) auswerten. Eine Übergabe von zusätzlichen Parametern ist dafür nicht nötig. Verletzung von Kapselung Die Schnittstellen der Klassen der Objektstruktur müssen ausreichend Funktionalität bieten, damit Visitor-Objekte ihre Aufgaben erledigen können. Oft muss mehr preisgegeben werden als (ohne Visitor) nötig wäre. © 2000-2010 Dr. G. Kniesel Vorlesung „Softwaretechnologie“ (SWT) Seite 7-143 ROOTS Das Visitor Pattern: Anwendbarkeit Funktionale Dekomposition Zusammengehörige Operationen sollen zusammengefasst werden ... statt in einer Klassenhierarchie verteilt zu sein Stabile Objekt-Hierarchie selten neue Klassen aber oft neue Operationen Heterogene Hierarchie viele Klassen mit unterschiedlichen Schnittstellen Operationen die von den Klassen abhängen Anwendungsbeispiel Java-Compiler des JDK 1.3 © 2000-2010 Dr. G. Kniesel Vorlesung „Softwaretechnologie“ (SWT) Seite 7-144 ROOTS Das Visitor Pattern: Implementierung Abstrakter Visitor Jede Objektstruktur besitzt eine (abstrakte) Visitor-Klasse. Für jeden Typ T in der Objektstruktur, enthält die Visitor-Klasse je eine Methode mit einem Parameter vom Typ T visitT(T) Konkrete Visitors Jede Unterklasse der Visitor-Klasse redefinieren die visit-Methoden, um ihre jeweilige Funktionalität zu realisieren. Jede konkrete visitT(T) Methode benutzt dabei die spezifischen Operationen des besuchten Objekttyps T Traversierung der Objektstruktur kann in der Objektstruktur (accept(...) Methoden) definiert sein ... oder im Visitor-Objekt (visit...(...) Methoden). © 2000-2010 Dr. G. Kniesel Vorlesung „Softwaretechnologie“ (SWT) Seite 7-145 ROOTS Kapitel 6: Entwurfsmuster Gemeinsamkeiten und Unterschiede der Pattern ROOTS Abgrenzung: Facade, Singleton, Abstract Factory Facade Versteckt Subsystem-Details (Typen und Objekte) Singleton Facaden sind meist Singletons (man braucht nur eine einzige) Abstract Factory Zur Erzeugung konsistenter Sätze von Subsystem-Objekten Als Alternative zu Facade "Verstecken" plattform-spezifischer Klassen © 2000-2010 Dr. G. Kniesel Vorlesung „Softwaretechnologie“ (SWT) Seite 7-147 ROOTS Abgrenzung: Proxy, Decorator, Adpater Proxy gleiches Interface kontrolliert Zugriff "Implementierungs-Detail" Decorator erweitertes Interface zusätzliche Funktionen „konzeptionelle Eigenschaft“ Adapter verschiedenes Interface ähnlich Protection-Proxy © 2000-2010 Dr. G. Kniesel Vorlesung „Softwaretechnologie“ (SWT) Seite 7-148 ROOTS Abgrenzung: Bridge, Adapter, Abstract Factory Bridge antizipierte Entkopplung von Schnittstelle und Implementierung Adapter nachträgliche Anpassung der Schnittstelle einer Implementierung Abstract Factory nutzbar zur Erzeugung und Konfiguration einer Bridge © 2000-2010 Dr. G. Kniesel Vorlesung „Softwaretechnologie“ (SWT) Seite 7-149 ROOTS Abgrenzung: Factory / Template Method, Abstract Factory, Prototype Factory Method Verzögerte Entscheidung über die Klasse eines zu erzeugenden Objektes Template Method ruft oft Factory Method auf Abstract Factory gleiche Motivation gruppiert viele Factory Methods die „zusammengehörige“ Objekte erzeugen erzeugt feste Menge von Objekten von festen Obejkttypen Prototype erfordert keine Unterklassenbildung ... dafür aber explizite initialize()-Methode © 2000-2010 Dr. G. Kniesel Vorlesung „Softwaretechnologie“ (SWT) Seite 7-150 ROOTS Kapitel 6: Entwurfsmuster „Patterns Create Architectures“ Ein Beispiel zum Zusammenspiel von Patterns Bridge & Abstract Factory & Singleton ROOTS „Patterns Create Architectures“ Idee Wenn man Patterns wohlüberlegt zusammen verwendet, entsteht ein Grossteil einer Software-Architektur aus dem Zusammenspiel der Patterns. Beispiel Zusammenspiel von Bridge, Factory und Singleton © 2000-2010 Dr. G. Kniesel Vorlesung „Softwaretechnologie“ (SWT) Seite 7-153 ROOTS Erinnerung ans Abstract Factory Pattern WidgetFactory Client createWindow() createScrollBar() in der Praxis müsste WidgetFactory ein Singleton sein MotifWidgetFactory createWindow() createScrollBar() PMWidgetFactory Window PMWindow MotifWindow createWindow() createScrollBar() Scrollbar in der Praxis müsste hier das BridgePattern angewendet werden PMScrollbar MotifScrollBar Erinnerung ans Bridge Pattern Trennung von Konzeptueller Hierarchie ImplementierungsHierarchie Client Window imp WindowImp drawText() drawRect() devDrawText() devDrawLine() IconWindow TransientWindow PMWindowImp XWindowImp drawBorder() drawCloseBox() devDrawText() devDrawLine() devDrawLine() devDrawText() © 2000-2010 Dr. G. Kniesel Vorlesung „Softwaretechnologie“ (SWT) Seite 7-155 ROOTS Zusammenspiel: Bridge, Factory, Singleton WidgetFactory.setFactory(WidgetFactory.MOTIF) << konfiguriert >> Client << fragt ab>> WidgetFactory setFactory(Type) getFactory() Singleton WidgetFactory.getFactory() PMWidgetFactory MotifWidgetFactory createWindow() createScrollBar() Window IconWIndow TransientWindow Scrollbar FixedSB imp imp ProportionalSB WindowImp PMWindow MotifWindow ScrollbarImp PMScrollbar MotifScrollBar Kapitel 6: Entwurfsmuster Weitere Patterns Kapitel „Systemenwurf“: Facade Pattern & Nutzung von Observer für Ebenen-Architekturen Kapitel „Objektentwurf“: Alle „Split-Object“-Patterns (Strategy, State, Decorator, Overriding, Multiple Vererbung) ROOTS Kapitel 6: Entwurfsmuster Rückblick: Was nützen Patterns? ROOTS Nutzen von Design Patterns (1) Abstraktionen identifiziere, die kein Gegenstück in der realen Welt / dem Analyse-Modell haben Beispiel: Command Pattern Composite Pattern Strategy State "Strict modelling of the real world leads to a system that reflects today's realities but not necesarilly tomorrow's. The abstractions that emerge during design are key to making a design flexible." © 2000-2010 Dr. G. Kniesel Vorlesung „Softwaretechnologie“ (SWT) Seite 7-159 ROOTS Nutzen von Design Patterns (2) Granularität der Objekte festlegen Visitor Gruppe von konsistenten Aktionen Command einzelne Aktion Facade ein "Riesen-Objekt" Flyweight viele kleine, gemeinsam verwendbare Teilobjekte Builder Komposition von Gesamt-Objekt aus Teilobjekten © 2000-2010 Dr. G. Kniesel Vorlesung „Softwaretechnologie“ (SWT) Seite 7-160 ROOTS Nutzen von Design Patterns (3) Schnittstellen identifizieren was gehört dazu was gehört nicht dazu (Bsp. Memento) Beziehungen zwischen Schnittstellen festlegen Subtyping Proxy Decorator Je eine Methode pro Klasse aus einer anderen Objekthierarchie Abstract Factory Visitor Builder © 2000-2010 Dr. G. Kniesel Vorlesung „Softwaretechnologie“ (SWT) Seite 7-161 ROOTS Nutzen von Design Patterns (4) Wahl der Implementierung Interface, Abstrakte Klasse oder konkrete Klasse? Grundthema fast aller Patterns Abstrakte Methode oder Hook Methode? von template method aufgerufene Methoden Overriding oder fixe Implementierung? Factory method Template method Vererbung oder Subtyp-Beziehung? Adapter, Decorator, State, Strategy, Command, Chain of Responsibility Gemeinsamer Obertyp, nicht gemeinsame Implementierung Vererbung oder Aggregation? Vererbung ist statisch, Aggregation dynamisch Wenn das „geerbte“ nicht in der Schnittstelle auftauchen soll: Aggregation und Anfrageweiterleitung nutzen (anstatt Vererbun) Siehe alle "split object patterns" © 2000-2010 Dr. G. Kniesel Vorlesung „Softwaretechnologie“ (SWT) Seite 7-162 ROOTS Nutzen von Design Patterns (5): Patterns verkörpern Grundprinzipien guten Designs Implementierungen austauschbar machen Typdeklarationen mit Interfaces statt mit Klassen Design an Interfaces orientieren, nicht an Klassen Client-Code wiederverwendbar für neue Implementierungen des gleichen Interface Objekt-Erzeugung änderbar gestalten "Creational Patterns" statt "new MyClass()" Client-Code wiederverwendbar für neue Implementierungen des gleichen Interface Funktionalität änderbar gestalten Aggregation und Forwarding statt Vererbung späte Konfigurierbarkeit, Dynamik weniger implizite Abhängigkeiten (kein "fragile base class problem") © 2000-2010 Dr. G. Kniesel Vorlesung „Softwaretechnologie“ (SWT) Seite 7-163 ROOTS Nichtfunktionale Anforderungen geben Hinweise zur Nutzung von Entwurfsmustern Identifikation von Entwurfsmustern anhand von Schlüsselwörtern in der Beschreibung nichtfunktionaler Anforderungen Analog zu Abbot’s Technik bei der Objektidentifikation Facade Pattern „muss mit einer Menge existierender Objekte zusammenarbeiten”, „stellt Dienst bereit“ Adapter Pattern „muss mit einem existierenden Objekt zusammenarbeiten” Bridge Pattern „muss sich um die Schnittstelle zu unterschiedlichen Systemen kümmern von denen einige erst noch entwickelt werden.“ „ein erster Prototyp muss vorgeführt werden“ © 2000-2010 Dr. G. Kniesel Vorlesung „Softwaretechnologie“ (SWT) Seite 7-164 ROOTS Nichtfunktionale Anforderungen geben Hinweise zur Nutzung von Entwurfsmustern (Fortsetzung) Proxy Pattern “muss ortstransparent sein” Observer Pattern “muss erweiterbar sein”, “muss skalierbar sein” Strategy Pattern “muss Funktionalität X in unterschiedlichen, dynamisch auswählbaren Ausprägungen bereitstellen können” Composite Pattern „rekursive Struktur“, “komplexe Struktur” “muss variable Tiefe und Breite haben” Abstract Factory Pattern “Herstellerunabhängig”, “Geräteunabhängig”, “muss eine Produktfamilie unterstützen” © 2000-2010 Dr. G. Kniesel Vorlesung „Softwaretechnologie“ (SWT) Seite 7-165 ROOTS Überblick Einführung Grundidee, Literatur, MVC-Framework als Beispiel Beispiele wichtiger Patterns Observer, Strategy, Command Facade, Singleton, Proxy, Adapter, Bridge Factory Method, Abstract Factory Composite, Visitor Patterns Create Architectures Bridge, Abstract Factory, Singleton Nutzen von Patterns Zusammenfassung und Ausblick Arten von Patterns, Abgrenzung Weiterführende Themen © 2000-2010 Dr. G. Kniesel Vorlesung „Softwaretechnologie“ (SWT) Seite 7-166 ROOTS Arten von Pattern Analysis Pattern Wiederkehrende Problemen in der Analysephase eines Softwareprojekts Martin Fowler: "Analysis Patterns", Addison-Wesley, 1997 Architecture Pattern ... beschreibt mögliche fundamentale Strukturen von Softwaresystemen. ... enthält vordefinierte Subsysteme und ihre Verantwortlichkeiten. ... enthält Regeln und Richtlinien für die Organisation ihrer Beziehungen. Beispiel: Model-View-Controller Design Pattern Schema für die Realisation von Subsystemen oder Komponenten eines Softwaresystems Idiom (auch: Coding Pattern) Low-level design patterns für eine gegebene Programmiersprache. Beispiel: Wie stelle ich sicher, dass eine Instanz einer Java-Klasse nur innerhalb einer bestimmten anderen Klasse erzeugt werden kann? © 2000-2010 Dr. G. Kniesel Vorlesung „Softwaretechnologie“ (SWT) Seite 7-167 ROOTS Weitere Arten von Pattern Organizational Patterns Struktur und Praxis von Organisationen; also Gruppen, die ein gemeinsames Ziel verfolgen http://en.wikipedia.org/wiki/Organizational_patterns Anti-Patterns beschreiben typische Fehler ... und bestenfalls auch wie man sie wieder beseitigt http://de.wikipedia.org/wiki/Anti-Pattern © 2000-2010 Dr. G. Kniesel Vorlesung „Softwaretechnologie“ (SWT) Seite 7-168 ROOTS AbgrenzungPattern versus Algorithmen Abstraktheit Algorithmen lösen konkrete Probleme im Anwendungsbereicht (z.B. Suchen, Sortieren) Pattern lösen generische Entwurfsprobleme (Dynamik, Wartbarkeit, ...) Unvollständigkeit / Schablonenhaftigkeit Algorithmen sind vollständig Komplexität genau ermittelbar Pattern sind „nur“ Schablonen für gewisse Schlüsselinteraktionen, Rest ist beliebig © 2000-2010 Dr. G. Kniesel Vorlesung „Softwaretechnologie“ (SWT) Seite 7-169 ROOTS AbgrenzungPattern versus Frameworks Framework Menge von kooperierenden Klassen für einen spezifischen Anwendungsbereich Erweiterbar durch Unterklassenbildung und Komposition von Instanzen Hollywood-Prinzip ("Don't call us, we'll call you." --> Template Method Pattern) Pattern versus Frameworks Patterns sind abstrakter Frameworks existieren als konkreter, wiederverwendbarer Code Patterns sind nur Schablonen für Code Patterns sind nicht anwendungsabhängig Frameworks werden für konkrete Anwendungsbereiche eingesetzt Patterns sind anwendungsunabhängig Frameworks nutzen Patterns © 2000-2010 Dr. G. Kniesel Vorlesung „Softwaretechnologie“ (SWT) Seite 7-170 ROOTS Weiterführende Themen Pattern Catalogs Sammlungen von lose zusammenhängenden Patterns http://hillside.net/patterns/patterns-catalog Pattern Systems Sammlungen von stark zusammenhängenden Patterns mit engen Verzahnungen Pattern Languages verfolgen ein gemeinsames Ziel, dass durch die Zusammenarbeit der enthaltenen Patterns erreicht werden kann inkl. einer Art "Grammatik", die alle mögliche Kombinationen aufzeigt http://en.wikipedia.org/wiki/Pattern_language © 2000-2010 Dr. G. Kniesel Vorlesung „Softwaretechnologie“ (SWT) Seite 7-171 ROOTS Pattern Zusammenfassung Betonung von Praktikabilität Patterns sind bekannte Lösungen für erwiesenermaßen wiederkehrende Probleme Lösungen, die sich noch nicht in der Praxis bewährt haben, sind keine Pattern. Patterns sind kein Allheilmittel Originalität bei der Anwendung von Patterns ist nach wie vor gefragt. Es muss immer noch abgewägt werden, welche Patterns eingesetzt werden. Gesamteffekt Aufgabe des Softwarearchitekten verlagert sich von der Erfindung des Rades zur Auswahl des richtigen Rades und seiner kreativen Anwendung © 2000-2010 Dr. G. Kniesel Vorlesung „Softwaretechnologie“ (SWT) Seite 7-172 ROOTS