© Markus Knauß, 2008 Entwurfsmuster Entwurfsmuster Markus Knauß [email protected] 1 © Markus Knauß, 2008 Motivation Entwurfsmuster helfen nicht nur bei der Erstellung eines Entwurfs, sie sind auch nützlich, um ein bestehendes Programm neu zu strukturieren. Entwurfsmuster In den kommenden zwei Vorlesungsterminen wird ein bestehendes Programm mit Entwurfsmustern neu strukturiert. 2 Praktische Anwendung eines Entwurfsmusters Erkennen der Vorteile und Nachteile von Entwurfsmustern Überblick über objektorientierte Konzepte und Entwurfsmuster Entwurfsmuster © Markus Knauß, 2008 Ziele 3 Nutzung einer Datenbank für die Speicherung der Eintragungen eines Geburtstagskalenders. Entwurfsmuster © Markus Knauß, 2008 Geburtstagskalender 4 © Markus Knauß, 2008 Entwurfsmuster Inhalt Java Database Connectivity (JDBC) Objektorientierte Konzepte Template Method Pattern Entwurfsmuster Geburtstagskalender mit Entwurfsmustern Zusammenfassung Literatur und Links 5 © Markus Knauß, 2008 Java Database Connectivity (JDBC) JDBC bietet eine plattformunabhängige Schnittstelle für die Nutzung von Datenbanken in Java-Programmen. Entwurfsmuster Das JDBC-API definiert Interfaces, welche die zentralen Datenbankfunktionen kapseln. Verbinden mit einer Datenbank Eine Anweisung ausführen Ergebnisse einer Anweisung auswerten 6 © Markus Knauß, 2008 JDBC Übersicht ResultSet erzeugt Statement erzeugt PreparedStatement erzeugt CallableStatement Entwurfsmuster erzeugt Connection erzeugt DriverManager implementiert herstellerspezifischer Datenbanktreiber greift zu auf java.sql.* implementiert JDBC-ODBC Brücke Datenbank ODBC Treiber greift zu auf 7 © Markus Knauß, 2008 Entwurfsmuster java.sql.Driver Ein Datenbankanbieter, der eine JDBC-Implementierung anbieten möchte, muss eine eigene Implementierung für das Interface java.sql.Driver liefern. Der JDBC DriverManager (java.sql.DriverManager) verwaltet in einer JVM verfügbare Datenbanktreiber (java.sql.Driver) und bietet Zugriff auf die Funktionen der verfügbaren Treiber. Um einen Treiber in der JVM verfügbar zu machen, muss dessen implementierende Klasse mit dem Klassenlader geladen werden. Hinweis: Der DriverManager ist ein Broker, der Zugriff auf die Driver-Implementierungen erlaubt. Driver-Implementierungen sind Factories für den Zugriff auf eine Datenbank. 8 © Markus Knauß, 2008 JDBC am Beispiel // Datenbanktreiber laden Class.forName( "org.apache.derby.jdbc.EmbeddedDriver"); // Verbindung zur Datenbank herstellen Connection con = DriverManager.getConnection( "jdbc:derby:/Users/knaussms/tmp/address"); // Auszuführende Anweisung erstellen Entwurfsmuster Statement stmt = con.createStatement(); // Anweisung ausführen ResultSet rs = stmt.executeQuery( "SELECT * FROM persons"); // Ergebnisse auswerten while (rs.next()) { int id = rs.getInt("id"); String firstName = rs.getString("first_name"); String lastName = rs.getString("last_name"); Date dateOfBirth = rs.getDate("date_of_birth"); DateFormat dateFormat = DateFormat.getDateInstance(DateFormat.MEDIUM); System.out.println(Integer.toString(id) + ": " + firstName + " " + lastName + ", " + dateFormat.format(dateOfBirth)); } Die einzige herstellerspezifische Anweisung ist das Laden des Datenbanktreibers. Konfigurationsspezifische Anweisungen sind das Verbinden mit der Datenbank und der Zugriff auf Tabellen und Spalten. Alle weiteren Befehle sind unabhängig von der verwendeten Datenbank. // Verbindung zur Datenbank schließen con.close(); SimpleJDBC.java 9 © Markus Knauß, 2008 Einschub: PersonDB <<interface>> IPerson +setFirstName(firstName:String) +getFirstName():String +setLastName(lastName:String) +getLastName():String +setDateOfBirth(dateOfBirth:Calendar) +getDateOfBirth():Calendar <<interface>> IDBObject +getId():int Entwurfsmuster PersonBean Die Klasse PersonDB implementiert alle Funktionen für die Speicherung, das Laden, das Ändern und das Löschen von GeburtstagskalenderEinträgen in einer Datenbank. -firstName:String -lastName:String -dateOfBirth:Calendar PersonDB -id:int +create(person:IPerson):PersonDB +read(id:int):PersonDB +select(qbe:IPerson):List<PersonDB> +read() +update() +delete() implementiert erbt von 10 © Markus Knauß, 2008 Entwurfsmuster Aufgabe Markieren Sie die einzelnen Schritte für den Datenbankzugriff in den Methoden create, read, update, delete und select der Klasse PersonDB. Welche Anweisungssequenzen können Sie identifizieren? Welche Teile der Sequenzen sind gleich, wo unterscheiden sie sich? con = DriverManager.getConnection(DB_URL); Mit Datenbank verbinden PreparedStatement ps = con.prepareStatement(DELETE_STMT); Statement erstellen ps.setInt(1, getId()); ps.execute(); Statement intialisieren und ausführen con.close(); Verbindung schließen PersonDB.java 11 © Markus Knauß, 2008 Entwurfsmuster Beispiel einer Lösung: Gleichbleibende Anweisungssequenzen public void read() { Connection con = null; try { con = DriverManager.getConnection(DB_URL); PreparedStatement ps = con.prepareStatement(READ_STMT); ps.setInt(1, getId()); ResultSet rs = ps.executeQuery(); while (rs.next()) { setFirstName(rs.getString("fist_name")); setLastName(rs.getString("last_name")); setDateOfBirth(toCalendar(rs.getDate("date_of_birth"))); } } catch (SQLException e) { log.log(Level.SEVERE, e.getMessage(), e); } finally { if (con != null) { try { con.close(); } catch (SQLException e) { log.log(Level.SEVERE, e.getMessage(), e); } } } } Verbindung herstellen Statement erstellen und initialisieren Statement ausführen Resultate auswerten Verbindung schließen 12 © Markus Knauß, 2008 Entwurfsmuster Beispiel einer Lösung: Unterschiede public void read() { Connection con = null; try { con = DriverManager.getConnection(DB_URL); PreparedStatement ps = con.prepareStatement(READ_STMT); ps.setInt(1, getId()); ResultSet rs = ps.executeQuery(); while (rs.next()) { setFirstName(rs.getString("fist_name")); setLastName(rs.getString("last_name")); setDateOfBirth(toCalendar(rs.getDate("date_of_birth"))); } } catch (SQLException e) { log.log(Level.SEVERE, e.getMessage(), e); } finally { if (con != null) { try { con.close(); } catch (SQLException e) { log.log(Level.SEVERE, e.getMessage(), e); } } } } Statements Initialisierung Auswertung 13 © Markus Knauß, 2008 Entwurfsmuster Inhalt Java Database Connectivity (JDBC) Objektorientierte Konzepte Template Method Pattern Entwurfsmuster Geburtstagskalender mit Entwurfsmustern Zusammenfassung Literatur und Links 14 © Markus Knauß, 2008 Klassen ModelFactory -instance:ModelFactory +getInstance():ModelFactory Eine Klasse ist eine Schablone für Objekte, die aus der Klasse erzeugt werden können. Entwurfsmuster Jede Klasse existiert nur einmal in einem laufenden Programm. Eine Klasse kann einen Zustand haben und Methoden anbieten. 15 © Markus Knauß, 2008 Entwurfsmuster Objekte Person -firstName:String -lastName:String -dateOfBirth:Calendar +getFirstName():String +setFirstName(firstName:String) +getLastName():String +setLastName(lastName:String) +getDateOfBirth():Calendar +setDateOfBirth(dateOfBirth:Calendar) JaggerMick:Person RichardsKeith:Person -firstName=“Mick“ -lastName=“Jagger“ -dateOfBirth='26.7.1943' -firstName=“Keith“ -lastName=“Richards“ -dateOfBirth='18.12.1943' Objekte werden aus Klassen erzeugt (instantiiert). Aus jeder Klassen können beliebig viele Objekte erzeugt werden. Jedes Objekt hat eine Identität und einen Zustand. 16 © Markus Knauß, 2008 Entwurfsmuster Vererbung Vererbung drückt eine „ist ein“Beziehung aus. Person -firstName:String -lastName:String -dateOfBirth:Calendar +getFirstName():String +setFirstName(firstName:String) +getLastName():String +setLastName(lastName:String) +getDateOfBirth():Calendar +setDateOfBirth(dateOfBirth:Calendar) Objekte von erbenden Klassen können an Stelle von Objekten der vererbenden Klasse verwendet werden. List<Person> persons = new ArrayList<Person>(); -id:int public void store(Person person) { persons.add(person); } +create(person:IPerson):PersonDB +read(id:int):PersonDB +select(qbe:IPerson):List<PersonDB> +read() +update() +delete() public static void main(String[] args) { PersonBean personBean = new PersonBean(); PersonDB personDB = new PersonDB(); store(personBean); store(personDB); } PersonBean PersonDB 17 © Markus Knauß, 2008 Polymorphie Erbende Klassen können Methoden überschreiben. Durch das Überschreiben kann das Verhalten einer Methode verändert werden. Entwurfsmuster Polymorphie = Vielgestaltigkeit, Verschiedengestaltigkeit 18 © Markus Knauß, 2008 Polymorphie Person -firstName:String Entwurfsmuster +getFirstName():String +setFirstName(firstName:String) public String getFirstName() { read(); return firstName; } public void setFirstName(String firstName) { this.firstName = firstName; update(); } PersonBean PersonDB +getFirstName():String +setFirstName(firstName:String) +getFirstName():String +setFirstName(firstName:String) +read() +update() public String getFirstName() { return firstName; } public void setFirstName(String firstName) { this.firstName = firstName; } 19 © Markus Knauß, 2008 Abstrakte Klassen, abstrakte Methoden Person DBObject Entwurfsmuster +getFirstName():String +setFirstName(firstName:String) +getLastName():String +setLastName(lastName:String) +getDateOfBirth():Calendar +setDateOfBirth(dateOfBirth:Calendar) PersonBean -firstName:String -lastName:String -dateOfBirth:Calendar +getId():int +read() +update() +delete() PersonDB -id:int +create(person:IPerson):PersonDB +read(id:int):PersonDB +select(qbe:IPerson):List<PersonDB> Von abstrakten Klassen können keine Objekte erzeugt werden. Abstrakte Methoden haben keine Implementierung, sie müssen in der erbenden Klasse überschrieben werden. Abstrakte Methoden können nur in abstrakten Klassen deklariert werden. 20 © Markus Knauß, 2008 Entwurfsmuster Aufgabe Kapseln Sie die spezifischen Anweisungsteile der readMethode in eigenen Methoden. Skizzieren Sie die Klasse DBStatement, in der die Methoden, in denen die spezifischen Anweisungsteile der read-Methode zusammengefasst sind, mit einer Standardimplementierung realisiert sind. Skizzieren Sie die von DBStatement erbende Klasse ReadStatement, in der die Methoden mit den spezifischen Anweisungsteilen der read-Methode enthalten sind. Überarbeiten Sie die Implementierung der read-Methode so, dass nur die Methoden mit den spezifischen Anweisungsteilen aus der Klasse ReadStatement verwendet werden. 21 © Markus Knauß, 2008 Beispiel einer Lösung: Klasse DBStatement public abstract class DBStatement { public abstract String getStatement(); public void initParameter(PreparedStatement stmt) throws SQLException { } Entwurfsmuster public void evaluateResults(ResultSet rs) throws SQLException { } } DBStatement.java 22 © Markus Knauß, 2008 Beispiel einer Lösung: Klasse ReadStatement public class ReadStatement extends DBStatement { private private private private int id; String firstName; String lastName; Calendar dateOfBirth; Entwurfsmuster @Override public String getStatement() { return "SELECT * FROM persons WHERE id = ?"; } @Override public void initParameter(PreparedStatement stmt) throws SQLException { stmt.setInt(1, id); } @Override public void evaluateResults(ResultSet rs) throws SQLException { firstName = rs.getString("fist_name"); lastName = rs.getString("last_name"); dateOfBirth = CalendarUtils.toCalendar(rs.getDate("date_of_birth")); } // Get and set methods for attributes. } ReadStatement.java 23 © Markus Knauß, 2008 Entwurfsmuster Beispiel einer Lösung: read()-Methode private ReadStatement readStatement = new ReadStatement(); public void read() { Connection con = null; try { con = DriverManager.getConnection(DB_URL); PreparedStatement ps = con.prepareStatement(readStatement.getStatement()); readStatement.setId(getId()); readStatement.initParameter(ps); ResultSet rs = ps.executeQuery(); while (rs.next()) { readStatement.evaluateResults(rs); } } catch (SQLException e) { log.log(Level.SEVERE, e.getMessage(), e); } finally { if (con != null) { try { con.close(); } catch (SQLException e) { log.log(Level.SEVERE, e.getMessage(), e); } } } } PersonDB.java 24 © Markus Knauß, 2008 Was wurde erreicht? Die Implementierung der speziellen Teile einer DatenbankAnweisung können in eigenen Klassen gekapselt werden. Entwurfsmuster Der Algorithmus für die Ausführung einer Anweisung ist in allen Methoden gleich! DBStatement +getStatement():String +initParameter(stmt:PreparedStatement) +evaluateResults(rs:ResultSet) CreateStatement ReadStatement UpdateStatement DeleteStatement 25 © Markus Knauß, 2008 Entwurfsmuster Inhalt Java Database Connectivity (JDBC) Objektorientierte Konzepte Template Method Pattern Entwurfsmuster Geburtstagskalender mit Entwurfsmustern Zusammenfassung Literatur und Links 26 © Markus Knauß, 2008 Entwurfsmuster Beobachtungen Die Abfolge der Schritte für den Datenbankzugriff via JDBC ist immer gleich. Verbindung zur Datenbank öffnen Anweisung erstellen Parameter initialisieren Anweisung ausführen Ergebnisse auswerten Verbindung zur Datenbank schließen Die Schritte unterscheiden sich in der ausgeführten Anweisung, den Parametern und der Auswertung der Ergebnisse. 27 © Markus Knauß, 2008 Template Method Zweck Definiere einen Algorithmus in einer Methode. Delegiere einzelne Schritte an erbende Klassen. Entwurfsmuster Die Verwendung einer Template Method ermöglicht es erbenden Klassen, bestimmte Schritte eines Algorithmus zu überschreiben, ohne die Struktur des Algorithmus zu ändern. 28 © Markus Knauß, 2008 Entwurfsmuster Template Method Motivation Zum Beispiel Datenbankzugriff via JDBC: Die Abfolge der Schritte für den Datenbankzugriff mit JDBC ist immer gleich. Die Inhalte der einzelnen Schritte, zum Beispiel die konkrete Anweisung oder die Auswertung der Ergebnisse, sind verschieden. 29 Invariante Teile eines Algorithmus sollen genau einmal implementiert werden. Gemeinsames Verhalten soll in einer Klasse zusammengefasst werden. Kontrolle der Erweiterungen durch Vererbung Entwurfsmuster © Markus Knauß, 2008 Template Method Anwendbarkeit 30 © Markus Knauß, 2008 Template Method Lösung CreateStatement Entwurfsmuster DBStatement +getStatement():String +initParameter(stmt:PreparedStatement) +evaluateResults(rs:ResultSet) +execute() PersonDB ReadStatement -id:int UpdateStatement DeleteStatement SelectStatement +create(person:IPerson):PersonDB +read(id:int):PersonDB +select(qbe:IPerson):List<PersonDB> +read() +update() +delete() NextPrimaryKeyStatement 31 © Markus Knauß, 2008 Entwurfsmuster Template Method Lösung public final void execute() { Connection con = null; try { con = DriverManager.getConnection(DB_URL); PreparedStatement ps = con.prepareStatement(getStatement()); initParameter(ps); ps.execute(); ResultSet rs = ps.getResultSet(); if (rs != null) { while (rs.next()) { evaluateResults(rs); } } } catch (SQLException e) { log.log(Level.SEVERE, e.getMessage(), e); } finally { if (con != null) { try { con.close(); } catch (SQLException e) { log.log(Level.SEVERE, e.getMessage(), e); } } } } DBStatement.java 32 public class PersonDB extends PersonBean implements IPerson, IDBObject { private static final CreateStatement createStatement = new CreateStatement(); private static final ReadStatement readStatement = new ReadStatement(); private static final NextPrimaryKeyStatement nextPrimaryKeyStatement = new NextPrimaryKeyStatement(); //... public static PersonDB create(IPerson person) { nextPrimaryKeyStatement.execute(); int nextPK = nextPrimaryKeyStatement.getNextPrimaryKey(); createStatement.setId(nextPK); createStatement.setFirstName(person.getFirstName()); createStatement.setLastName(person.getLastName()); createStatement.setDateOfBirth(person.getDateOfBirth()); createStatement.execute(); return new PersonDB(nextPK, person); } Entwurfsmuster © Markus Knauß, 2008 Template Method Lösung public static PersonDB read(int id) { readStatement.setId(id); readStatement.execute(); return new PersonDB( id, readStatement.getFirstName(), readStatement.getLastName(), readStatement.getDateOfBirth()); } //... } PersonDB.java 33 Gemeinsames Verhalten wird in einer Klasse gekapselt. Der Kontrollfluss wird invertiert, die vererbende Klasse ruft Methoden der erbenden Klasse auf. Es muss klar sein, welche Methoden überschrieben werden dürfen bzw. überschrieben werden müssen. Entwurfsmuster © Markus Knauß, 2008 Template Methode Konsequenzen 34 Factory, Factory Method: nutzt Template Method zur Objekterzeugung Strategy: Kapselung eines Algorithmus Entwurfsmuster © Markus Knauß, 2008 Template Methode Ähnliche und Verwandte Muster 35 © Markus Knauß, 2008 Entwurfsmuster Inhalt Java Database Connectivity (JDBC) Objektorientierte Konzepte Template Method Pattern Entwurfsmuster Geburtstagskalender mit Entwurfsmustern Zusammenfassung Literatur und Links 36 © Markus Knauß, 2008 Gamma et al. (1995) Das Buch der „Gang of Four“: Design Patterns: Elements of Reusable Object-Oriented Software, hat die Entwurfsmuster bekannt gemacht und eine Entwurfsmuster-Bewegung initiiert. Entwurfsmuster Gamma, E., R. Helm, R. Johnson und J. Vlissides (1995): Design Patterns: Elements of Reusable Object-Oriented Software. Addison-Wesley. In ihrem Buch dokumentieren die Autoren 23 Entwurfsmuster. 37 © Markus Knauß, 2008 Klassifizierung der Entwurfsmuster Erzeugungsmuster Entwurfsmuster Verstecken die Erzeugung von Objekten, wodurch ein Programm unabhängig von der Erzeugung, der Zusammensetzung und der Initialisierung seiner Objekte wird. Strukturmuster Fassen Klassen und Objekte in größeren Strukturen zusammen, wodurch ein zusammenhängendes System entsteht. Verhaltensmuster Kapseln Algorithmen und Zuständigkeiten, wodurch deren Nutzung unabhängig von der Implementierung wird. 38 Gültigkeitsbereich © Markus Knauß, 2008 Entwurfsmuster Klassifizierung nach Gamma et al. (1995) Aufgabe Erzeugungsmuster Strukturmuster Factory Method Adapter klassenbasiert (klassenbasiert) Abstract Factory Adapter Builder (objektbasiert) Prototyp Bridge Singleton Decorator Facade objektbasiert Flyweight Composite Proxy Verhaltensmuster Interpreter Template Method Command Observer Visitor Iterator Memento Strategy Mediator State Chain of Responsibility 39 © Markus Knauß, 2008 Entwurfsmuster Dokumentation eines Entwurfsmusters Name und Klassifizierung, Alternative Namen Zweck, Motivation Anwendbarkeit Struktur, Teilnehmer, Interaktion Konsequenzen Implementierung, Beispiel-Programmcode, Bekannte Verwendungen Verwandte Entwurfsmuster 40 © Markus Knauß, 2008 Erzeugungsmuster Abstract Factory: Definiert eine Schnittstelle, mit der Objekte abstrakter Klassen erzeugt werden können. Die Implementierung der abstrakten Klassen ist verborgen. Entwurfsmuster Builder: Trennt die Erzeugung eines Objekts von dessen Repräsentation. Factory Method: Deklariert eine Schnittstelle für die Erzeugung von Objekten. Welche Objekte erzeugt werden, entscheidet die implementierende Klasse. Prototyp: Erzeugt Objekte durch kopieren eines Prototyps. Singleton: Garantiert, dass von einer Klasse nur ein Objekt erzeugt wird. 41 © Markus Knauß, 2008 Strukturmuster Adapter: Passt die Schnittstelle einer Klasse an eine andere Schnittstelle an. Bridge: Entkoppelt eine Struktur von ihrer Implementierung. Entwurfsmuster Decorator: Erweitert ein Objekt um Funktionen/Zuständigkeiten. Facade: Bietet eine einheitliche Schnittstelle für die Nutzung eines Teilsystems. Flyweight: Stellt Objekte zur gemeinsamen Verwendung zur Verfügung. Composite: Kombiniert Objekte in Baum-Strukturen. Proxy: Kontrolliert den Zugriff auf ein Objekt. 42 © Markus Knauß, 2008 Verhaltensmuster Command: Kapselt einen Algorithmus in einem Objekt. Observer: Beobachtet den Zustand eines Objekts. Entwurfsmuster Visitor: Kapselt die Operationen, die auf einer Objektstruktur ausgeführt werden, in einem Objekt. Interpreter: Wertet Ausdrücke, die entsprechend einer definierten Grammatik formuliert sind, aus. Iterator: Bietet sequenziellen Zugriff auf die Elemente einer Struktur. Memento: Speichert den Zustand eines Objekts. 43 © Markus Knauß, 2008 Verhaltensmuster Template Method: Definiert das Skelett eines Algorithmus und bietet Erweiterungspunkte für die spezifische Anpassung. Entwurfsmuster Strategy: Kapselt die Implementierung eines Algorithmus in einer Klasse. Mediator: Definiert ein Objekt, welches das Zusammenspiel mehrerer Objekte regelt. State: Definiert das Verhalten eines Objekts abhängig von seinem Zustand. Chain of Responsibility: Entkoppelt den Aufrufer einer Routine vom ausführenden Objekt. 44 © Markus Knauß, 2008 Entwurfsmuster Inhalt Java Database Connectivity (JDBC) Objektorientierte Konzepte Template Method Pattern Entwurfsmuster Geburtstagskalender mit Entwurfsmustern Zusammenfassung Literatur und Links 45 © Markus Knauß, 2008 Entwurfsmuster Entwurfsmuster im Geburtstagskalender Singleton Facade Abstract Factory Observer Flyweight Adapter 46 © Markus Knauß, 2008 Entwurfsmuster Singleton /** * Holds an instance of this class. */ private static Application instance = null; Klassenvariable speichert einziges Objekt der Klasse. /** * Provides access to an instance of this class. * @return */ public static Application getInstance() { if (instance == null) { instance = new Application(); } return instance; } Auf die Klassenvariable kann unterschiedlich zugegriffen werden. Application.java Bei konkurrierenden Zugriffen muss darauf geachtet werden, dass nur ein Thread das Objekt erzeugen kann. 47 © Markus Knauß, 2008 Entwurfsmuster Singleton mit Thread-Synchronisation /** * Holds an instance of this class. */ private static Application instance = null; /** * Provides access to an instance of this class. * @return */ public static Application getInstance() { if (instance == null) { synchronized (Application.class) { if (instance == null) { instance = new Application(); } } } return instance; } Application.java Double Checked Locking Muster Threads werden nur synchronisiert, wenn noch kein Objekt erzeugt wurde. Im synchronisierten Block kann sich nur ein Thread befinden. Im synchronisierten Block wird noch einmal geprüft, ob bereits ein Objekt erzeugt wurde. 48 © Markus Knauß, 2008 Entwurfsmuster Singletons im Geburtstagskalender Application.java BirthdayIOFactory UI.java ActionRegistry.java DBStatementRegistry.java 49 © Markus Knauß, 2008 Facade Die Klasse PersonDB bietet einen einheitlichen Zugriff auf das Teilsystem, das den Datenbankzugriff implementiert. Registry Entwurfsmuster PersonDB ValueType DBStatement +register(value:ValueType) +get(key:String):ValueType -id:int +create(person:IPerson):PersonDB +read(id:int):PersonDB +select(qbe:IPerson):List<PersonDB> +read() +update() +delete() CreateStatement DeleteStatement DBStatementRegistry ReadStatement SelectStatement UpdateStatement 50 © Markus Knauß, 2008 Entwurfsmuster Abstract Factory Skizzieren Sie die Beziehungen der Klassen BirthdayIO, BirthdayIOFactory, CSVBirthdayIO, CSVBirthdayIOFactory, DBBirthdayIO und DBBirthdayIOFactory. Wie wird ein Objekt einer Klasse erzeugt, die das Interface BirthdayIO implementiert? Welche Klassen muss ein Nutzer des IO-Teilsystems kennen, um Geburtstage zu speichern bzw. zu laden? Wie kann zwischen der Speicherung in einer Datenbank und der Speicherung in CSV formatierten Dateien gewechselt werden? 51 © Markus Knauß, 2008 Abstract Factory BirthdayIO +load():List<Birthday> +store(birthdays:List<Birthday>) Entwurfsmuster DBBirthdayIO CSVBirthdayIO public static BirthdayIOFactory getInstance() { if (instance == null) { // instance = new CSVBirthdayIOFactory(); instance = new DBBirthdayIOFactory(); } return instance; } Application.java BirthdayIOFactory +getIOProvider(): BirthdayIO DBBirthdayIOFactory CSVBirthdayIOFactory Wechsel des IO-Teilsystems durch ändern des IO-Factory-Objekts 52 © Markus Knauß, 2008 Observer Die Klasse BirthdaysTableModel speichert die Geburtstage, die in der Tabelle der graphischen Benutzungsschnittstelle angezeigt werden. Entwurfsmuster Die Klasse Application speichert die Geburtstage. BirthdaysTableModel Application Birthday Wie wird ein Objekt der Klasse BirthdaysTableModel über eine Änderung der Daten in einem Objekt der Klasse Application informiert? 53 © Markus Knauß, 2008 Observer PropertyChangeListener +propertyChange() Entwurfsmuster BirthdaysTableModel public void propertyChange( PropertyChangeEvent evt) { getBirthdays().clear(); Birthdays birthdays = Application.getInstance().getBirthdays(); for (int birthdayIdx = 0; birthdayIdx < birthdays.numberOfBirthdays(); birthdayIdx++) { getBirthdays().add(birthdays.get(birthdayIdx)); } fireTableDataChanged(); } PropertyChangeSupport +addPropertyChangeListener(listener:PropertyChangeListener) +firePropertyChangeEvent() Application public void editBirthday( Birthday oldBirthday, Birthday newBirthday) { int indexOfOld = birthdays.getIndexOf(oldBirthday); birthdays.set(indexOfOld, newBirthday); getPropertyChangeSupport().firePropertyChange( "birthdays", oldBirthday, newBirthday); } 54 © Markus Knauß, 2008 Flyweight ValueType Registry Action +register(value:ValueType) +get(key:String):ValueType AddAction DeleteAction Entwurfsmuster EditAction DBStatementRegistry ActionRegistry Die DBStatementRegistry ist gleich aufgebaut. ExitAction HelpAboutAction OpenAction SaveAction 55 © Markus Knauß, 2008 Adapter (objektbasiert) OpenAction BirthdayIO SaveAction +load():List<Birthday> +store(birthdays:List<Birthday>) Entwurfsmuster DBBirthdayIO PersonDB -id:int +create(person:IPerson):PersonDB +read(id:int):PersonDB +select(qbe:IPerson):List<PersonDB> +read() +update() +delete() Ein Objekt der Klasse DBBirthdayIO adaptiert die Schnittstelle der Klasse PersonDB auf die Schnittstelle des Interface BirthdayIO. 56 © Markus Knauß, 2008 Entwurfsmuster Geburtstagskalender Weitere Entwurfsmuster: Die Benutzungsschnittstelle ist entsprechend dem Model View Controller Muster augebaut (UI-, Model- und Action-Klassen). Der Algorithmus für die Erzeugung des Primärschlüssels für das Speichern von Einträgen in der Datenbank kann mit einem Strategy Muster implementiert werden. Der Programmcode des Geburtstagskalenders steht auf der Webseite zur Vorlesung zum Download zur Verfügung. http://www.iste.uni-stuttgart.de/se/teaching/courses/muw/index.html 57 © Markus Knauß, 2008 Entwurfsmuster Inhalt Java Database Connectivity (JDBC) Objektorientierte Konzepte Template Method Pattern Entwurfsmuster Geburtstagskalender mit Entwurfsmustern Zusammenfassung Literatur und Links 58 © Markus Knauß, 2008 Vorteile und Nachteile Entwurfsmuster sind wiederverwendbare Lösungen für wiederkehrende Entwurfsprobleme auf Klassen- und Objektebene. Entwurfsmuster Entwurfsmuster, wie sie hier behandelt wurden, setzen ein „solides“ Verständnis objektorientierter Konzepte voraus. Vor allem Vererbung und Polymorphie müssen verstanden sein. Die Verwendung von Entwurfsmustern macht die Teile eines Programms unabhängiger voneinander, wodurch sie einfacher austauschbar und wiederverwendbar sind. Verständlicher wird ein Programm für den unerfahrenen Entwurfsmuster-Anwender nicht. 59 © Markus Knauß, 2008 Entwurfsmuster Praktische Anwendung Im Rahmen dieses Vorlesungsteils wurde die praktische Anwendung der Entwurfsmuster Singleton, Facade, Abstract Factory, Observer, Flyweight, Adapter und Template Method im Geburtstagskalender vorgestellt. Die Anwendung und Implementierung des Template Method Musters wurde praktisch geübt. Der Programmcode des Geburtstagskalenders, in dem die Muster implementiert sind, steht auf der Webseite zur Vorlesung zum Download zur Verfügung. 60 © Markus Knauß, 2008 OO-Konzepte und Entwurfsmuster Wichtige objektorientierte Konzepte, die für das Verstehen von Entwurfsmustern notwendig sind, wurden besprochen. Entwurfsmuster Die Klassifizierung von Entwurfsmustern und ihre Dokumentation nach Gamma et al. (1995) wurde vorgestellt. Die 23 Entwurfsmuster, die in Gamma et al. (1995) dokumentiert sind, wurden kurz vorgestellt. 61 © Markus Knauß, 2008 Entwurfsmuster Ausblick Muster gibt es für verschiedene Abstraktionsebenen eines Programms, zum Beispiel für die Architektur oder den Programmcode, aber auch für verschiedenste Einsatzzwecke, zum Beispiel für Java Enterprise Anwendungen. Architekturmuster: Bass, L., P. Clements und R. Kazman (1998): Software Architecture in Practice. Addison Wesley Longman, Inc. Java Blueprints: http://java.sun.com/reference/blueprints/ Außerdem gibt es noch Anti-Patterns, RE-Patterns, UI-Patterns, ... 62 © Markus Knauß, 2008 Entwurfsmuster Inhalt Java Database Connectivity (JDBC) Objektorientierte Konzepte Template Method Pattern Entwurfsmuster Geburtstagskalender mit Entwurfsmustern Zusammenfassung Literatur und Links 63 © Markus Knauß, 2008 Literatur und Links Das Buch der „Gang of Four“ mit den bekanntesten Entwurfsmuster: Entwurfsmuster Gamma, E., R. Helm, R. Johnson und J. Vlissides (1995): Design Patterns: Elements of Reusable Object-Oriented Software. Addison-Wesley. Wikipedia Artikel mit Links und Hintergrundinformationen für den Einstieg ins Themengebiet (25.6.2008): http://de.wikipedia.org/wiki/Entwurfsmuster 64 © Markus Knauß, 2008 Entwurfsmuster Inhalt Java Database Connectivity (JDBC) Objektorientierte Konzepte Template Method Pattern Entwurfsmuster Datenbankzugriff mit Entwurfsmustern Zusammenfassung Literatur und Links 65