Objektorientierte Implementierung 11) Programmieren gegen Schnittstellen "Der Aufrufer programmiert gegen die Schnittstelle, er befindet sich sozusagen im luftleeren Raum." Siedersleben/Denert, Wie baut man Informationssysteme, Informatik-Spektrum, August 2000 Softwaretechnologie, © Prof. Uwe Aßmann, Prof. Heinrich Hussmann 1 Objektorientierte Implementierung mit Java-Datenstrukturen 10 Verfeinern von Assoziationen mit dem Java-2 Collection Framework 11 Programmieren gegen Schnittstellen Auswahl von Datenstrukturen Persistente Datenhaltung Softwaretechnologie 2 Schnittstellen und Implementierungen im Collection-Framework Vererbung (extends) <<interface>> Collection <<interface>> List Implementierung (implements) <<interface>> Set <<interface>> SortedSet ArrayList LinkedList Softwaretechnologie HashSet <<interface>> Map <<interface>> SortedMap HashMap TreeSet TreeMap 3 Typanpassungen mit Schnittstellen: Geordnete Listen mit ArrayList (1) import java.util.ArrayList; ... class Bestellung { private String kunde; private ArrayList liste; private int anzahl = 0; public Bestellung(String kunde) { this.kunde = kunde; this.liste = new ArrayList(); } public void neuePosition (Bestellposition b) { liste.add(b); } public void loeschePosition (int pos) { liste.remove(pos); } ... Softwaretechnologie 4 Anwendungsbeispiel mit ArrayList (falsch!) ... public void sonderpreis (int pos, int preis) { liste.get(pos).einzelpreis(preis); } ... ► Compilermeldung: „Method einzelpreis(int) not found in class java.lang.Object.“ ? liste.get(pos).einzelpreis(preis); ArrayList Object defi niert auf Bestellposition Spezialisierung von Object auf Bestellposition? Softwaretechnologie 5 Typanpassungen auf Elementtypen * Object Bestellung – kunde: String – anzahl: int 1 java.util.ArrayList add(Object o) liste get(pos: int): Object ... * Zusicherung: Alle von einem Bestellung-Objekt über die liste-Assoziation erreichbaren Objekte sind aus der Klasse Bestellposition. Bestellposition Typanpassung (cast): • Operationen der Oberklasse passen immer auch auf Objekte der Unterklasse • Operationen der Unterklasse auf Objekte einer Oberklasse anzuwenden, erfordert explizite Typanpassung (dynamic cast): ( Typ ) Objekt hier: (Bestellposition)liste.get(pos) Softwaretechnologie 6 Anwendungsbeispiel mit ArrayList (2) public void sonderpreis (int pos, int preis) { ((Bestellposition)liste.get(pos)).einzelpreis(preis); } public int auftragssumme() { int s = 0; for(int i=0; i<liste.size(); i++) s += ((Bestellposition)liste.get(i)).positionspreis(); return s; } } public void print () { System.out.println("Bestellung fuer Kunde "+kunde); for(int i=0; i<liste.size(); i++) System.out.println(liste.get(i)); System.out.println("Auftragssumme: "+auftragssumme()); System.out.println(); } Online: Bestellung1.java Softwaretechnologie 7 Geordnete Collections II java.util.LinkedList (Auszug) public class LinkedList implements List { public boolean add (Object o); public boolean remove (Object o); public void clear(); public boolean isEmpty(); public boolean contains (Object o); public int size(); public Object get (int index); public Object set (int index, Object element) public Object remove (int index); public int indexOf (Object o); public void addFirst (Object o); public void addLast (Object o); ... Anwendungsbeispiel Online: } mit LinkedList: Bestellung3.java Softwaretechnologie 8 Polymorphe Container durch Schnittstellen Softwaretechnologie, © Prof. Uwe Aßmann, Prof. Heinrich Hussmann 9 Programmieren gegen Schnittstellen -- Polymorphe Container class Bestellung { ! List ist ein Interface, keine Klasse ! private String kunde; private List liste; ... // Konstruktor sh. nächste Folien public void neuePosition (Bestellposition b) { liste.add(b); } public void loeschePosition (int pos) { liste.remove(pos); } public void sonderpreis (int pos, int preis) { ((Bestellposition)liste.get(pos)).einzelpreis(preis); } Softwaretechnologie 10 Polymorphe Container: Wechsel der Datenstruktur • ArrayList: class Bestellung { private String kunde; private List liste; public Bestellung(String kunde) { this.kunde = kunde; this.liste = new ArrayList(); } ... ! List ist ein Interface, keine Klasse ! • LinkedList: class Bestellung { private String kunde; private List liste; public Bestellung(String kunde) { this.kunde = kunde; this.liste = new LinkedList(); } ... Softwaretechnologie Code muß bei Wechsel der Datenstruktur nur an einer Stelle (Konstruktor) geändert werden ! 11 Standardalgorithmen in der Algorithmenklasse java.util.Collections ► Algorithmenklassen: enthalten Algorithmen, die auf einer Familie von anderen Klassen arbeiten ■ ■ ■ Hier: java.util.Collections enthält Algorithmen auf beliebigen Klassen, die das Collection- bzw. List-Interface implementieren Bei manchen Operationen ist Ordnung auf Elementen vorausgesetzt. Achtung: Statische Operationen! public class Collections { public static Object max (Collection coll); public static Object min (Collection coll); public static int binarySearch(List list, Object key); public static void reverse (List list); public static void sort (List list) ... } Softwaretechnologie 12 Prädikat-Schnittstellen (...able Schnittstellen) ► Schnittstellen, die die Eigenschaft einer Klasse ausdrücken, werden oft mit dem Suffix “able” benannt: ■ ■ ■ ► Iterable Clonable Serializable Beispiel: geordnete Standarddatentypen (z.B. String oder List) implementieren Comparable: public interface Comparable { public int compareTo (Object o); } ► Resultat ist kleiner/gleich/größer 0: genau dann wenn "this" kleiner/gleich/größer als Objekt o Softwaretechnologie 13 Entwurfsmuster Iterator (Implementierungsmuster) ► Name: Iterator (auch: Stream, Cursor, Enumeration) ► Problem: Sequentielles Durchlaufen der Elemente eines zusammengesetzten Objekts oder einer Collection. ► ■ Aufzählen der in einem “Behälter” befindlichen Elemente durch Herausziehen (pull) ■ Keine Aussage über die Reihenfolge! Lösung: Iterator {abstract} pull.. next() hasNext() Aggregate elements(): Iterator <<create>> ConcreteIterato r Element Softwaretechnologie 14 Iterator-Beispiel in der JDK (ArrayList) <<interface>> java.util.Iterator Iterator hasNext() next() Aggregate Bestellung – kunde: String – anzahl: int 1 Concrete Iterator java.util.ArrayList add(o: Object) liste get(pos: int): Object <<create>> iterator(): Iterator ... Klassenname nicht * Element Softwaretechnologie bekannt, weil privat (z.B. ArrayListIterator) Object 15 Iterator-Implementierungsmuster ► Verwendungsbeispiel: List list; .. Iterator i = list.iterator(); while (i.hasNext()) { doSomeThing(i.next()); } Softwaretechnologie 16 Anwendungsbeispiel mit Iteratoren import java.util.Iterator; ... class Bestellung { private String kunde; private ArrayList liste; ... public int auftragssumme() { Iterator i = liste.iterator(); int s = 0; while (i.hasNext()) s += ((Bestellposition)i.next()).positionspreis(); return s; } ... } Online: Bestellung2.java Softwaretechnologie 17 Objektorientierte Implementierung mit Java-Datenstrukturen Auswahl von Datenstrukturen Softwaretechnologie, © Prof. Uwe Aßmann, Prof. Heinrich Hussmann 18 Weitere Implementierungen in der CollectionHierarchie Vererbung (extends) <<interface>> Collection <<interface>> List Implementierung (implements) <<interface>> Set <<interface>> Map <<interface>> SortedSet <<interface>> SortedMap ArrayList LinkedList Vector Softwaretechnologie HashSet HashMap TreeSet Hashtable TreeMap 19 Welche Listen-Implementierung soll man wählen? Gemessener relativer Aufwand für Operationen auf Listen: (aus Eckel, Thinking in Java, 2nd ed., 2000) Typ Lesen Iteration Einfügen Entfernen array 1430 3850 --ArrayList 3070 12200 500 46850 LinkedList 16320 9110 110 60 Vector 4890 16250 550 46850 ► ► Stärken von ArrayList: ■ ► ► wahlfreier Zugriff Stärken von LinkedList: ■ Iteration ■ Einfügen und Entfernen irgendwo in der Liste Vector generell die langsamste Lösung Softwaretechnologie 20 Collection Framework (Überblick) Vererbung (extends) <<interface>> Collection <<interface>> List Implementierung (implements) <<interface>> Set <<interface>> SortedSet <<interface>> Map <<interface>> SortedMap ArrayList LinkedList HashSet HashMap TreeSet Softwaretechnologie TreeMap 21 Ungeordnete Mengen: java.util.Set (Auszug) public interface Set { public public public public public public ... public public ... public boolean add (Object o); boolean remove (Object o); void clear(); boolean isEmpty(); boolean contains (Object o); int size(); boolean equals (Object o); int hashCode(); Iterator iterator(); } Softwaretechnologie 22 Anwendungsbeispiel für Set Warengruppe – name: String – lagerplatz: String + add (a: Artikel) + anzahl(): int 1 * Artikel – name: String – preis: int + preis(): int Softwaretechnologie 23 java.util.HashSet (Auszug) public class HashSet implements Set ... { public HashSet (int initialCapacity, float loadFactor); ... public boolean add (Object o); public boolean remove (Object o); public void clear(); public boolean isEmpty(); public boolean contains (Object o); public int size(); public boolean equals (Object o); public int hashCode(); ... public Iterator iterator(); } (Anmerkung: Erläuterung von Hashfunktionen folgt etwas später !) Softwaretechnologie 24 Anwendungsbeispiel mit HashSet class Warengruppe { private String name; private String lagerplatz; private Set inhalt; public Warengruppe (String name, String lagerplatz) { this.name = name; this.lagerplatz = lagerplatz; this.inhalt = new HashSet(); } public void add (Artikel a) { inhalt.add(a); } public int anzahl() { return inhalt.size(); } public String toString() { String s = "Warengruppe "+name+"\n"; Iterator it = inhalt.iterator(); while (it.hasNext()) { s += " "+(Artikel)it.next(); }; Online: } Warengruppe0.java } Softwaretechnologie 25 Wann sind Objekte gleich? (1) ► ► Vergleich mit Operation == : ■ Referenzgleichheit, d.h. physische Identität der Objekte ■ Typischer Fehler: Stringvergleich mit "==" (ist nicht korrekt, geht aber meistens gut!) Vergleich mit o.equals(): ■ deklariert in java.lang.Object ■ überdefiniert in vielen Bibliotheksklassen . ■ z.B. java.lang.String für selbstdefinierte Klassen . Standardbedeutung Referenzgleichheit . bei Bedarf selbst überdefinieren ! (Ggf. für kompatible Definition der Operation o.hashCode() aus java.lang.Object sorgen) Online: Warengruppe1.java Softwaretechnologie 26 Wann sind Objekte gleich? (2) public static void main (String[] args) { Warengruppe w1 = new Warengruppe("Moebel","L1"); w1.add(new Artikel("Tisch",200)); w1.add(new Artikel("Stuhl",100)); w1.add(new Artikel("Schrank",300)); w1.add(new Artikel("Tisch",200)); System.out.println(w1); } Systemausgabe beim Benuten der Standard-Gleichheit: Warengruppe Moebel Tisch(200) Tisch(200) Schrank(300) Stuhl(100) Online: Warengruppe0.java Softwaretechnologie 27 Wann sind Objekte gleich? (3) public static void main (String[] args) { Artikel tisch = new Artikel("Tisch",200); Artikel stuhl = new Artikel("Stuhl",100); Artikel schrank = new Artikel("Schrank",300); } Warengruppe w2 = new Warengruppe("Moebel","L2"); w2.add(tisch); w2.add(stuhl); w2.add(schrank); w2.add(tisch); System.out.println(w1); Systemausgabe: Warengruppe Moebel Schrank(300) Tisch(200) Stuhl(100) Es wurde zweifach dasselbe Tisch-Objekt übergeben ! (Gleiches Verhalten bei Strukturgleichheit, s. Warengruppe1.java) Softwaretechnologie 28 Delegation vs. Vererbung class Warengruppe { … private Set inhalt; } Delegation public Warengruppe (…) { … this.inhalt = new HashSet(); } public void add (Artikel a) { inhalt.add(a); } … class Warengruppe extends HashSet { … Vererbung public Warengruppe (…) { super(); … } … // keine explizite add-Operation nötig ! } Warengruppe2.java Softwaretechnologie 29 java.util.SortedSet (Auszug) public interface SortedSet extends Set { public public public public public public ... public public public ... public public boolean add (Object o); boolean remove (Object o); void clear(); boolean isEmpty(); boolean contains (Object o); int size(); boolean equals (Object o); int hashCode(); Iterator iterator(); Object first(); Object last(); ... } Softwaretechnologie 30 java.util.TreeSet ► java.util.TreeSet implementiert ein geordnete Menge und benötigt Schnittstelle Comparable ► Modifi kation der Klasse Warengruppe: ► class Warengruppe { private Set inhalt; public Warengruppe (…) { … this.inhalt = new TreeSet(); } … Systemreaktion: } Exception in thread "main" java.lang.ClassCastException: Artikel at java.util.TreeMap.compare(TreeMap.java, Compiled Code) ► java.util.TreeSet: public class TreeSet … implements SortedSet … { … } Softwaretechnologie 31 Anwendungsbeispiel mit TreeSet ► Artikel muss von Schnittstelle Comparable erben ► Modifikation der Klasse „Artikel“: class Artikel implements Comparable { ... public int compareTo (Object o) { return name.compareTo(((Artikel)o).name); } } Systemausgabe: Warengruppe Moebel Schrank(300) Stuhl(100) Tisch(200) Online: Warengruppe3.java Softwaretechnologie 32 HashSet oder TreeSet? ► Gemessener relativer Aufwand für Operationen auf Mengen: (aus Eckel, Thinking in Java, 2nd ed., 2000) Typ HashSet TreeSet ► Enthalten 106,5 177,4 Iteration 39,39 40,04 Stärken von HashSet: ■ ► Einfügen 36,14 150,6 in allen Fällen schneller ! Stärken von TreeSet: ■ erlaubt Operationen für sortierte Mengen Softwaretechnologie 33 Collection Framework (Überblick) Vererbung (extends) <<interface>> Collection <<interface>> List Implementierung (implements) <<interface>> Set <<interface>> SortedSet <<interface>> Map <<interface>> SortedMap ArrayList LinkedList HashSet HashMap TreeSet Softwaretechnologie TreeMap 34 java.util.Map (Auszug) public interface Map { ... public boolean containsKey (Object key); public boolean containsValue (Object value); public Object get (Object key); public Object put (Object key, Object value); public Object remove (Object key); public int size(); public Set keySet(); public Collection values(); ... } Eine Map ist ein „assoziativer Speicher“ (associative array) Softwaretechnologie 35 Anwendungsbeispiel Katalog – name: String + put (code: String, a: Artikel) + get (code: String): Artikel + anzahl(): int code: String * 1 Artikel – name: String – preis: int HashMap ist eine sehr günstige Umsetzung für qualifizierte Assoziationen: Der Qualifikator bildet den Schlüssel; die Zielobjeke den Wert + preis(): int Softwaretechnologie 36 Anwendungsbeispiel mit HashMap class Katalog { private String name; private Map inhalt; public Katalog (String name) { this.name = name; this.inhalt = new HashMap(); } public void put (String code, Artikel a) { inhalt.put(code,a); } public int anzahl() { return inhalt.size(); } public Artikel get (String code) { return (Artikel)inhalt.get(code); } ... Online: } Katalog.java Softwaretechnologie 37 Testprogramm für Anwendungsbeispiel: Speicherung der Waren mit Schlüsseln public static void main (String[] args) { Artikel tisch = new Artikel("Tisch",200); Artikel stuhl = new Artikel("Stuhl",100); Artikel schrank = new Artikel("Schrank",300); Artikel regal = new Artikel("Regal",200); } Katalog k = new Katalog("Katalog1"); Systemausgabe: k.put("M01",tisch); Katalog Katalog1 k.put("M02",stuhl); M03 -> Schrank(300) M02 -> Stuhl(100) k.put("M03",schrank); M01 -> Tisch(200) System.out.println(k); Katalog Katalog1 k.put("M03",regal); M03 -> Regal(200) M02 -> Stuhl(100) System.out.println(k); M01 -> Tisch(200) put(...) überschreibt vorhandenen Eintrag (Ergebnis = vorhandener Eintrag). Ordnung auf den Schlüsseln: SortedMap (Implementierung z.B.TreeMap). Softwaretechnologie 38 Prinzip der Hashtabelle ► Typischerweise wird der Schlüssel (key) vor dem Einstechen auf einen Zahlenbereich modulo der Kapazität der Hashtabelle abgebildet, d.h., der Schlüssel wird auf die Hashtabelle “normiert” (hash code) hashtab Object 0 hashCode(): int key: Object key.hashCode() value: Object value: Object Effekt von hashtab.put(key,value) Softwaretechnologie capacity 39 Kollision beim Einstechen ► Die Hashfunktion ist mehrdeutig (nicht injektiv): ■ Bei nicht eindeutigen Schlüsseln, oder auch durch die Normierung, werden Einträge doppelt “adressiert” (Kollision) 0 key1: Object value1: Object key2: Object key1.hashCode() value?: Object = key2.hashCode() value2: Object Verfahren zur Kollisionsauflösung: – Überlauflisten – Überlauf in der Hashtabelle Softwaretechnologie capacity 40 Vorgehensweise beim Datenstruktur-Entwurf Identifi kation der Anforderungen an die Datenstruktur: Funktionalität, häufi g benutzte Operationen Abstraktion auf die wesentlichen Eigenschaften Suche nach vorgefertigten Lösungen (Nutzung der Collection-Bibliothek) Ggf. Experimente (experimentelle Prototypen) Anpassung an vorgefertigte Lösung Softwaretechnologie Entwicklung einer neuartigen Lösung 41 Suche nach vorgefertigten Lösungen (Collection-Klassen der Bibliothek) Collection Map Einfügen eines Elements Entfernen eines Elements Aufzählen aller Elemente "ist enthalten"-Abfrage dynamisch erweiterbar Einfügen eines Werts für einen Schlüssel Entfernen eines Schlüssel/Wert-Paars Abfrage eines Werts für einen Schlüssel "ist enthalten"-Abfrage für Schlüssel dynamisch erweiterbar Einfügereihenfolge relevant? ja Sortierung der Schlüssel relevant? SortedMap nein List Abfrage an i-ter Position Set Sortierung relevant? Ersetzen an i-ter Position SortedSet kleinstes/größtes Element Entfernen an i-ter Position Elemente "über"/"unter" x Softwaretechnologie 42 Beispiel: Realisierung von Assoziationen A * assoc B Datenstruktur im A-Objekt für B-Referenzen Anforderung 1) Assoziation anlegen 2) Assoziation entfernen 3) Durchlaufen aller bestehenden Assoziationen zu B-Objekten 4) Manchmal: Abfrage, ob Assoziation zu einem B-Objekt besteht 5) Keine Obergrenze der Multiplizität gegeben Realisierung 1) Einfügen (ohne Reihenfolge) 2) Entfernen (ohne Reihenfolge) 3) Aufzählen aller Elemente 4) "ist enthalten"-Abfrage 5) Maximalanzahl der Elemente unbekannt; dynamisch erweiterbar Set Softwaretechnologie 43 Realisierung von ungeordneten Assoziationen mit Set A assoc * B class A { private Set assoc; ... public void addAssoc (B b) { assoc.add(b); } public boolean testAssoc (B b) { return assoc.contains(b); } public A { ... assoc = new HashSet(); } Softwaretechnologie 44 Beispiel: Raumverwaltung static Besprechungsraum freienRaumSuchen (int groesse, Hour beginn, int dauer) ► Suche unter vorhandenen Räumen nach Raum mit mindestens der Kapazität groesse, aber möglichst klein. ■ Datenstruktur für vorhandene Räume in Klasse Raumverwaltung » SortedSet (Elemente: Besprechungsraum) ► Überprüfung eines Raumes, ob er für die Zeit ab beginn für die Länge dauer bereits belegt ist. ■ Operation in Klasse Besprechungsraum: boolean frei (Hour beginn, int dauer) ■ Datenstruktur in Klasse Besprechungsraum für Zeiten (Stunden): » Set (Elemente: Hour) ► Zusatzanforderung (Variante): Überprüfung, welcher andere Termin eine bestimmte Stunde belegt. ■ Datenstruktur in Klasse Besprechungsraum: » Map (Schlüssel: Hour, Wert: Teambesprechung) Softwaretechnologie 45 Raumverwaltung: Freien Raum suchen class Raumverwaltung { } private static SortedSet vorhandeneRaeume = new TreeSet(); // Vorhandene Raeume, aufsteigend nach Groesse sortiert static Besprechungsraum freienRaumSuchen (int groesse, Hour beginn, int dauer) { Besprechungsraum r = null; boolean gefunden = false; Iterator it = vorhandeneRaeume.iterator(); while (! gefunden && it.hasNext()) { r = (Besprechungsraum)it.next(); if (r.grossGenug(groesse)&& r.frei(beginn,dauer)) gefunden = true; }; if (gefunden) return r; else return null; } ... Softwaretechnologie 46 Objektorientierte Implementierung mit Java-Datenstrukturen Persistente Datenhaltung Art is long, and Time is fleeting. H. W. Longfellow Softwaretechnologie, © Prof. Uwe Aßmann, Prof. Heinrich Hussmann 47 Temporäre und persistente Daten ► Daten sind ■ temporär, wenn sie mit Beendigung des Programms verloren gehen, das sie verwaltet; ■ persistent, wenn sie über die Beendigung des verwaltenden Programms hinaus erhalten bleiben. ► Objektorientierte Programme benötigen Mechanismen zur Realisierung der Persistenz von Objekten. ► Möglichkeiten zur Realisierung von Objekt-Persistenz: ■ ■ Einsatz eines Datenbank-Systems . Objektorientiertes Datenbank-System . Relationales Datenbank-System Java: Java Data Base Connectivity (JDBC) . Zugriffsschicht auf Datenhaltung Java: Java Data Objects (JDO) Speicherung von Objektstrukturen in Dateien . Objekt-Serialisierung (Object Serialization) Softwaretechnologie 48 Objekt-Serialisierung in Java ► Die Klassen java.io.ObjectOutputStream und java.io.ObjectInputStream stellen Methoden bereit, um ein Geflecht von Objekten linear darzustellen (zu serialisieren) bzw. aus dieser Darstellung zu rekonstruieren. ► Eine Klasse, die Serialisierung zulassen will, muß die (leere!) Schnittstelle java.io.Serializable implementieren. class ObjectOutputStream { public ObjectOutputStream (OutputStream out) throws IOException; public void writeObject (Object obj) throws IOException; } Softwaretechnologie 49 Objekt-Serialisierung: Abspeichern import java.io.*; class XClass implements Serializable { private int x; public XClass (int x) { this.x = x; } } ... XClass xobj; ... FileOutputStream fs = new FileOutputStream("Xfile.dat"); ObjectOutputStream os = new ObjectOutputStream(fs); os.writeObject(xobj); ... Softwaretechnologie 50 Objekt-Serialisierung: Einlesen import java.io.*; class XClass implements Serializable { private int x; public XClass (int x) { this.x = x; } } ... XClass xobj; ... FileInputStream fs = new FileInputStream("Xfile.dat"); ObjectInputStream os = new ObjectInputStream(fs); xobj = (XClass) os.readObject(); Softwaretechnologie 51 The End ► Diese Folien sind eine überarbeitete Version der Vorlesungsfolien zur Vorlesung Softwaretechnologie von © Prof. H. Hussmann, 2002. used by permission. Softwaretechnologie 52