Entwurfsmuster (Software Design Patterns) Verhaltens-Entwurfsmuster Übung Softwareentwicklung 2 für Wirtschaftsinformatik Entwurfsmuster (Software Design Patterns) Verhaltens-Entwurfsmuster Überblick
Entwurfsmuster: Dekorierer / Decorator Überblick
Entwurfsmuster: Dekorierer / Dekorator Problem: Manchmal möchte man zusätzliche Struktur und Verhalten einem Objekt nicht jedoch gleich einer ganzen Klasse (z.B.: durch Vererbung) zuorgnen. Lösung: Die Instanz eines Dekorierers wird vor die zu dekorierende Klasse geschaltet. Der Dekorierer hat die gleiche Schnittstelle wie die zu dekorierende Klasse. Aufrufe an den Dekorierer werden dann verändert oder unverändert weitergeleitet (Delegation), oder sie werden komplett in Eigenregie verarbeitet. Der Dekorierer ist dabei "unsichtbar", da der Aufrufende gar nicht mitbekommt, dass ein Dekorierer vorgeschaltet ist. In einer alternativen Variante kann der Dekorierer als eine Strategie eingebunden und explizit aufgerufen werden. Überblick
Entwurfsmuster: Dekorierer / Dekorator Ein Textfeld soll mit einer Umrahmung "dekoriert" werden. Zwischen den Aufrufer und das Textfeldobjekt wird das entsprechende Dekoriererobjekt eingefügt. Das Dekoriererobjekt erzeugt die Umrahmung, ein weiteres das Scrolling und übergibt den Kontrollfluss an das Textfeld. Da der Dekorierer dieselbe Schnittstelle hat, ändert sich aus der Sicht des Aufrufers nichts. aComponent VisualComponent draw() TextView Decorator draw() component.draw() ScrollDecorator BorderDecorator super.draw() scrollTo() scrollPosition borderWidth draw() scrollTo() draw() drawBorder() super.draw() drawBorder() aBorderDecorator aScrollDecorator aTextView Überblick
Entwurfsmuster: Dekorierer / Dekorator component component aBorderDecorator aScrollDecorator aTextView aBorderDecorator aScrollDecorator aTextView draw() (super.)draw() (super.)draw() scrollTo() drawBorder() Überblick
Entwurfsmuster: Dekorierer / Dekorator Vorteile: Es können mehrere Dekorierer hintereinandergeschaltet werden Die zu dekorierende Klasse ist nicht unbedingt festgelegt (wohl aber deren Schnittstelle) Die Dekorierer können zur Laufzeit und sogar nach der Instantierung ausgetauscht werden Lange, unübersichtliche Vererbungshierarchien werden vermieden. Nachteile: Eventuell müssen viele Methoden implementiert werden, welche die Aufrufe lediglich weiterleiten. Erweiterungen der zu dekorierenden Klasse werden unabsichtlich versteckt. Der Aufbau der Dekorierer-Instanzen wird komplexer. Als Hilfe kann dazu das Entwurfsmuster des Erbauer (Builder) dienen. Überblick
Entwurfsmuster: Besucher / Visitor Überblick
Entwurfsmuster: Besucher / Visitor Problem: Die Integration verschiedener nicht miteinander verwandter Operationen in die Klassen einer Objektstruktur gestaltet sich oft schwierig. Bei der Erweiterung um neue Operationen müssen alle Klassen erweitert werden. Zweck: dient der Kapselung einer auf Elementen einer Objektstruktur auszuführenden Operation. Lösung: Das Besuchermuster lagert die Operationen in externe Besucherklassen. Dazu müssen die zu besuchenden Klassen jedoch eine Schnittstelle zum Empfang eines Besuchers definieren. Vorteil: Definition neuer Operationen ist dadurch ohne Veränderung der betroffenden Elementklassen möglich. Überblick
Entwurfsmuster: Besucher / Visitor Verwendung: Generell empfiehlt sich die Verwendung von Besuchern, wenn: viele unterschiedliche, nicht verwandte Operationen auf einer Objektstruktur realisiert werden sollen, sich die Klassen der Objektstruktur nicht verändern, häufig neue Operationen auf der Objektstruktur integriert werden müssen oder ein Algorithmus über die Klassen einer Objektstrukur verteilt arbeitet, aber zentral verwaltet werden soll. Überblick
Entwurfsmuster: Besucher / Visitor visitConcreteElementA(ConreteElementA) visitConcreteElementB(ConreteElementB) ConcreteVisitor1 ConcreteVisitor2 visitConcreteElementA(concreteElementA) visitConcreteElementB(concreteElementB) visitConcreteElementA(concreteElementA) visitConcreteElementB(concreteElementB) ListOfObjects Element accept(v::Visitor) ConcreteElementA ConcreteElementB accept(v::Visitor) OperationA() accept(v::Visitor) OperationB() v.visitConcreteElementA(this) v.visitConcreteElementB(this) Überblick
Entwurfsmuster: Besucher / Visitor listOfObjects aConcreteElement aConcreteVisitor doSomething() for some elements in listOfObjects accept(v::Visitor) visit(this) operationA() Überblick
Entwurfsmuster: Zuständigkeitskette / Chain of Responsibility Überblick
Entwurfsmuster: Zuständigkeitskette / Chain of Responsibility Problem: Vermeidung der Kopplung des Senders und Empfänger einer Anfrage. Zweck: Trennung von Sender und Empfänger um mehreren Objekten die Möglichkeit zu geben die Anfrage zu beantworten. Weiterleitung der Anfrage an weitere Objekte um ein Objekt zu finden, dass die Anfrage bearbeiten kann. Verwendung: mehr als ein Objekt sind in der Lage eine Anfrage zu beantworten und der Empfänger ist a priori nicht bekannt und soll automatisch bestimmt werden können. senden einer Anfrage an eine Reihe von Objekten ohne das empfangende Objekt explizit zu spezifizieren. Menge der Objekte, die eine Anfrage beantworten können soll zu Laufzeit bestimmt werden. Überblick
Entwurfsmuster: Zuständigkeitskette / Chain of Responsibility Vorteile: Reduzierung der Kopplung Flexibilisierung der Zuteilung von Aufgaben Nachteil: Beantwortung der Anfrage ist nicht garantiert, da ev. sich keiner verantwortlich "fühlt" Überblick
Entwurfsmuster: Zuständigkeitskette / Chain of Responsibility successor Client Handler handleRequest() canHandle() ConcreteHandler1 ConcreteHandler2 handleRequest() canHandle() doSomething() handleRequest() canHandle() doSomething() if(canHandle()) { doSomething() } else { // deligate successor.handleRequest() } Überblick
Patterns: Generating patterns Abstract Factory goal: generating an object with well defined interface but of variable dynamic type solution: object is not created by a constructor but through requesting it from a factory object Factory Method solution: analog to Abstract Factory; class let sub-class generate the object Prototype solution: creation of an object as "copy" of a prototype Überblick
Patterns: Structural Patterns Family goal: clustering of variants solution: abstract class with sub-classes Adapter (Wrapper) goal: make classes fit to a family solution: new family member that redirects messiges to the class Composite goal: composite object that are treated as single entities solution: composite object is part of the family Decorator goal: add new behavior to a class without changing the class or sub-classing solution: message interception Proxy goal: replacement for another object solution: object with same interface replaces the original object, like decorator but adds no new behavior Überblick
Patterns: Structural Patterns Facade goal: access point for a sub-system solution: additional object as mediator between the client and the sub-system Twin goal: modeling multiple inheritance solution: twins coupling objects bidirectional Überblick
Patterns: Behavioural Patterns Iterator goal: iterate through a set of object without knowing the structure of the set solution: iterator hides the set-specific operations Visitor goal: iterate over a homogeneous data structure, but invoking different operations solution: double dispatching - visitor is called back by the visited object Observer goal: object is informed about state changes of observed object solution: observers sub-scribe to observed object and get notified as soon as state changes Strategy goal: changing behaviour solution: changing behaviour realized as class family which is referenced by the invoking object Überblick
Patterns: Behavioural Patterns Message Object goal: message as data package solution: message classes containing the actual message form a family Template Method goal: structure of an algorithm which should contain some variable parts solution: steps of the algorithm as abstract methods which are overridden in the sub-classes Chain of Responsibility goal: passing messages from object to object solution: chainging object of event handlers Überblick