24.11.2013 Aufrufe

Entwurfsmuster

Entwurfsmuster

Entwurfsmuster

MEHR ANZEIGEN
WENIGER ANZEIGEN

Sie wollen auch ein ePaper? Erhöhen Sie die Reichweite Ihrer Titel.

YUMPU macht aus Druck-PDFs automatisch weboptimierte ePaper, die Google liebt.

<strong>Entwurfsmuster</strong><br />

iTec<br />

1


Inhalt 11. Patterns und Frameworks<br />

q Einführung: was ist und wozu braucht man Patterns u. Frameworks ?<br />

q wie werden Patterns beschrieben ?<br />

q Beispiele für Designpatterns<br />

– Singleton<br />

– Proxy<br />

– State<br />

– Beobachter/Observer<br />

– Adapter<br />

– Kompositum<br />

– Dekorierer<br />

– Abstrakte Fabrik<br />

iTec<br />

2


Einführung 11. Patterns und Frameworks<br />

was ist und wozu braucht man Patterns und Frameworks?<br />

q Software-Entwicklung ist mühsam<br />

q wiederverwendbare Software zu schreiben, ist noch mühsamer<br />

q Hilfe bei dieser Mühe:<br />

Design-Patterns und Frameworks, die für häufig<br />

wiederkehrende Probleme bewährte Lösungsmuster<br />

anbieten<br />

iTec<br />

3


Einführung 11. Patterns und Frameworks<br />

Geschichte der Patterns<br />

q Christopher Alexander (1977): A Pattern Language<br />

wie können Standardlösungen immer wiederkehrender<br />

Innenarchitekturprobleme sprachlich formuliert werden?<br />

q Erich Gamma, R.Helm, R. Johnson, J. Vlissides (1995):<br />

Design Patterns – Elements of reusable OO-Software<br />

legten einen bis heute massgebenden Katalog von 23 Patterns vor<br />

q heute:<br />

es gibt kaum OO-Entwicklungen ohne Patterns !<br />

es gehört zum Grundvokabular eines jeden SW-Ingenieurs !<br />

iTec<br />

4


Einführung 11. Patterns und Frameworks<br />

zunächst einige wichtige Begriffe<br />

Software Design<br />

Die Aktivitäten, die aus den Anforderungen an ein<br />

Softwaresystem eine Softwarelösung entwerfen.<br />

Diese Lösung beschreibt die Systemstruktur als<br />

Systemarchitektur (siehe nächste Folie) und dient der<br />

Implementation des Systems als Blueprint.<br />

.<br />

q der Design enthält nicht die Implementation des Systems<br />

q der Design enthält die eigentliche Lösung eines Problems<br />

q der Design wird methodisch und mit Diagrammtechniken erarbeitet<br />

iTec<br />

5


Einführung 11. Patterns und Frameworks<br />

wichtige Begriffe<br />

Software-Architektur<br />

eine Beschreibung der Teilsysteme und Komponenten eines<br />

Softwaresystems und deren Beziehungen untereinander.<br />

Teilsysteme und Komponenten werden unter verschiedenen<br />

Blickwinkeln betrachtet, um verschiedene funktionale und<br />

nichtfunktionale Aspekte zu beschreiben.<br />

Eine Softwarearchitektur ist das Resultat des Software-Designs.<br />

q Komponenten sind gekapselte, mit Schnittstellen versehene<br />

Systemteile: Module, Bibliotheken, Klassen/Objekte<br />

q nichtfunktionale Aspekte: z.B. Erweiterbarkeit, Zuverlässigkeit,<br />

Kosten, Wartbarkeit, Portierbarkeit<br />

q Beziehungen: zB. statisch, dynamisch, abhängig, enthalten, abgeleitet<br />

iTec<br />

6


Einführung 11. Patterns und Frameworks<br />

wichtige Begriffe<br />

Framework<br />

Ein teilweise vorgefertigtes Softwaresystem das noch<br />

"instanziiert" werden muss durch Einfügen fehlender Teile.<br />

Dabei wird eine Architektur vordefiniert, in der wesentliche<br />

Komponenten vorgefertigt sind, und diejenigen Stellen werden<br />

genau definiert, in denen das Framework mit Implementationen<br />

für ein spezielles System noch instanziiert werden muss/kann.<br />

.<br />

q Frameworks sind die grösstmöglich vorgefertigten Systemrohbauten<br />

q Frameworks sind meist typisch für ganze Anwendungsbereiche, zB.:<br />

– für interaktive Systeme mit GUIs – MFC (C++), JFC (JAVA)<br />

– für verteilte OO-Systeme – CORBA, DCOM<br />

iTec<br />

7


Einführung 11. Patterns und Frameworks<br />

Pattern Einordnung<br />

q Idiom<br />

Programmiermuster – wie in einer bestimmten Programmiersprache<br />

kleine Programmierprobleme gelöst werden.<br />

Beispiel in C/C++: wie man ein Feld durchläuft<br />

q Spezifischer Design<br />

ein spezifischer, persönlicher Design für ein bestimmtes Problem.<br />

Kann schlau sein, aber versucht nicht, allgemein anwendbar zu sein<br />

q Standard Design<br />

ein Design für ein bestimmtes Problem, der Allgemeinheit erlangt<br />

hat durch Wiederverwendung. Z.B. eine unternehmensweite Lösung<br />

für das Y2000-Problem<br />

q Design Pattern<br />

eine Lösung für eine ganze Klasse von ähnlichen Problemen. Meistens<br />

erst sichtbar nach längerer Anwendung von Standard-Designs.<br />

iTec<br />

8


Einführung 11. Patterns und Frameworks<br />

wie wird man ein guter Schachspieler?<br />

q lerne Regeln<br />

Figurenamen und –zugmöglichkeiten, Schachbrettgeometrie etc.<br />

q lerne Prinzipien<br />

relativer Figurenwert, strategischer Wert des Brettzentrums,<br />

Angriffsvermögen etc.<br />

q schliesslich und vor allem: lerne von Spielen der Meister<br />

Spielzüge und deren Anwendungssituationen: Muster (Patterns)<br />

es gibt hunderte von solchen Spielzügen/Strategien<br />

iTec<br />

9


Einführung 11. Patterns und Frameworks<br />

wie wird man ein guter Software-Designer?<br />

q lerne Regeln<br />

Algorithmen, Datenstrukturen, Programmiersprachen<br />

q lerne Prinzipien<br />

modulares Programmieren, objektorientiertes Programmieren<br />

q schliesslich und vor allem: lerne von SW-Designs der "Meister"<br />

Muster (Patterns) von allgemeinen Lösungen immer<br />

wiederkehrender Designprobleme<br />

iTec<br />

10


Einführung 11. Patterns und Frameworks<br />

Pattern Beispiel: Singleton<br />

q Absicht<br />

stellt sicher, daß von einer Klasse höchstens ein Objekt erzeugt<br />

wird, und stellt einen globalen Zugriff auf das Objekt bereit<br />

q Motivation<br />

in manchen Anwendungen dürfen einige Klassen nur eine<br />

Objektinstanz besitzen – z.B. ein Printer-Spooler Objekt, ein Firma<br />

Objekt, ein Windows Manager Objekt, ein Roboter Objekt mit<br />

Konfigurationsdaten zur Robotersteuerung, ein DB-Broker.<br />

Objekt in globaler Variablen<br />

keine Garantie für Einmaligkeit<br />

besser:<br />

lasse die Klasse selber ihren Konstruktor überwachen<br />

iTec<br />

11


Einführung 11. Patterns und Frameworks<br />

Beispiel: Singleton<br />

q Idee<br />

– verberge alle Konstruktoren nach aussen: mache sie private<br />

– biete eine neue Methode "instance" nach aussen an, die eine<br />

Referenz auf (das einzige) Objekt zurückgibt<br />

– diese Methode muss eine Klassenoperation sein (static)!<br />

warum?<br />

iTec<br />

12


Einführung 11. Patterns und Frameworks<br />

Beispiel: Singleton<br />

class Singleton {<br />

private static Singleton s = new Singleton();<br />

}<br />

private Singleton() { . . }<br />

public static Singleton Instance() { return s; }<br />

. . . //Attribute und Methoden<br />

das das Klassenattribut Klassenattribut sshält<br />

hält<br />

eine eine Referenz Referenz auf auf das das einzige einzige<br />

Objekt Objekt der der Klasse Klasse Singleton Singleton<br />

mindestens mindestens einen einen Konstruktor Konstruktor<br />

definieren definieren als als private: private:<br />

kein kein (öffentlicher) (öffentlicher) Default- Default-<br />

Konstruktor Konstruktor mehr mehr verfügbar verfügbar<br />

einzige einzige öffentliche öffentliche Zugriffsmethodmethode<br />

auf auf ein ein Singleton- Singleton-<br />

Zugriffs-<br />

Objekt: Objekt: ist ist Klassenmethode<br />

Klassenmethode<br />

Singleton s = Singleton.Instance();<br />

Benutzung: Benutzung: ssreferenziert referenziert das das<br />

einzige einzige Singleton-Objekt<br />

Singleton-Objekt<br />

iTec<br />

13


Einführung 11. Patterns und Frameworks<br />

Beispiel: Singleton (JAVA)<br />

class Singleton {<br />

private static Singleton s =<br />

new Singleton(99);<br />

private int i;<br />

private Singleton(int x) { i = x; }<br />

public static Singleton Instance() {<br />

return s;<br />

}<br />

public int getValue() { return i; }<br />

public void setValue(int x) { i = x; }<br />

}<br />

public class SingletonPattern {<br />

public static void main(String[] args) {<br />

Singleton s = Singleton.Instance();<br />

System.out.println(s.getValue());<br />

Singleton s2 = Singleton.Instance();<br />

s2.setValue(9);<br />

System.out.println(s.getValue());<br />

}<br />

}<br />

iTec<br />

Ausgabe: 99<br />

9<br />

14


Einführung 11. Patterns und Frameworks<br />

es gibt drei Pattern Typen<br />

1. Erzeugungsmuster (creational pattern)<br />

beschreiben Strukturen, die den Prozeß der Objekterzeugung<br />

enthalten. Das Anwendungsprogramm wird von der konkreten<br />

Realisation der Objekterzeugung entkoppelt. Es arbeitet auf<br />

einer höheren Abstraktionsebene und delegiert die Erzeugung<br />

der Objekte an die Erzeugungsstrukturen<br />

2. Strukturmuster (structural pattern)<br />

zeigen auf, auf welche Art und Weise Klassen bzw. Objekte zu<br />

größeren Strukturen zusammengefaßt werden können. Nahezu<br />

alle der vonStrukturmustern beschriebenen Strukturen<br />

entstehen zur Laufzeit, beruhen also auf der Technik der<br />

dynamischen Objektkomposition<br />

iTec<br />

15


Einführung 11. Patterns und Frameworks<br />

es gibt drei Pattern Typen<br />

3. Verhaltensmuster (behavioral patterns)<br />

beschreiben Strukturen, die am Kontrollfluß innerhalb der<br />

Anwendung beteiligt sind. Sie konzentrieren sich also auf<br />

Algorithmen und die Delegation von Zuständigkeiten.<br />

iTec<br />

16


Einführung 11. Patterns und Frameworks<br />

iTec<br />

17


Einführung 11. Patterns und Frameworks<br />

Vorteile von <strong>Entwurfsmuster</strong>n<br />

q Entwickler lernen schnell besseres Design<br />

q Entwickler werden produktiver<br />

q Qualität der Software wird besser<br />

q Kommunikation zwischen Entwicklern wird besser<br />

q Kommunikation bei der Wartung wird besser<br />

iTec<br />

18


Patternbeschreibung 11. Patterns und Frameworks<br />

q Name<br />

den wir als Kürzel für das Muster benutzen können, wenn wir uns darüber<br />

unterhalten.<br />

q Absicht kurze (1 – 2 Sätze) Beschreibung des Ziels des Patterns<br />

q Problem<br />

beschreibt die typische Situation, die eine neue Lösung erfordert. Oft<br />

wird hier ein ganz konkretes Problem beschrieben, anhand dessen das<br />

einzuführende Muster ausprobiert werden kann.<br />

q Lösungsidee<br />

skizziert, wie das Muster aussehen könnte, mit dem das im vorigen<br />

Abschnitt beschriebene Problem gelöst werden könnte.<br />

q Struktur<br />

wird in einem UML Diagramm angegeben, das die statische Struktur der<br />

beteiligten Klassen verdeutlicht.<br />

q Die Beteiligten<br />

iTec<br />

Hier werden die beteiligten Klassen noch einmal in Worten aufgezählt<br />

19<br />

und ihre Rollen ausführlicher beschrieben.


Patternbeschreibung 11. Patterns und Frameworks<br />

q Zusammenspiel<br />

erklärt die Kooperation zwischen den beteiligten Klassen. Dieser Abschnitt<br />

enthält oft auch ein (UML) Diagramm, in dem der Austausch von Nachrichten<br />

zwischen Objekten verdeutlicht wird.<br />

q Anwendbarkeit<br />

beschreibt Situationen, in denen das Muster sinnvoll eingesetzt werden kann,<br />

bzw. die Bedingungen, die gelten müssen, damit es eingesetzt werden kann.<br />

q Folgen<br />

beschreibt die Vor- und Nachteile, die dieses Muster mit sich bringt.<br />

q Implementation<br />

diskutiert Aspekte, die bei Implementation des Musters zu bedenken sind<br />

q Codebeispiele<br />

gibt konkrete Implementationen des Musters an anhand eines typischen<br />

Problems, in den wichtigsten OO-Sprachen (JAVA, C++)<br />

q Bekannte Anwendungen (bekannt!)<br />

q Verwandte Muster<br />

geht auf Beziehungen zwischen diversen Mustern ein; es ist selten so, daß<br />

eine Problemklasse nur durch ein einziges Muster allein entschärft wird.<br />

20<br />

iTec


Proxy 11. Patterns und Frameworks<br />

q Name<br />

Proxy<br />

q Absicht<br />

stelle ein Stellvertreter/Platzhalter für ein Objekt zur Verfügung, um<br />

über dieses Platzhalter-Objekt Zugriff auf das ursprüngliche Objekt<br />

zu garantieren<br />

q Problem<br />

manchmal ist die Erzeugung und Initialisierung eines Objektes<br />

aufwendig – grosse Datenmenge (z.B. Bilddaten), oder "entlegener"<br />

Ort wo das Objekt gespeichert ist (Netz, verteilte DB), oder grosse<br />

Anzahl von Objekten bei Initialisierung einer komplexen Anwendung<br />

q Lösungsidee verschiebe die Objektinitialisierung bis zum eigentlichen<br />

Gebrauch seitens des Verwenders (Klient), und stelle ihm solange nur<br />

ein Stellvertreterobjekt zur Verfügung (Schnittstelle mit den<br />

Operationen des eigentlichen Objekts).<br />

Der Klient soll den Proxy so sehen als ob er das richtige Objekt wäre.<br />

iTec<br />

21


Proxy 11. Patterns und Frameworks<br />

Struktur<br />

Klassendiagramm<br />

Klient<br />

Subjekt<br />

{abstract}<br />

operation()<br />

. . . ()<br />

iTec<br />

EchtesSubjekt<br />

operation()<br />

. . . ()<br />

Objektdiagramm<br />

einKlient:<br />

operation()<br />

vertritt<br />

einProxy:<br />

Proxy<br />

operation()<br />

. . . ()<br />

operation()<br />

operation() {<br />

vertritt.operation();<br />

}<br />

einEchtesSubjekt:<br />

22


Proxy 11. Patterns und Frameworks<br />

q Rollen<br />

Klient: greift auf ein Subjekt über ein Proxy zu, so als ob es<br />

ein EchtesSubjekt wäre. Er ist aber nur mit dem Proxy direkt<br />

verbunden (Referenz, Zeiger)<br />

Subjekt: stellt die gemeinsame Schnittstelle dar, sodass Proxy<br />

überall dort verwendet werden kann, wo eine EchtesSubjekt<br />

gebraucht wird. Hält meistens nur die Operationen (alle<br />

Attribute von EchtesSubjekt geschützt).<br />

Insbesondere stellt Subjekt sicher, dass Proxy und<br />

EchtesSubjekt gleich aussehen<br />

Proxy: ist der Ansprechpartner für Nachrichten eines<br />

Klients. Hält eine Referenz/Zeiger auf das EchteSubjekt, und<br />

ist verantwortlich für die Erzeugung (und evtl. Zerstörung) von<br />

EchtesSubjekt.<br />

iTec<br />

EchtesSubjekt:<br />

enthält die Daten und den Programmcode<br />

23


Proxy 11. Patterns und Frameworks<br />

Rollen (Fortsetzung)<br />

es gibt mehrere Typen von Proxy:<br />

q Remote-Proxy<br />

EchtesSubjekt (Objekte) befindet sich in einem anderen<br />

Adressraum (anderer Prozess, oder woanders im Netzwerk).<br />

Ein Remote -Proxy kodiert und schickt einen Request an<br />

EchtesSubjekt<br />

q Virtuelles Proxy<br />

erzeugt ein umfangreiches Objekt im gleichen Adressraum "auf<br />

Anfrage"<br />

q Schutz-Proxy<br />

kontrolliert den (geschützten) Zugriff auf EchtesSubjekt, z.B.<br />

über Zugriffsrechte<br />

iTec<br />

24


Proxy 11. Patterns und Frameworks<br />

Folgen<br />

q ein Remote-Proxy kann einem Klient verbergen, dass das angesprochene<br />

Objekt (EchtesSubjekt) in anderem Adressraum liegt<br />

q ein Virtuelles Proxy kann optimieren:<br />

– verzögerte Objektinitialisierung (vielleicht nie)<br />

– Lastausgleich bei initialisierungsintensiven Anwendungen<br />

q ein virtuelles Proxy kann selber einfache Daten halten<br />

iTec<br />

25


Proxy 11. Patterns und Frameworks<br />

iTec<br />

26


interface Subjekt {<br />

int getA();<br />

float getB();<br />

}<br />

class Proxy implements Subjekt {<br />

private EchtesSubjekt vertritt;<br />

// delegiere Methodenaufrufe an EchtesS:<br />

}<br />

Proxy 11. Patterns und Frameworks<br />

Beispiel in Java: virtueller Proxy<br />

public int getA() {<br />

iTec<br />

return getEchtesSubjekt().getA(); }<br />

public float getB() {<br />

return getEchtesSubjekt().getB(); }<br />

protected EchtesSubjekt getEchtesSubjekt() {<br />

if ( vertritt == null )<br />

vertritt = new EchtesSubjekt();<br />

return vertritt;<br />

}<br />

lazy lazy initialization<br />

class EchtesSubjekt implements Subjekt {<br />

protected int a;<br />

protected int b;<br />

public int getA() {<br />

System.out.println("EchtesSub.getA()");<br />

return a; }<br />

public float getB() {<br />

System.out.println(" EchtesSub.getB()");<br />

return b; }<br />

public EchtesSubjekt() {a=1; b=1;}<br />

}<br />

public class Klient {<br />

public static void main(String args[]) {<br />

Proxy p = new Proxy();<br />

System.out.println(" a: " + p.getA() );<br />

System.out.println(" b: " + p.getB() );<br />

}<br />

}<br />

27


Zustand/State 11. Patterns und Frameworks<br />

q Name<br />

Zustand/State<br />

q Absicht<br />

lass ein Objekt sein Verhalten ändern (Ausführung einer<br />

Operation) wenn sein interner Zustand sich ändert<br />

q Problem ein Objekt hat interne Zustände (Attributwerte), die<br />

einige seiner Operationen beeinflussen. z.B. Datei öffnen:<br />

Datei<br />

dateiname : String<br />

offen : boolean<br />

oeffnen()<br />

schliessen()<br />

weitereOp()<br />

Spezialisierung<br />

Datei<br />

dateiname : String<br />

oeffnen()<br />

schliessen()<br />

weitereOp()<br />

Problem: ein Dateiobjekt müsste<br />

seine Klasse wechseln können<br />

iTec<br />

OffeneDatei<br />

oeffnen()<br />

schliessen()<br />

GeschlosseneDatei<br />

oeffnen()<br />

schliessen()<br />

28


Zustand/State 11. Patterns und Frameworks<br />

q Lösungsidee<br />

lagere den zustandsabhängigen Teil aus der Klasse aus (eigene<br />

Klasse), implementiere in der Klasse nur den zustandsunabhängigen<br />

Teil, und delegiere zustandsabhängige Operationen an die<br />

ausgelagerte Klasse<br />

q Struktur<br />

operation() {<br />

state.opAbhängig();<br />

}<br />

KlasseMitZustand<br />

opAbhängig()<br />

opUnabhängig()<br />

1<br />

state<br />

Zustand<br />

{abstract}<br />

opAbhängig()<br />

ZustandA<br />

opAbhängig()<br />

ZustandB<br />

opAbhängig()<br />

. . .<br />

Zustandsänderung: - wie wird er geändert ?<br />

- wer bzw. wo wird ein Zustand geändert ?<br />

iTec<br />

29


Zustand/State 11. Patterns und Frameworks<br />

Rollen<br />

q KlasseMitZustand<br />

die eigentliche Klasse, die nur den zustandsunabhängigen Teil<br />

enthält (evtl. mit Operationen die den Zustand verändern). Sie<br />

hält eine Referenz auf den aktuellen Zustand, über die<br />

zustandsabhängige Operationen delegiert werden.<br />

q Zustand<br />

abstrakte Schnittstelle (Polymorphismus) für die delegierten,<br />

zustandsabhängigen Operationen<br />

q konkreter Zustand (ZustandA, ZustandB)<br />

implementieren die zustandsabhängigen Operationen<br />

iTec<br />

Zustandsänderungen:<br />

ersetze aktuell referenziertes Zustandsobjekt durch ein neues<br />

30


Zustand/State 11. Patterns und Frameworks<br />

Anwendbarkeit:<br />

1. wenn ein Objekt Operationen hat, deren Logik von einem<br />

Zustand des Objektes selber abhängt der sich zur Laufzeit<br />

ändern kann<br />

2. das Objekt wenig Zustände hat und die Zustandsübergänge<br />

selber einen einfache Zustandsübergangsgraphen besitzen<br />

3. falls 2 nicht erfüllt ist, empfiehlt sich eine Realisierung mit<br />

einem endlichen Zustandsautomat<br />

iTec<br />

31


Zustand/State 11. Patterns und Frameworks<br />

wenn man komplexe Zustandsübergänge hat, benutzt man vorzugsweise<br />

einen endlichen Zustandsautomaten:<br />

iTec<br />

Zustand<br />

z_i<br />

Zustand<br />

z_j<br />

Ereignis e_k<br />

/<br />

Aktion a_m<br />

im im Zustand z_j z_j führt führt<br />

das das Ereignis e_k e_k zum zum<br />

Folgezustand z_j z_j und und<br />

löst löst Akton Akton a_m a_m aus aus<br />

Zustand<br />

Ereignis<br />

e_1<br />

e_2<br />

. . .<br />

e_k<br />

. . .<br />

z_1 z_2 . . . z_i . . .<br />

(folgezustand,<br />

aktion)<br />

Darstellung in in einer einer<br />

Tabelle von von Paaren:<br />

(folgezustand,aktion)<br />

( z_j ,<br />

a_m )<br />

32


Zustand/State 11. Patterns und Frameworks<br />

ComplexClass<br />

...<br />

actState : State<br />

act : Action;<br />

... event1(..) {<br />

//operation op1 implements event 1<br />

actState = hasSTT.transit(actState,<br />

E1, act );<br />

switch (act) {<br />

case A1: action1(..); //execute action<br />

break;<br />

case A2: action2(..);<br />

. . .<br />

}<br />

event2(..)<br />

...<br />

action1(..) //action A1<br />

action2(..) //action A2<br />

. . .<br />

iTec<br />

hasSTT<br />

1..* 1<br />

stTable //state table<br />

StateTransitionTable<br />

create(ComplexClass cp) //loads table<br />

save()<br />

addState( State st )<br />

addEvent( Event ev )<br />

addTransition(State st1, State st2,<br />

Event ev, Action act)<br />

removeState(...)<br />

...<br />

State transit( State st, Event ev,<br />

Action &act)<br />

33


Zustand/State 11. Patterns und Frameworks<br />

Konsequenzen<br />

q es strukturiert das Objektverhalten nach Zuständen:<br />

– jede Zustandsklasse enthält die Zustandsbesonderheiten<br />

– leichter les- und vor allem wartbar<br />

q unterstützt Zustandsklassifizierung: Zustände sind manchmal<br />

klassifizierbar durch Super-/Subklassenbeziehungen<br />

q Zustände werden explizit gemacht<br />

iTec<br />

34


Beobachter/Observer 11. Patterns und Frameworks<br />

q Name: Beobachter (Observer)<br />

q Absicht<br />

Objekte können Daten bei einem Informationsanbieter<br />

abonnieren. Bei jeder Änderung der abonnierten Daten werden<br />

die Abonnenten automatisch über die Änderung informiert, die<br />

sich dann die geänderten Daten holen.<br />

q Problem<br />

voneinander abhängige Objekte sollen nicht zu stark aneinander<br />

gekoppelt werden, was Wiederverwendbarkeit einschränken<br />

würde.<br />

q Lösungsidee<br />

Trennung von Informationsbereitsteller und einer Menge von<br />

Informationsverarbeitern bzw. Darstellern der Information. Die<br />

Bereitsteller müssen die Verarbeiter nicht direkt kennen: statt<br />

direkter Kommunikation über Aufrufe benutze eine indirekte<br />

über Benachrichtigungen.<br />

iTec<br />

35


Beobachter/Observer 11. Patterns und Frameworks<br />

Struktur<br />

Subjekt<br />

{abstract}<br />

- beobachtetVon : ListOfBeobachter<br />

#benachrichtigen()<br />

+registrieren(beob:Beobachter)<br />

+löschen(beob:Beobachter)<br />

beobachtetVon ?<br />

1..* ? beobachtet<br />

für alle beo in beobachtetVon:<br />

beo.aktualisieren(. . . );<br />

*<br />

Beobachter<br />

{abstract}<br />

- beobachtet : Subjekt<br />

+aktualisieren(. . . )<br />

beobachtet.getMeineDaten();<br />

. . . //aktualisiere zustand<br />

Client<br />

setMeineDaten(x)<br />

MeinSubjekt<br />

-meineDaten : Data<br />

+getMeineDaten(): Data<br />

+setMeineDaten(d:Data)<br />

. . .<br />

. // bearbeite und<br />

. // aktualisiere<br />

. // meineDaten<br />

benachrichtigen();<br />

MeinBeobachter<br />

- zustand<br />

+aktualisieren(. . . )<br />

iTec<br />

36


Beobachter/Observer 11. Patterns und Frameworks<br />

Teilnehmer<br />

q Subjekt<br />

kennt seine Beobachter (beliebig viele) als abstrakte Beobachter;<br />

bietet Schnittstelle zur (Ent)Registrierung von Beobachtern;<br />

hat Operation zur Benachrichtigung registrierter Beobachter<br />

q Beobachter<br />

bietet einen Typ (abstrakte Klasse/Interface) der benachrichtigt<br />

werden kann von Subjekten<br />

q MeinSubjekt<br />

wird unabhängig von Beobachtern programmiert: hält aber Daten von<br />

denen Beobachter-Objekte abhängig sind;<br />

sendet (fast automatisch) Benachrichtigungen an Beobachter-Objekte<br />

wenn Daten sich ändern<br />

q MeinBeobachter<br />

ist abhängig und hält eine Referenz zu einem MeinSubjekt-Objekt;<br />

enthält Daten die mit Daten des Subjekts konsistent sein müssen;<br />

implementiert iTec die aktualisiere-Operation zur Benachrichtigung<br />

37


Beobachter/Observer 11. Patterns und Frameworks<br />

Zusammenspiel<br />

q jedes Objekt der Klasse Subjekt führt eine Liste von Beobachtern, welche<br />

an Veränderungen im Zustand dieses Objekts interessiert sind. registrieren<br />

bzw. loeschen fügt Beobachter in die Liste ein bzw. entfernt sie.<br />

q nach jeder Veränderung schickt das Subjekt sich selbst die Nachricht<br />

benachrichtigen. Diese iteriert die Liste der Beobachter und schickt jedem<br />

Beobachter die Nachricht aktualisieren. Ggf. können Informationen (z. B.<br />

die Art des eingetretenen Ereignisses, oder das benachrichtigende Objekt<br />

selber) als Parameter mitgegeben werden.<br />

q jeder benachrichtigte Beobachter reagiert, indem er beim benachrichtigenden<br />

Sujekt mit getXXX- Nachrichten die ihn interessierenden<br />

Informationen abruft.<br />

q alternativ können der aktualisiere-Nachricht die veränderten Daten gleich<br />

mitgegeben werden, wodurch der Abruf durch getXXX entfällt. Dieses<br />

"Bring"-Prinzip ist effizient, koppelt aber Subjekt und Beobachter stärker<br />

als das mit getXXX realisierte "Hol"-Prinzip.<br />

iTec<br />

38


Beobachter/Observer 11. Patterns und Frameworks<br />

Zusammenspiel<br />

setMeineDaten<br />

ms :MeinSubjekt<br />

registrieren<br />

mb<br />

registrieren<br />

db<br />

mb :MeinBeobachter<br />

db :DeinBeobachter<br />

benachrichtigen<br />

aktualisieren<br />

getMeineDaten<br />

Data<br />

aktualisieren<br />

getMeineDaten<br />

Data<br />

iTec<br />

39


Beobachter/Observer 11. Patterns und Frameworks<br />

Anwendbarkeit<br />

q wenn eine Änderung in einem Objekt Änderungen in anderen<br />

verlangt, und das erstere weiss zur Programmierzeit oder zum<br />

Systemstart nicht, welche anderen von ihm abhängen<br />

q wenn man also dynamische Abhängigkeiten hat<br />

q wenn man Abhängigkeiten in reinen Client/Server-Beziehungen<br />

modellieren möchte zwecks leichterer Änderbarkeit<br />

weiss von<br />

Clientklasse<br />

Serverklasse<br />

weiss nichts von<br />

iTec<br />

40


Beobachter/Observer 11. Patterns und Frameworks<br />

Folgen<br />

q schwache, einseitige Kopplung zwischen unabhängiger und<br />

abhängigen Klassen: erstere kennt nur eine abstrakte<br />

Schnittstelle zur Benachrichtigung<br />

q sauberer Design: Aktualisierungslogik im abhängigen Teil, nicht<br />

im bestimmenden (nur benachrichtigen, nicht aktualisieren)<br />

q dadurch können die beiden Klassentypen zu unterschiedlichen<br />

Systemebenen gehören (nächste Folie)<br />

q unterstützt eine Art Broadcasting<br />

iTec<br />

41


Beobachter/Observer 11. Patterns und Frameworks<br />

bekannte Anwendungen<br />

von Präsentationsschicht unabhängige Anwendungslogik<br />

Präsentationsschicht<br />

GUI-Komponenten GUI-Komponenten repräsentieren<br />

repräsentieren<br />

Daten Daten der der Anwendungslogikschicht<br />

Anwendungslogikschicht<br />

GUI-Komponente1<br />

GUI-Komponente2<br />

GUI-Komponente3<br />

Klasse1<br />

Anwendungslogikschicht<br />

Klasse2<br />

Klassen Klassen der der Anwendungslogikschicht<br />

Anwendungslogikschicht<br />

verarbeiten verarbeiten Daten, Daten, ohne ohne sie sie am am Bildschirschirm<br />

zu zu präsentieren<br />

Bild-<br />

präsentieren<br />

iTec<br />

Abhängigkeit<br />

42


Beobachter/Observer 11. Patterns und Frameworks<br />

Implementation<br />

q wann soll die Registrierung (Löschen) geschehen?<br />

meistens im Konstruktor (Destruktor) eines Beobachters<br />

q mehrere Subjekte: wie erkennen, welches Subjekt benachrichtigt?<br />

Parameter des Subjektes (this) bei Benachrichtigung übergeben<br />

q muss immer gleich aktualisiert werden?<br />

nein, man kann eine lazy-computing Technik einsetzen<br />

iTec<br />

43


Beobachter/Observer 11. Patterns und Frameworks<br />

lazy computing: erst dann berechnen, wenn Daten gebraucht werden<br />

Client<br />

getMeinAttribut()<br />

MeinBeobachter<br />

-meinAttribut: Typ //abhängiges Attr.<br />

-meinAttributStatus //valid/invalid<br />

+benachrichtige()<br />

+getMeinAttribut(): Typ<br />

void benachrichtige() {<br />

meinAttributStatus = invalid;<br />

}<br />

Typ getMeinAttribut() {<br />

if (meinAttributStatus == invalid)<br />

{<br />

beobachtet.getMeineDaten();<br />

. . . //Neuberechnung von meinAttribut<br />

meinAttributStatus = valid;<br />

}<br />

return meinAttribut; }<br />

iTec<br />

Vorteil:<br />

weniger Berechnungen, falls Subjekt<br />

wesentlich öfter benachrichtigt als<br />

Beobachter befragt wird<br />

44


Beobachter/Observer<br />

public class MeinSubjekt<br />

extends Subjekt {<br />

private int wert;<br />

public MeinSubjekt( int wert ) {<br />

this.wert = wert;<br />

}<br />

public void setWert( int wert )<br />

{<br />

this.wert = wert;<br />

benachrichtigen();<br />

}<br />

public int getWert() {<br />

return wert;<br />

}<br />

}<br />

iTec<br />

4. Patterns und Frameworks<br />

public abstract class Subje kt {<br />

}<br />

private Beobachter[] beobachtetVon =<br />

new Beobachter[MAXB];<br />

private int anzBeobachter = 0;<br />

public void registrieren( Beobachter beob ) {<br />

beobachtetVon[ anzBeobachter++] = beob;<br />

}<br />

public void löschen( Beobachter beob ) {<br />

for ( int i = 0; i < anzBeobachter; ++i ) {<br />

if (beobachtetVon[i] == beob) {<br />

- - observerCnt;<br />

for ( ; i < anzBeobachter; ++i)<br />

beobachtetVon[ i ] = beobachtetVon[ i + 1 ];<br />

break;<br />

}<br />

}<br />

}<br />

public void benachrichtigen() {<br />

for (int i = 0; i < anzBeobachter; ++i)<br />

beobachtetVon[i].aktualisieren( this );<br />

}<br />

45


Beobachter/Observer 11. Patterns und Frameworks<br />

interface Beobachter {<br />

public void aktualisieren( Subje kt subjekt );<br />

}<br />

public class MeinBeobachter<br />

implements Beobachter {<br />

int abhgWert; //abhängiger Wert<br />

public class Anwendung {<br />

public static void main( String[] args )<br />

MeinSubjekt sub = new MeinSubjekt( 99 );<br />

MeinBeobachter beo =<br />

new MeinBeobachter( sub );<br />

}<br />

public MeinBeobachter( Subjekt subjekt ) {<br />

abhgWert = subjekt.getWert() / 2;<br />

subjekt.registrieren( this );<br />

}<br />

public void aktualisieren( Subjekt subjekt ) {<br />

abhgWert = subjekt.getWert() / 2;<br />

//zum Beispiel<br />

}<br />

public int getAbhgWert() {<br />

return abhgWert;<br />

}<br />

iTec<br />

}<br />

}<br />

sub.setWert( 2 );<br />

System.out.println( "abhgWert: " +<br />

beo.getAbhgWert() );<br />

hier hier wird wird im im Hintergrund der der<br />

abhängige Wert Wert von von<br />

MeinBeobachter aktualisiert.<br />

Ausgabe: abhgWert: 11<br />

46


Adapter 11. Patterns und Frameworks<br />

q Name: Adapter<br />

q Absicht<br />

erlaubt die Zusammenarbeit von Klassen die unterschiedliche Schnittstellen<br />

haben. Adapter wird als verbindendes Element zwischen die<br />

beiden Klassen eingefügt.<br />

q Problem<br />

Schnittstellenproblem: eine Klasse "Verwender" (Klient) soll eine andere<br />

Klasse "Dienstanbieter" (Ziel) verwenden. Der Verwender kann jedoch<br />

auf den Dienstanbieter nicht zugreifen, da der Verwender eine andere<br />

Schnittstelle erwartet als die, die vom Dienstanbieter angeboten wird.<br />

q Lösungsidee<br />

Der Dienstanbieter wird in einen Adapter eingepackt. Der Adapter<br />

bietet die Schnittstelle an, die der Verwender benötigt.<br />

Dazu gibt es zwei Varianten:<br />

• Objektadapter<br />

• Klassenadapter<br />

iTec<br />

Adapter<br />

47


Adapter 11. Patterns und Frameworks<br />

Struktur: Objektadapter<br />

Klient<br />

benutzt<br />

Ziel<br />

operation()<br />

adaptiert<br />

AdaptierteKlasse<br />

spezifischeOperation()<br />

Adapter<br />

operation()<br />

operation()<br />

. . .<br />

adaptiert.spezifischeOperation()<br />

. . .<br />

Adaption:<br />

q andere Operationensignatur – Operations- und Parameternamen,<br />

Parametertypen und -reihenfolge<br />

q andere Operationsfunktionen – ähnliche, aber nicht genau gleiche<br />

48<br />

iTec<br />

Semantik


Adapter 11. Patterns und Frameworks<br />

Adapter Beispiel:<br />

ein Zeicheneditor mit fremder Komponente TextAnzeige<br />

1 manipuliert *<br />

Zeicheneditor<br />

zeichne()<br />

begrenzungsrahmen()<br />

GraphischesObjekt<br />

{abstract}<br />

begrenzungsRahmen()<br />

zeichne()<br />

TextAnzeige<br />

getUrsprung()<br />

getHoehe()<br />

getBreite()<br />

zeigMich()<br />

Linie<br />

begrenzungsRahmen()<br />

zeichne()<br />

Kreis<br />

begrenzungsRahmen()<br />

zeichne()<br />

iTec<br />

TextAnzeige passt nicht zu GraphischesObjekt:<br />

Problem für den Zeicheneditor<br />

49


Adapter 11. Patterns und Frameworks<br />

Adapter Beispiel: ein Zeicheneditor<br />

mit fremder Komponente TextAnzeige<br />

1 manipuliert *<br />

Zeicheneditor<br />

zeichne()<br />

begrenzungsrahmen()<br />

GraphischesObjekt<br />

{abstract}<br />

begrenzungsrahmen()<br />

zeichne()<br />

einseitige Beziehung:<br />

TextAnzeige auch auch ohne ohne<br />

Quellcode verwendbar<br />

1<br />

text<br />

TextAnzeige<br />

getUrsprung()<br />

getHoehe()<br />

getBreite()<br />

zeigMich()<br />

Linie<br />

begrenzungsrahmen()<br />

zeichne()<br />

Kreis<br />

begrenzungsrahmen()<br />

zeichne()<br />

Text<br />

begrenzungsrahmen()<br />

zeichne()<br />

1<br />

iTec<br />

begrenzungsrahmen()<br />

text.getHoehe()<br />

text.getBreite()<br />

. . .<br />

zeichne()<br />

. . .<br />

text.zeigMich()<br />

. . .<br />

50


Adapter 11. Patterns und Frameworks<br />

Struktur: Klassenadapter<br />

Klient<br />

Ziel<br />

operation()<br />

AdaptierteKlasse<br />

spezifischeOperation()<br />

Adapter<br />

operation()<br />

benutzt Mehrfachvererbung<br />

operation()<br />

. . .<br />

spezifischeOperation()<br />

. . .<br />

iTec<br />

51


Adapter 11. Patterns und Frameworks<br />

Folgen<br />

q Klassenadapter<br />

benutzt nur eine Objekt, während Objektadapter aus zwei<br />

bestehen<br />

q Objektadapter<br />

kann auch Objekte von Unterklassen der adaptierten Klasse<br />

adaptieren, was der Klassenadapter nicht kann<br />

iTec<br />

52


Adapter 11. Patterns und Frameworks<br />

Implementation in JAVA: Objektadapter mit einem Interface<br />

class WasIchHabe {<br />

public void g() {}<br />

public void h() {}<br />

}<br />

interface WasIchMoechte {<br />

void f();<br />

}<br />

class WasIchBenutze {<br />

public void op(WasIchMoechte wim) {<br />

wim.f();<br />

}<br />

}<br />

class Adapter implements WasIchMoechte {<br />

//Referenz auf was adaptiert werden soll<br />

private WasIchHabe wasichhabe;<br />

//Konstruktor verbindet Adapter mit WasIchHabe<br />

public Adapter(WasIchHabe wih) {<br />

wasichhabe = wih;<br />

}<br />

public void f() {<br />

// Implementiert Methode mit den<br />

// Methoden in WasIchHabe:<br />

wasichhabe.g();<br />

wasichhabe.h();<br />

}<br />

}<br />

WasIchBenutze WasIchMoechte WasIchHabe<br />

iTec<br />

Adapter<br />

53


Kompositum 11. Patterns und Frameworks<br />

Zweck<br />

Füge Objekte zu Baumstrukturen zusammen, um Teil-Ganzes-<br />

Hierarchien zu repräsentieren.<br />

Das Kompositionsmuster ermöglicht es dem Klienten (Benutzer<br />

dieses Musters), sowohl einzelne Objekte als auch Kompositionen<br />

von Objekten einheitlich zu behandeln.<br />

Motivation<br />

viel verwendet in Grafik-Anwendungen<br />

und im Produktionsbereich (Produktbäume)<br />

iTec<br />

54


Kompositum 11. Patterns und Frameworks<br />

Beispiel:<br />

Grafikanwendung<br />

Grafik<br />

zeichne()<br />

hinzufügen(Grafik)<br />

entfernen(Grafik)<br />

holeNächstesKind()<br />

{abstract}<br />

*<br />

enthält<br />

iTec<br />

Linie<br />

zeichne()<br />

Rechteck Text<br />

zeichne() zeichne()<br />

für für alle alle g in in "enthält":<br />

g.zeichne();<br />

Bild<br />

zeichne() //Delegation!!<br />

hinzufügen(Grafik g)<br />

entfernen(Grafik)<br />

holeNächstesKind()<br />

füge füge g g ein ein in in<br />

"enthält" "enthält"<br />

55


Kompositum 11. Patterns und Frameworks<br />

iTec<br />

56


Kompositum 11. Patterns und Frameworks<br />

Komponente<br />

• Deklariert die Schnittstelle für Objekte in der zusammengefügten Struktur.<br />

• Implementiert, sofern angebracht, ein Defaultverhalten für die allen Klassen gemeinsame<br />

Schnittstelle (ist in JAVA dann abstrakte Klasse).<br />

• Deklariert eine Schnittstelle zum Zugriff auf und zur Verwaltung von Kindobjekten.<br />

• Definiert optional eine Schnittstelle zum Zugriff auf das Elternobjekt einer Komponente<br />

innerhalb der rekursiven Struktur und implementiert sie, falls dies angebracht erscheint.<br />

Blatt<br />

• Repräsentiert Blattobjekte in der Komposition. Ein Blatt besitzt keine Kindobjekte.<br />

• Definiert Verhalten für die primitiven Objekte in der Komposition.<br />

Kompositum<br />

• Definiert Verhalten für Komponenten, die Kindobjekte haben können.<br />

• Speichert Kindobjektkomponenten.<br />

• Implementiert kindobjekt-bezogene Operationen der Schnittstelle von Komponente.<br />

Klient<br />

Rollen<br />

57<br />

• Manipuliert iTec die Objekte in der Komposition durch die Schnittstelle von Komponente.


Kompositum 11. Patterns und Frameworks<br />

Verwendung<br />

Verwende das Kompositionsmuster, wenn<br />

• Teil-Ganzes-Hierarchien von Objekten repräsentiert werden sollen<br />

• KKKlienten in der Lage sein sollen, die Unterschiede zwischen<br />

zusammengesetzten und einzelnen Objekten zu ignorieren.<br />

Klienten behandeln alle Objekte in der zusammengesetzten Struktur<br />

einheitlich.<br />

iTec<br />

58


Singleton/Kompositum 11. Patterns und Frameworks<br />

Beispiel<br />

ein binärer Suchbaum: Entwurf als Kompositum und mit leerem<br />

Baum als Singleton<br />

q gewünscht: eine Klasse eines binären Suchbaums, dessen<br />

Objekte auch leer sein können: Binärbaum ohne Elemente<br />

q Anforderung: der leere Baum muss genauso ansprechbar sein<br />

wie ein nichtleerer binärer Suchbaum: also mit Operationen<br />

– isEmpty(), isIn(Object o), insert(Object o)<br />

q ein leerer Baum kann also nicht als Nullreferenz realisiert<br />

werden !<br />

iTec<br />

59


Singleton/Kompositum 11. Patterns und Frameworks<br />

ein binärer Suchbaum:<br />

Entwurf als Kompositum<br />

und mit leerem Baum<br />

als Singleton<br />

«Interface»<br />

BinSearchTree<br />

isEmpty(): boolean<br />

isIn(Object o): boolean<br />

insert(Object o): BinSearchTree<br />

0..2<br />

hasFather<br />

hasChild<br />

iTec<br />

«Singleton»<br />

EmptyTree<br />

empty: EmptyTree<br />

isEmpty(): boolean<br />

isIn(Object o): boolean<br />

insert(Object o): BinSearchTree<br />

Node<br />

info: Object<br />

leftChild: BinSearchTree<br />

rightChild: BinSearchTree<br />

isEmpty(): boolean<br />

isIn(Object o): boolean<br />

insert(Object o): BinSearchTree<br />

0..1<br />

60


Singleton/Kompositum 11. Patterns und Frameworks<br />

ein binärer Suchbaum: Entwurf als Kompositum und mit leerem<br />

Baum als Singleton<br />

:ClientClass<br />

empty:EmptyTree<br />

b =<br />

EmptyTree.Instance()<br />

Instance()<br />

b = b.insert(o1)<br />

b = b.insert(o2)<br />

b = b.insert(o3)<br />

insert(o1)<br />

insert(o2)<br />

insert(o3)<br />

new(o1)<br />

b:Node<br />

{b.info < o1}<br />

{b.info > o2}<br />

new(o2)<br />

new(o3)<br />

b.leftChild:Node<br />

b.rightChild:Node<br />

iTec<br />

61


Singleton/Kompositum 11. Patterns und Frameworks<br />

ein binärer Suchbaum:<br />

JAVA Code<br />

einzige einzige Instanz Instanz als als<br />

Klassenattribut<br />

Klassenattribut<br />

alle alle Konstruktoren<br />

Konstruktoren<br />

sind sind damit damit privat privat<br />

public interface BinSearchTree {<br />

boolean isEmpty();<br />

boolean isIn(Object e);<br />

BinSearchTree insert(Object e);<br />

}<br />

//----------------------------------------------------------------<br />

public class EmptyTree implements BinSearchTree {<br />

private static EmptyTree empty = new EmptyTree();<br />

private EmptyTree() {}<br />

Benutzung: Benutzung:<br />

Instance() Instance() als als "Konstruktor"<br />

"Konstruktor"<br />

gibt gibt einziges einziges empty empty als als<br />

EmptyTree-Objekt EmptyTree-Objekt heraus heraus<br />

hier hier wird wird aus aus dem dem einzigen einzigen<br />

EmptyTree-Objekt EmptyTree-Objekt jeweils jeweils<br />

ein ein neuer neuer Baum Baum erzeugt erzeugt der der<br />

nur nur aus<br />

iTec aus einer einer Wurzel Wurzel besteht besteht<br />

public static EmptyTree Instance() {<br />

return empty;<br />

}<br />

public boolean isEmpty() { return true; }<br />

public boolean isIn(Object e) { return false; }<br />

public BinSearchTree insert(Object e) {<br />

return new Node(e);<br />

}<br />

}<br />

62


Singleton/Kompositum 11. Patterns und Frameworks<br />

public class Node implements BinSearchTree {<br />

protected Object info;<br />

protected BinSearchTree left;<br />

protected BinSearchTree right;<br />

public Node(Object info) {<br />

}<br />

this.info = info;<br />

left = EmptyTree.Instance();<br />

right = EmptyTree.Instance();<br />

public boolean isEmpty() { return false; }<br />

public boolean isIn(Object e) {<br />

switch ( info.compareTo(e) ) {<br />

case -1: return left.isIn(e);<br />

case 0: return true;<br />

case +1: return right.isIn(e);<br />

}<br />

return false;<br />

} iTec<br />

Kompositum: Kompositum:<br />

füge füge leere leere Bäume Bäume<br />

als als Blätter Blätter ein ein<br />

public BinSearchTree insert(Object e) {<br />

switch ( info.compareTo(e) ) {<br />

case -1:<br />

left = left.insert(e);<br />

break;<br />

case 0: break;<br />

case +1:<br />

right = right.insert(e);<br />

break;<br />

}<br />

return this;<br />

}<br />

}<br />

63


Singleton/Kompositum 11. Patterns und Frameworks<br />

Benutzung des binären Suchbaumes<br />

public static void main( String args[ ] ) {<br />

}<br />

BinSearchTree tree = EmptyTree.Instance();<br />

tree = readTree( tree, "dateiname" );<br />

. . .<br />

public BinSearchTree readTree( BinSearchTree bst, String datei ) {<br />

int wert;<br />

// in einer Schleife werte einlesen<br />

. . .<br />

bst = bst.insert( Integer(wert) ); Achtung: Achtung: falls falls ein ein leerer leerer Baum Baum<br />

. . .<br />

unser unser Binärbaum Binärbaum<br />

} hat hat allgemeine allgemeine<br />

Knoten, Knoten, die die Informationen Informationen vom vom<br />

Typ Typ Object Object halten halten (keine (keine Templates!) Templates!)<br />

Deshalb: Deshalb: Wrapperklasse Wrapperklasse um um den den<br />

Integerwert! Integerwert!<br />

iTec<br />

übergeben übergeben wird, wird, ändert ändert sich sich<br />

die die Objektreferenz Objektreferenz durch durch die die<br />

Einfügung Einfügung des des ersten ersten Knotens Knotens<br />

64


Kompositum 11. Patterns und Frameworks<br />

wichtig beim Kompositum ist die Unterscheidung von Klassen- und<br />

Objektbäumen – das Kompositum generiert Objektbäume<br />

Klasse1<br />

objA<br />

Klasse11<br />

Klasse12<br />

objB<br />

objC<br />

objD<br />

objE<br />

objF<br />

Klasse121<br />

Klasse122<br />

q Klassenbäume sind statische Vererbungshierarchien<br />

q Objektbäume sind dynamisch erzeugte Bäume mit Knotenobjekten<br />

iTec<br />

65


Dekorierer 11. Patterns und Frameworks<br />

q Name: Dekorierer (decorator oder wrapper)<br />

q Absicht: füge einem Objekt dynamisch Zusatzfunktionalität hinzu<br />

q Problem: wenn man zu einer Basisfunktionalität wie Grafikdarstellung<br />

oder einer Ein-/Ausgabe vielfache Zusatzfunktionalität wie<br />

in einem Baukasten frei kombinierbar hinzufügen möchte, ergibt<br />

sich rasch eine kombinatorische Vielfalt, die man nur noch schwer in<br />

einer statischen Klassenstruktur darstellen und warten kann.<br />

q Lösungsidee: kombiniere die Zusatzfunktionalität dynamisch in einer<br />

Umhüllung in mehreren Schichten (Wrapper) um das ursprüngliche<br />

Objekt herum. Jede Hülle (Dekoriererklasse) kann genauso<br />

angesprochen werden wie das ursprüngliche Objekt<br />

iTec<br />

66


Dekorierer 11. Patterns und Frameworks<br />

Struktur<br />

Komponente<br />

{abstract}<br />

+operation()<br />

1<br />

KonkreteKomponente<br />

Dekorierer<br />

hatKomponente<br />

{abstract}<br />

+operation()<br />

+operation()<br />

operation() {<br />

zusatzoperationA();<br />

//sende operation weiter:<br />

hatKomponente.operation();<br />

}<br />

KonkreterDekoriererA<br />

+operation()<br />

#zusatzOperationA()<br />

KonkreterDekoriererB<br />

+operation()<br />

#zusatzOperationB()<br />

. . .<br />

iTec<br />

67


Dekorierer 11. Patterns und Frameworks<br />

Rollen<br />

q Komponente:<br />

die Schnittstelle für einen Klienten zum Gebrauch eines<br />

dekorierten Objektes<br />

q KonkreteKomponente:<br />

Objekt, das eine Basisfunktionalität bereitstellt welche mit<br />

Zusatzfunktionalität dekoriert werden kann<br />

q Dekorierer:<br />

enthält eine Referenz zu einer weiteren Komponente auf der<br />

die Operation weitergesandt wird<br />

q KonkreterDekorierer:<br />

fügt Zusatzfunktionalität zur Operation der<br />

KonkretenKomponente hinzu (dekoriert)<br />

iTec<br />

68


Dekorierer 11. Patterns und Frameworks<br />

Zusammenspiel<br />

dA:KonkreterDekoriererA<br />

hatKomponente<br />

dB:KonkreterDekoriererB<br />

hatKomponente<br />

kp:KonkreteKomponente<br />

operation()<br />

zusatzOperationA()<br />

operation()<br />

zusatzOperationB()<br />

operation()<br />

iTec<br />

69


Dekorierer 11. Patterns und Frameworks<br />

Beispiel<br />

. . .<br />

/*display text*/<br />

. . .<br />

Component<br />

{abstract}<br />

+draw()<br />

1<br />

hasComponent<br />

TextView<br />

+draw()<br />

Decorator<br />

{abstract}<br />

+draw()<br />

hasComponent. draw()<br />

scrollDraw()<br />

hasComponent. draw()<br />

borderDraw()<br />

BorderDecorator<br />

+draw()<br />

#borderDraw()<br />

ScrollDecorator<br />

+draw()<br />

#scrollDraw()<br />

BW 1<br />

:BorderDecorator<br />

SW 1<br />

:ScrollDecorator<br />

T 1<br />

:TextView<br />

draw()<br />

iTec<br />

draw()<br />

draw()<br />

70


Dekorierer 11. Patterns und Frameworks<br />

Konsequenzen<br />

q die Verbindung der Komponenten über hatKomponente wird im<br />

Konstruktor erzeugt:<br />

KonkreteKomponente kp<br />

= new KonkreteKomponente();<br />

KonkreterDekoriererA kdA = new KonkreterDekoriererA( kp ); //kdA mit kp verbunden<br />

KonkreterDekoriererB kdB = new KonkreterDekoriererB( kdA ); //kdB " kdA "<br />

. . .<br />

kdB.operation();<br />

oder:<br />

KonkreterDekoriererB kdB = new KonkreterDekoriererB(<br />

iTec<br />

KonkreterDekoriererB<br />

KonkreterDekoriererA<br />

KonkréteKomponente<br />

new KonkreterDekoriererA(<br />

new KonkreteKomponente( ) ) );<br />

71


Dekorierer 11. Patterns und Frameworks<br />

Konsequenzen<br />

q das Muster erlaubt, alle Kombinationen von Zusatzfunktionalität<br />

in einer einfachen Klassenstruktur zu beschreiben.<br />

Eine explizite Beschreibung wäre sehr aufwendig.<br />

q es ist einfach, neue Zusatzfunktionalität einzufügen<br />

q Nachteil: das vom Klienten angesprochene Objekt ist ein<br />

Dekorierer, nicht das Hauptobjekt (KonkreteKomponente):<br />

alle Dekorierer müssen sämtliche Operationen des Hauptobjekts<br />

anbieten, auch wenn sie diese nicht dekorieren<br />

iTec<br />

allerdings können diese Operationen für alle Konkreten-<br />

Dekorierer in der (abstrakten) Superklasse Dekorierer mit<br />

einfacher Delegation an das Hauptobjekt implementiert werden<br />

(siehe nächste Folie)<br />

72


Dekorierer 11. Patterns und Frameworks<br />

nichtdekorierte Operationen<br />

werden einfach zur<br />

KonkretenKomponente<br />

durchgereicht<br />

Komponente<br />

{abstract}<br />

+operation1()<br />

+operation2()<br />

+operation3()<br />

1<br />

hatKomponente<br />

KonkreteKomponente<br />

+operation1()<br />

+operation2()<br />

+operation3()<br />

Dekorierer<br />

+operation1()<br />

+operation2()<br />

+operation3()<br />

{abstract}<br />

operation2() {<br />

hatKomponente.operation2();<br />

}<br />

operation3() {<br />

hatKomponente.operation3();<br />

}<br />

operation1() {<br />

zusatzoperationA();<br />

//sende operation weiter:<br />

hatKomponente.operation1();<br />

}<br />

iTec<br />

KonkreterDekoriererA<br />

+operation()<br />

#zusatzOperationA()<br />

KonkreterDekoriererB<br />

+operation()<br />

#zusatzOperationB()<br />

. . .<br />

73


Dekorierer 11. Patterns und Frameworks<br />

Zusammenspiel: Durchreichen nichtdekorierter Operationen<br />

dA:KonkreterDekoriererA<br />

hatKomponente<br />

dB:KonkreterDekoriererB<br />

hatKomponente<br />

kp:KonkreteKomponente<br />

operation3()<br />

operation3()<br />

operation3()<br />

iTec<br />

74


Objektfabriken 11. Patterns und Frameworks<br />

Problem:<br />

Polymorphismus in Vererbungshierarchien:<br />

man kann Spezialisierungen<br />

polymorph benutzen, und neue<br />

Spezialisierungen verlangen keine<br />

Änderung bei der Benutzung: schön!<br />

pPZ<br />

alles wird zu Polygon<br />

. . .<br />

void optimiereLayout( Polygon[] pP, int anzahl) {<br />

. . .<br />

for ( i=0; i < anzahl; i++ ) {<br />

f[i] = pP[i].berechneFlaeche();<br />

. . .<br />

pP[i].verschieben(dx, dy);<br />

pP[i].fuellen( rot );<br />

}<br />

. . .<br />

Aber:<br />

irgendwo muss man die Objekte<br />

erzeugen - und da muss man<br />

konkret werden. Diese Erzeugungen<br />

können weit verstreut sein - eine<br />

Änderung wird aufwendig und<br />

fehleranfällig<br />

iTec<br />

Polygon[] pPZ;<br />

. . .<br />

pPZ[k++] = new Dreieck(p1,p2,p3);<br />

. . .<br />

pPZ[k++] = new Rechteck(lo, ru);<br />

. . .<br />

pPZ[k++] = new Polygon(parray);<br />

. . .<br />

optimiereLayout( pPZ, k ) ;<br />

Änderungswunsch:<br />

Änderungswunsch:<br />

DreieckMitGrafik(<br />

DreieckMitGrafik(<br />

p1, p1, p2, p2, p3 p3 ))<br />

75


Objektfabriken 11. Patterns und Frameworks<br />

Lösungsidee:<br />

kann man nicht auch die Erzeugung kapseln - und dann sogar<br />

polymorph gestalten?<br />

Antwort:<br />

ja, und zwar in einer "Objekterzeugungsfabrik" - Object Factory<br />

erzeuge (gewünschtesObjekt )<br />

Objektfabrik<br />

neues Objekt<br />

erzeuge( Dreieck)<br />

FigurenFabrik<br />

neues Dreieck<br />

Fabrikmuster sind sind<br />

Erzeugungsmuster<br />

iTec<br />

new DreieckMitGrafik(...)<br />

76


Objektfabriken 11. Patterns und Frameworks<br />

abstract class Figur {<br />

public abstract void zeichne();<br />

public abstract void lösche();<br />

}<br />

public static Figur fabrik( String typ )<br />

throws FalscheFigurenErzeugung {<br />

if ( typ.equals("Kreis") ) return new Kreis();<br />

if ( typ.equals("Rechteck") ) return new Rechteck();<br />

throw new FalscheFigurenErzeugung( typ );<br />

}<br />

class Kreis extends Figur {<br />

Kreis() {} //Konstruktor mit Paketsichtbarkeit<br />

public void zeichne() {<br />

System.out.println("Kreis.zeichne");<br />

}<br />

public void lösche() {<br />

System.out.println("Kreis.loesche");<br />

}<br />

}<br />

class Rechteck extends Figur { . . .<br />

iTec<br />

1. Schritt:<br />

wie man die Erzeugung<br />

von Objekten kapselt<br />

77


Objektfabriken 11. Patterns und Frameworks<br />

public class FigurenFabrik1 {<br />

String figlist[] = { "Kreis", "Rechteck",<br />

"Rechteck", "Kreis", "Kreis", "Rechteck" };<br />

List figuren = new ArrayList();<br />

public void test() {<br />

try {<br />

for( int i = 0; i < figlist.length; i++)<br />

figuren.add( Figur.fabrik( figlist[i] ) );<br />

} catch( FalscheFigurenErzeugung e ) {<br />

System.out.println( e.getMessage() );<br />

}<br />

Iterator figIt = figuren.iterator();<br />

while( figIt.hasNext() ) {<br />

Figur f = (Figur)figIt.next();<br />

f.zeichne();<br />

f.lösche();<br />

}<br />

}<br />

public static void main(String args[]) {<br />

new FigurenFabrik1().test();<br />

}<br />

}<br />

iTec<br />

78


Objektfabriken 11. Patterns und Frameworks<br />

2. Schritt: wie man eine polymorphe Erzeugung bereitstellt:<br />

das Fabrikmuster<br />

Abhängigkeit (UML)<br />

abstrakte Produkt Meu fabrik(. fabrik(. . .) .{<br />

.) {<br />

abstrakte Klasse: Klasse:<br />

Product return return create(. create(. ...);<br />

Product fabrik(..) fabrik(..)<br />

.);<br />

nicht }<br />

nicht implementiert implementiert<br />

}<br />

Produkt<br />

operation1(..)<br />

operation2(..)<br />

. . .<br />

(Name)<br />

ProduktFabrik<br />

create(. . .): Produkt<br />

fabrik( . . . ): Produkt<br />

fabrik(..)<br />

Klient<br />

KonkretesProdukt<br />

KonkretesProdukt(..)<br />

operation1(..)<br />

operation2(..)<br />

. . .<br />

iTec<br />

(Konstruktor)<br />

KonkretesProduktFabrik<br />

create(. . .): Produkt<br />

Eine Anwendung benutzt die Produktfabrik, um<br />

Objekte zu erzeugen. Die KonkreteProduktFabrik<br />

erzeugt ein KonkretesProdukt, dessen Klasse für die<br />

Anwendung transparent ausgetauscht werden kann.<br />

79


Objektfabriken 11. Patterns und Frameworks<br />

Fabrik-Beispiel: eine Menufabrik<br />

Menu<br />

addOption(option:String)<br />

removeOption(option:String)<br />

select(): String<br />

. . .<br />

Menu Menu fabrik(String fabrik(String titel) titel) {{<br />

return return create(titel); create(titel);<br />

}}<br />

Menufabrik<br />

create(titel:String): Menu<br />

fabrik(titel:String): Menu<br />

iTec<br />

KonsoleMenu<br />

addOption(option:String)<br />

removeOption(<br />

option:String)<br />

select(): String<br />

. . .<br />

AWTMenu<br />

. . .<br />

KonsoleMenufabrik<br />

create(titel:String):<br />

Menu<br />

AWTMenufabrik<br />

create(titel:String):<br />

Menu<br />

80


Objektfabriken 11. Patterns und Frameworks<br />

das Fabrikmuster kapselt die Erzeugung von Objekten einer Klasse.<br />

Häufig sind aber Objekte mehrerer zusammenhängender Klassen in<br />

einer Fabrik zu erzeugen.<br />

das AbstrakteFabrik Muster<br />

erzeuge (gewünschtesObjekt1 )<br />

Objekt1fabrik<br />

neues Objekt1<br />

gemeinsame Basis<br />

(z.B. graphische Menuelemente ein<br />

bestimmtes Betriebssystem)<br />

erzeuge (gewünschtesObjekt2 )<br />

Objekt2fabrik<br />

neues Objekt2<br />

iTec<br />

81


Objektfabriken 11. Patterns und Frameworks<br />

AbstrakteFabrik: die Struktur<br />

iTec<br />

82


Objektfabriken 11. Patterns und Frameworks<br />

Anwendbarkeit von Abstrakten Fabriken<br />

q wenn man eine Anwendung braucht, die von der Erzeugung<br />

ihrer "Produkte" und deren Komposition/Aggregation<br />

unabhängig sein soll<br />

q wenn man Produktfamilien hat<br />

q im Design von Klassenbibliotheken<br />

da Polymorphismus einer der Pfeiler des objektorientierten Ansatzes ist,<br />

und eine polymorphe Objekterzeugung das Gegenstück zu polymorpher<br />

Benutzung von Objekten ist, ist das Fabrikmuster eines der am<br />

weitesten verbreiteten überhaupt!<br />

iTec<br />

83

Hurra! Ihre Datei wurde hochgeladen und ist bereit für die Veröffentlichung.

Erfolgreich gespeichert!

Leider ist etwas schief gelaufen!