31b-programming-agai..
Transcrição
31b-programming-agai..
Objektorientierte Implementierung 2 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 Klausur Softwaretechnologie WS 06/07 am 7. Februar 2007 ► Einschreibung bis in 2 Wochen ► Softwaretechnologie 2 Einschreibung in das Softwarepraktikum SS 2007 ► Einschreibung erfolgt für ALLE Studenten (auch für ISTler) über www.jexam.de ■ Externes Praktikum bis 9. Februar 2007 ■ Internes Praktikum (SalesPoint) bis 8. März 2007 ► Achtung! Entweder in das externe oder in das interne Praktikum einschreiben. ► Wer keinen externen Praktikumsplatz erhält, bekommt bei erfüllter Zulassungsvoraussetzung automatisch einen internen Praktikumsplatz. ► Über den Erhalt/Nichterhalt eines externen Praktikumsplatzes werden Sie persönlich bis spätestens Ende März per Email benachrichtigt. Teamwünsche bitte an Falk Hartmann ([email protected]) senden. Die Berücksichtigung von Teamwünschen kann nicht garantiert werden. ► Softwaretechnologie 3 Objektorientierte Implementierung mit Java-Datenstrukturen 1 Verfeinern von Assoziationen mit dem Java-2 Collection Framework 2 Programmieren gegen Schnittstellen 3 Auswahl von Datenstrukturen 4 Persistente Datenhaltung Softwaretechnologie 4 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 5 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 6 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 definiert auf Bestellposition Spezialisierung von Object auf Bestellposition? Softwaretechnologie 7 Typanpassungen auf Elementtypen * Bestellung – kunde: String – anzahl: int 1 Object java.util.ArrayList add(Object o) liste get(pos: int): Object ... Zusicherung: Alle von einem BestellungObjekt über die listeAssoziation erreichbaren Objekte sind aus der Klasse Bestellposition. * Bestell position 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 8 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 9 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: Softwaretechnologie Bestellung3.java 10 Polymorphe Container durch Schnittstellen Softwaretechnologie, © Prof. Uwe Aßmann, Prof. Heinrich Hussmann 11 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 12 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 ! 13 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 14 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 15 Verhaltensmuster 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 Element Softwaretechnologie <<create>> ConcreteIterator 16 Iterator-Beispiel in der JDK (ArrayList) <<interface>> java.util.Iterator Iterator hasNext() next() Aggregate Bestellung – kunde: String – anzahl: int 1 java.util.ArrayList add(o: Object) liste get(pos: int): Object <<create>> iterator(): Iterator Klassenname nicht ... bekannt, weil privat * Element Softwaretechnologie Concrete Iterator (z.B. ArrayListIterator) Object 17 Iterator-Implementierungsmuster ► Verwendungsbeispiel: List list; .. Iterator i = list.iterator(); while (i.hasNext()) { doSomeThing(i.next()); } Softwaretechnologie 18 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 19 Objektorientierte Implementierung mit Java-Datenstrukturen 3 Auswahl von Datenstrukturen Softwaretechnologie, © Prof. Uwe Aßmann, Prof. Heinrich Hussmann 20 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 21 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 22 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 23 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 24 Anwendungsbeispiel für Set Warengruppe – name: String – lagerplatz: String + add (a: Artikel) + anzahl(): int 1 * Artikel – name: String – preis: int + preis(): int Softwaretechnologie 25 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 26 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 27 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 28 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 29 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 30 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 31 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 32 java.util.TreeSet ► java.util.TreeSet implementiert ein geordnete Menge und benötigt Schnittstelle Comparable ► Modifikation 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 33 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 34 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 35 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 36 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 37 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 38 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 39 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 40 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 41 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 42 Vorgehensweise beim Datenstruktur-Entwurf Identifikation der Anforderungen an die Datenstruktur: Funktionalität, häufig benutzte Operationen Abstraktion auf die wesentlichen Eigenschaften Suche nach vorgefertigten Lösungen (Nutzung der CollectionBibliothek) Ggf. Experimente (experimentelle Prototypen) Anpassung an vorgefertigte Lösung Softwaretechnologie Entwicklung einer neuartigen Lösung 43 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ügereihenfolge relevant? ja 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 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 44 Beispiel: Realisierung von Assoziationen A * assoc B Datenstruktur im AObjekt für BReferenzen Anforderung Realisierung 1) Assoziation anlegen 1) Einfügen (ohne Reihenfolge) 2) Assoziation entfernen 2) Entfernen (ohne Reihenfolge) 3) Durchlaufen aller bestehenden Assoziationen zu BObjekten 3) Aufzählen aller Elemente 4) Manchmal: Abfrage, ob Assoziation zu einem BObjekt besteht 4) "ist enthalten"Abfrage 5) Keine Obergrenze der Multiplizität gegeben 5) Maximalanzahl der Elemente unbekannt; dynamisch erweiterbar Set Softwaretechnologie 45 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 46 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 47 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 48 Objektorientierte Implementierung mit Java-Datenstrukturen 4 Persistente Datenhaltung Art is long, and Time is fleeting. H. W. Longfellow Softwaretechnologie, © Prof. Uwe Aßmann, Prof. Heinrich Hussmann 49 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 . Softwaretechnologie Objekt-Serialisierung (Object Serialization) 50 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 51 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 52 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 53 The End ► Diese Folien sind eine überarbeitete Version der Vorlesungsfolien zur Vorlesung Softwaretechnologie von © Prof. H. Hussmann, 2002. used by permission. Softwaretechnologie 54