Software Engineering Entwurfsmuster (update: 11.6.) Prof. Adrian A. Müller, PMP, PSM 1, CSM Fachbereich Informatik und Mikrosystemtechnik 1
Entwurfsmuster Entwurfsmuster (Design Patterns) geben bewährte Lösungen für immer wiederkehrende Entwurfsprobleme an Entwurfsmuster für die Software Entwicklung Populär durch das Buch Design Patterns Elements of Reusable Object-Oriented Software (1994) von Gamma, Helm, Johnson, Vlissides ( Gang of Four, GoF) Die dort beschriebenen Muster werden nach wie vor erfolgreich eingesetzt. Im Laufe der Zeit kamen noch weitere Muster hinzu. Im Folgenden wird eine Auswahl einiger häufig verwendeter Muster besprochen. Ein Muster wird später vorgestellt: Das Zustandsmuster. 2
Beispiele für Entwurfsmuster Fassade Singleton Strategie Schablonenmethode Fabrikmethode Kompositum Dekorierer Beobachter MVC: Model View - Controller 3
Fassaden-Muster Entwurfsziel: Lose Kopplung Verschiedene Pakete sollten möglichst lose gekoppelt sein Viele direkte Assoziationen oder Methodenaufrufe zu den einzelnen Klassen innerhalb eines Paketes führen zu einer engen Kopplung 4
Fassaden-Muster Enge Kopplung: Client Entkopplung durch eine Fassadenklasse als vereinfachte Schnittstelle zu dem Paket Package 5
Fassaden-Muster Enge Kopplung: Client Entkopplung durch Fassaden-klasse: Client Package Package Fassade 6
Beispiel: Geräteverwaltung Bei den im Geräteverwaltungs- Beispiel verwendeten Control-Klassen handelt es sich um Fassaden zu den jeweiligen Paketen. 7
Beispiel aus Java Swing: JOptionPane als vereinfachende Fassade Für einen einfachen Message- oder Eingabe-Dialog kann man einfach die statischen Methoden von JOptionPane verwenden, anstatt Objekte der ganzen anderen Klassen anzulegen. Zweck ist hier Vereinfachung (nicht lose Kopplung, denn für komplexere Dialoge kann und soll man schon auf die anderen Klassen zugreifen) Quelle: http://best-practice-software-engineering.ifs.tuwien.ac.at/patterns/facade.html 8
JOptionPane als vereinfachende Fassade Ohne Nutzung der Fassade Nutzung der Fassade: JFrame frame = new JFrame("Nachricht"); frame.setdefaultcloseoperation(jframe.exit_on_close); JButton button = new JButton("OK"); JLabel label = new JLabel("This is My Message Dialog!"); ActionListener actionlistener = new ActionListener() { public void actionperformed(actionevent actionevent) { System.exit(0); } }; JOptionPane.showMessageDialog(null, "This is my Message Dialog!"); button.addactionlistener(actionlistener); Container contentpane = frame.getcontentpane(); contentpane.add(label, BorderLayout.CENTER); contentpane.add(button, BorderLayout.SOUTH); frame.setsize(300, 200); frame.setvisible(true); Quelle: http://best-practice-software-engineering.ifs.tuwien.ac.at/patterns/facade.html 9
Beispiele für Entwurfsmuster Fassade Singleton Strategie Schablonenmethode Fabrikmethode 10
Singleton Eine Klasse, von der es nur ein Objekt geben soll, z. B.: Container zur Verwaltung aller Objekte einer anderen Klasse Zentrale Aufgaben, wie z. B. Verwaltung der Datenbankverbindung Mit Vorsicht zu verwenden Entspricht einer globalen Variablen Wenn man alle möglichen Werte über ein Singleton systemweit bekannt macht, widerspricht dies dem Geheimnisprinzip Gefahr von Seiteneffekten, schlechte Änderbarkeit 11
Singleton Statisches Attribut, enthält das einzige Exemplar Der Konstruktor ist private, damit man ihn nicht direkt aufrufen kann Beispiele für sonstige Attribute Statische Methode, die das einzige Exemplar zurückgibt Beispiele für sonstige Methoden 12
Singleton - Implementierung Erste Möglichkeit: Instanziieren des einzigen Exemplars bei Programmstart: Meist reicht das aus. Nachteile: Exceptions des Konstruktors können nicht aufgefangen werden, evtl. vom Konstruktor benötigte Objekte sind möglicherweise noch nicht vorhanden. Zweite Möglichkeit: private static Beispiel einzigesexemplar = new Beispiel(); Das einzige Exemplar wird zu Beginn noch nicht instanziiert: private static Beispiel einzigesexemplar = null; Bevor die Methode geteinzigesexemplar() das einzige Exemplar zurückgibt, überprüft, ob es schon ein Objekt gibt. Wenn nicht, erzeugt sie es. Problem: Falls das Singleton thread-safe sein soll, muss man die Zugriffe synchronisieren, sonst könnten mehrere Exemplare angelegt werden. 13
Aufgabe Schreiben Sie für den zweiten Fall für eine Klasse Beispiel Programmieren Sie: wo wird das Singleton einzigesexemplar initialisiert? Programmieren Sie danach die Methode geteinzigesexemplar( ); 14
Beispiele für Entwurfsmuster Fassade Singleton Strategie Schablonenmethode Fabrikmethode 15
Strategie-Muster Definiert eine Familie von Algorithmen, kapselt jeden einzelnen und macht sie austauschbar Beispiel: In einem elektronischer Kalender sollen unter anderem die Feiertage angezeigt werden. Es soll möglich sein, ihn je nach Land so zu konfigurieren, dass jeweils die richtigen Feiertage angezeigt werden. Es soll auch leicht möglich sein, ihn für weitere Länder anzupassen. Lösung: Es wird eine abstrakte Klasse oder ein Interface für die Ermittlung der Feiertage definiert. Für jedes Land wird eine konkrete Unterklasse angelegt. Je nach gewünschtem Land wird dem Kalender ein Objekt der zugehörigen konkreten Unterklasse zugeordnet. 16
Strategie-Muster 17
Aufgabe Setzen Sie das Strategie Muster um: Sie wollen eine Liste von doubles sortieren; je nach Kontext mit BubbleSort, Quicksort, public interface SortInterface { } public void sort(double[] list); Welche Implementierungen des Interfaces benötigen Sie? In einer Klasse SortingContext: welche Methoden benötigen sie, um die Wahl der Strategie zu verwalten? die Sortierung zu starten? 18
Beispiele für Entwurfsmuster Fassade Singleton Strategie Schablonenmethode Fabrikmethode 20
Schablonenmethode Problem: Zwei fast identische Methoden Code methodex in Klasse1 Code methodey in Klasse2 identisch unterschiedlich identisch unterschiedlich identisch wären sie komplett identisch, könnte man sie in eine Oberklasse verlagern 21
Schablonenmethode Lösungsansatz: Man kapselt die unterschiedlichen Teile in eigene Methoden Die Gesamtmethode wird in eine abstrakte Klasse verlagert An den unterschiedlichen Stellen werden jeweils Methoden aufgerufen, die als abstrakte Methoden definiert sind und daher von den Unterklassen implementiert werden. 22
Schablonenmethode public void schablonenmethode(){ //... // gemeinsame Teile //... elementaremethode1(); //... // gemeinsame Teile //... elementaremethode2(); //... // gemeinsame Teile //... } Unterschiedliche Implementierungen der elementaren Methoden 23
Beispiele für Entwurfsmuster Fassade Singleton Strategie Schablonenmethode Fabrikmethode 25
Fabrikmethode Problemstellung Es soll ein Framework für Anwendungen erstellt werden, die mehrere Dokumente anzeigen können. Darin gibt es eine abstrakte Klasse Dokument. Anwendungsentwickler, die das Framework nutzen, erstellen Unterklassen von Dokument Problem: Wie kann man im Framework, wo nur die abstrakte Klasse Dokument zur Verfügung steht (von der man keine Objekte anlegen kann), dann doch Dokumente anlegen? 26
Fabrikmethode Problemstellung Allgemeine Funktionen zur Dokumentenbearbeitung als Framework bereitgestellt, z. B. in einer Klassenbibliothek Hier sind die konkreten Unterklassen noch nicht bekannt, und von abstrakten Klassen kann man keine Objekte anlegen. Anwendungsentwickler nutzen das Framework, erstellen Unterklassen zu den abstrakten Framework- Klassen 27
Fabrikmethode Lösung: Abstrakte Fabrikmethode zum Anlegen eines Dokuments (muss von Unterklassen überschrieben werden) Die abstrakte Methode kann so aufgerufen werden: public void anderemethode(){ //... Dokument d = createdokument(); //... } public Dokument createdokument(){ return new Dokument1(); } public Dokument createdokument(){ return new Dokument2(); } Die abstrakte Methode Muss von einer Methode überschrieben werden, die konkrete Prof. Dokumente A. Müller, HS KL instanziiert. Nur dann Software können Engineering die Unterklassen 2015 ein Objekt Ihrer Dokument-Unterklasse anlegen (das Herzstück des Factory Method Pattern) 28
Beispiele für Entwurfsmuster Kompositum Dekorierer Beobachter MVC: Model View - Controller 29
Kompositum-Muster (Composite) Problemstellung: Es soll eine Hierarchie aufgebaut werden, z. B. eine Ordner- Hierarchie eines Dateisystems In einem Ordner können einfache und zusammengesetzte Objekte liegen Dateien. Dies sind einfache Objekte, die selbst keine anderen untergeordneten Objekte beinhalten. Ordner. Dies sind zusammensetze Objekte, die selbst wieder andere Ordner und Dateien enthalten können. Ordner und Dateien haben vieles gemeinsam Gemeinsame Attribute (Name, Autor, Anlegedatum, ) Gemeinsame Operationen (printeigenschaften, printinfo, ) Das Kompositum-Muster ermöglicht es einem übergeordneten Ordner, beide Arten von Objekten gleich zu behandeln 30
Kompositum-Muster In einem Ordner können beliebige Dateiobjekte liegen, d. h. Dateien und andere Ordner. Diese Methoden stehen für alle Dateiobjekte zur Verfügung, daher kann ein übergeordneter Ordner sie für alle seine enthaltenen Objekte aufrufen egal ob es Dateien oder selbst wieder Ordner sind. Wird rekursiv aufgerufen, zeigt die gesamte Hierarchie. 31
Kompositum-Muster public void printkompletteninhalt(){ printinfo(); for(dateiobjekt d:inhalt){ d.printkompletteninhalt(); } } public void printkompletteninhalt(){ printinfo(); } 32
Beispiele für Entwurfsmuster Kompositum Dekorierer Beobachter MVC: Model View - Controller 34
Dekorierer-Muster (Decorator) Problem: Einem Objekt müssen neue Zuständigkeiten zugeordnet werden. Die Klasse darf dabei nicht geändert werden. Lösung: Dynamisches Vorschalten von Objekten mit dem gleichen Typ wie die ursprüngliche Klasse Beispiel: Ein Modem-Objekt soll zusätzlich noch folgende Zuständigkeiten erhalten: Loggen von gesendeten Daten in eine Datei Zählen der Aufrufe und Ausgabe auf die Konsole 35
Dekorierer-Muster (Decorator) Die Dekorierer haben dasselbe Interface wie das Modem. Die Anwendung kann statt mit dem Modem auch mit einem Dekorierer arbeiten. Jeder ModemDekorierer dekoriert etwas, das ein ModemInterface besitzt (ein Modem oder einen anderen ModemDekorierer) Beim Senden führt jeder ModemDekorierer seine Aufgabe aus und leitet dann den Methodenaufruf an das von ihm Dekorierte weiter. public void send(string s){ zaehler++; dekoriertes.send(s); } public void send(string s){ log(s); dekoriertes.send(s); } 36
Verwendung Ohne Dekorierer: Mit ZaehlDekorierer: Mit Zaehl- und LogDekorierer: Eine andere Reihenfolge ist möglich 37
Beispiel: Kaffee Einfach: 1,- EUR Mit Milch: + -,50 EUR Mit Sahne: + -,70 EUR Mit Streusel: + -,20 EUR public interface Coffee { public double getcost(); // returns the cost of the coffee public String getingredients(); // returns the ingredients of the coffee } 38
public interface Coffee { public double getcost(); // returns the cost of the coffee public String getingredients(); // returns the ingredients of the coffee } // abstract decorator class - note that it implements Coffee interface abstract public class CoffeeDecorator implements Coffee { protected final Coffee decoratedcoffee; protected String ingredientseparator = ", "; public CoffeeDecorator(Coffee decoratedcoffee) { } this.decoratedcoffee = decoratedcoffee; public double getcost() { // implementing methods of the interface } return decoratedcoffee.getcost(); public String getingredients() { return decoratedcoffee.getingredients(); } } 39
Beispiele für Entwurfsmuster Kompositum Dekorierer Beobachter MVC: Model View - Controller 40
Beobachter-Muster (Observer Pattern) Bei einer Änderung eines Objekts sollen alle davon abhängigen Objekte benachrichtigt und aktualisiert werden Beispiel Die Daten eines Objekts sollen einmal als Tabelle und einmal als Grafik dargestellt werden. Tabellen- und Grafikobjekt kennen sich nicht, Änderungen in der Tabelle sollen aber die Grafik aktualisieren. Man soll auch leicht weitere Anzeigen hinzufügen können. Lösung Das Anwendungsobjekt (Subject) kennt alle Anzeige-Objekte (Beobachter, Observer) und informiert sie über alle Änderungen. Als Reaktion synchronisiert sich jeder Beobachter mit dem Zustand des Subjects. 41
Beobachter-Muster Der Wert dieses Attributs soll angezeigt werden. Dies sind die Daten, die angezeigt werden. Sie sollen bei einer Änderung von daten synchronisiert werden. Ruft getdaten() auf und weist den Wert angezeigtedaten zu. 42
Beobachter-Muster Trägt den Beobachter in die Liste angemeldetebeobachter ein Ruft bei allen angemeldeten Beobachtern die Methode aktualisiere() auf Weist den Wert dem Attribut daten zu und ruft anschließend benachrichtigebeobachter() auf. 43
Beobachter-Muster public void meldean(beobachter b){ angemeldetebeobachter.add(b); } public void benachrichtigebeobachter(){ for(beobachter b: angemeldetebeobachter){ b.aktualisiere(); } } public void setdaten(string s){ this.daten = s; benachrichtigebeobachter(); } public void aktualisiere() { angezeigtedaten = subjekt.getdaten(); } 44
Beispiel für Verwendung des Beobachter-Musters Das Event-Handling in Java Swing basiert auf diesem Muster Die verwendeten Listener sind Beobachter JFrame frame = new JFrame("Nachricht"); frame.setdefaultcloseoperation(jframe.exit_on_close); JButton button = new JButton("OK"); Codeausschnitt: JLabel label = new JLabel("This is My Message Dialog!"); ActionListener actionlistener = new ActionListener() { public void actionperformed(actionevent actionevent) { System.exit(0); } }; button.addactionlistener(actionlistener); Container contentpane = frame.getcontentpane(); contentpane.add(label, BorderLayout.CENTER); contentpane.add(button, BorderLayout.SOUTH); frame.setsize(300, 200); Hier wird der Listener bei einer Komponente (in diesem Fall einem Button) angemeldet. frame.setvisible(true); Hier wird ein neuer Listener angelegt. Dabei wird festgelegt, wie er auf die Benachrichtigung über ein Ereignis reagieren soll. Wir der Button gedrückt, so teilt er dies allen angemeldeten ActionListenern durch den Aufruf von actionperformed mit, und die ActionListener führen die definierte Aktion aus (in diesem Fall Beenden des Programms). 46
Beispiele für Entwurfsmuster Kompositum Dekorierer Beobachter MVC: Model View - Controller 47
Model View Controller (MVC) Häufig eingesetztes Muster für Oberflächen, aber auch für die Strukturierung kompletter Anwendungen Unterteilung in: Model: Speichert die eigentlichen Informationen. Kennt alle Views und informiert sie, wenn sich etwas ändert, damit sie aktualisiert werden können. View: Dient zur Darstellung des Ergebnisses nach außen. Häufig die Komponente einer grafischen Oberfläche. Controller: Komponente zur Änderung von Werten, aktualisiert das Model. Es gibt viele verschiedene Implementierungsvarianten Z. B. mit ein oder mehreren Views und Controllern Z. B. kann der Controller selbst zugleich eine View sein (beispielsweise eine grafische Darstellung, die man interaktiv ändern kann) 48
Model View Controller (MVC) Nicht unbedingt 49
MVC Beispiel-Implementierung Quelle: Stephan Kleuker, Grundkurs Software Engineering mit UML. 2. Auflage. Vieweg und Teubner 2011. Durch Drücken der Buttons ändert sich der Wert in der View. 50
MVC Beispiel-Implementierung Listener über Änderung informieren (Aufruf von xmodelchanged) Listener anmelden Holt sich mit getwert() den aktuellen Wert aus dem Model und zeigt ihn an. Ruft firexmodelchanged() auf Wenn im Controller etwas gedrückt wird, wird changevalue() des Model aufgerufen Quelle: Stephan Kleuker, Grundkurs Software Engineering mit UML. 2. Auflage. Vieweg und Teubner 2011. Hauptklasse mit Main-Methode zum Starten, legt Model, View und Controller an. 51
MVC Beispiel-Implementierung Quelle: Stephan Kleuker, Grundkurs Software Engineering mit UML. 2. Auflage. Vieweg und Teubner 2011. 52
Anhang 53
Beispiel für die Anwendung des Dekorierer-Musters Java IO:Ein InputStream kann mit verschiedenen Filtern versehen werden, die als Dekorierer implementiert sind: Quelle: http://www.philipphauer.de/study/se/design-pattern/decorator.php 54
Beispiel: MVC mit Java Server Pages URL HTML-Formular Ausgefülltes Formular Der Controller verarbeitet das ausgefüllte Formular, reicht die Daten zur Speicherung an das Modell weiter und gibt die Kontrolle an die geeignete Präsentations-jsp weiter. Quelle: Wikipedia, http://commons.wikimedia.org/wiki/image:mvc-modell.png Urheber: Franz Seidl (Ursprungsbild von Matthias Wieland) 55