730 likes | 939 Views
2. Interfaces vs. abstrakte Klassen. Vorteile von InterfacesKlassen k?nnen mehrere Interfaces implementierenexistierende Klassen k?nnen einfach um die Implementierung eines Interfaces erweitert werdeneinfache Deklaration von typ?bergreifenden FunktionenNachteile von Interfaces?nderung des Inter
E N D
1. Modellierung und Programmierung 2 Professur für Angewandte Telematik / e-Business
Institut für Informatik
Universität Leipzig
Stiftungsprofessur der DTAG
info@ebus.informatik.uni-leipzig.de
www.lpz-ebusiness.de
+49 (341) 97 323 30
2. 2 Interfaces vs. abstrakte Klassen Vorteile von Interfaces
Klassen können mehrere Interfaces implementieren
existierende Klassen können einfach um die Implementierung eines Interfaces erweitert werden
einfache Deklaration von typübergreifenden Funktionen
Nachteile von Interfaces
Änderung des Interfaces muss in allen implementierenden Klassen nachvollzogen werden
Das Objekt KANN etwas Vorteile von abstrakten Klassen
ermöglichen die Vererbung von implementierten Methoden
können einfach um zusätzliche Methoden erweitert werden (sofern diese bereits implementiert sind)
Nachteile von abstrakten Klassen
Vererbungshierarchie erlaubt nur eine Oberklasse
Klassenhierarchie u.U. schwierig nachträglich änderbar
Das Objekt IST EIN…
3. 3 Entwurfsmuster Im objektorientierten Entwurf existieren für viele häufig wiederkehrende Detailanforderungen allgemeine Lösungen, sog. Entwurfsmuster (Design Patterns):
zur Realisierung bestimmter Objektstrukturen(z.B. Singleton, Factory, Composite, ...)
zur Interaktion von Objekten mit bestimmten Verhaltensweisen(z.B. Iterator, Observer, Transaction, ...)
zur Kooperation und Entkopplung von Systemkomponenten(z.B. Facade, Adapter, Model-View-Controller, ...)
Ziel: effektive Anwendung von OO-Konzepten
4. 4 Literatur: Entwurfsmuster Entwurfsmuster von Kopf bis Fuß, O'Reilly 2005
Erich Gamma et al.: Design Patterns. Elements of Reusable Object-Oriented Software.Addison-Wesley, 1995
Stephen Stelting, Olav Massen: Applied Java Patterns. Prentice Hall, 2001
5. 5
6. 6
7. public class Kunde {
private enum Status {NEUKUNDE, KUNDE, SAMMELBESTELLER}
private Status status;
public String[] gueltigeZahlungsweisen() {
switch (status) {
case NEUKUNDE:
// Zahlungsweisen für Neukunden
break;
case KUNDE:
// Zahlungsweisen für Altkunden
break;
case SAMMELBESTELLER:
// Zahlungsweisen für Sammelbesteller
}
} 7
8. public int berechneRabatt() {
switch (status) {
case NEUKUNDE:
// Rabatt für Neukunden
break;
case KUNDE:
// Rabatt für Altkunden
break;
case SAMMELBESTELLER:
// Rabatt für Sammelbesteller
}
} 8
9. 9
10. Übernahme einer britischen Firma…
Neue Geschäftsregeln:
Kunden in Großbritannien erhalten natürlich eine englische Rechnung.
Für Kunden in Großbritannien ist die Zahlungsweise "Scheck" nicht zugelassen. 10
11. 11
12. 12
13. (schlechte) erste Idee: Vererbung 13
14. Was erbt wirklich voneinander? 14
15. 15
16. 16
17. 17
18. Das Strategy-Muster 18
19. Strategy Vorteil des Strategy-Musters:
Welcher Algorithmus (von mehreren möglichen) genau verwendet wird, wird zur Laufzeit entschieden.
Über eine set-Methode kann die modellierte Eigenschaft später geändert werden ? der Algorithmus ändert sich mit.
Die Algorithmen sind in getrennten Klassen programmiert, Änderungen werden so leichter.
Mehrfachverzweigung (case…) wird vermieden
Neu gegenüber bisheriger Modellierung:Unterschied fachliche Klassen / technische Klassen 19
20. Das Strategy-Muster – ein Beispiel 20
21. Beispiel: Kontext public class StringCompressor {
// die Variable für die Strategie
private Compressor compressor;
private String text;
public StringCompressor(Compressor compressor )
{ this.compressor = compressor; }
String compress(String text) {
// uebergib dem Komprimierer die Aufgabe
// (siehe spätere Folie)
}
} 21
22. Das Strategy-Muster 22
23. Beispiel: Interface Strategie public interface Compressor {
// Methode zum Komprimieren
String compress (String s);
} 23
24. Das Strategy-Muster 24
25. Beispiel: konkrete Strategie public class ZIPCompressor implements Compressor {
// ZIP - Verfahren zum Komprimieren
public String compress (String text) {
// komprimiere mittels ZIP – Verfahren:
text_gepackt= …
return text_gepackt;
}
} 25
26. Aufruf in der Klasse StringCompressor if (text.length() < 1000000)
compressor = new Compressor (new ZIPCompressor());
else
compressor = new Compressor (new HuffmanCodeCompressor());
String gepackt = compressor.compress(text); 26
27. Die Rechnung bitte… 27
28. Geschäftsregeln für Rechnung Rechnungen basieren auf einem einheitlichen "Grundtext". Davon gibt es einen für eine Erstrechnung, eine Zahlungserinnerung, und eine Sammelrechnung.
Dem werden ggf. weitere Texte hinzugefügt:
Wenn das Kundenkonto ein Guthaben aufweist, wird beschrieben, wie dieses auf den Rechnungsbetrag angerechnet wird.
3 Wochen vor Jahresende wird der Kunde darauf hingewiesen, dass die Rechnung noch in diesem Jahr bezahlt werden sollte, um besondere Steuervorteile nutzen zu können.
Wenn die Rechnungsadresse von der Lieferadresse abweicht, wird dies in der Rechnung erwähnt.
… und noch etwa 100 weitere solche Regeln. 28
29. (schlechte) erste Idee 29
30. 30
31. Wir nehmen ein Sammelrechnung- Objekt.
Wir fügen diesem lt. Geschäftsregel einen Zusatz hinzu.
Das neue Objekt enthält das
bisherige.
Das neue Objekt ist selbst
wieder eine Rechnung. 31
32. … dann noch einen Zusatz
… und noch einen… 32
33. 33
34. 34
35. 35
36. Decorator-Muster allgemein 36
37. 37
38. 38
39. 39
40. 40
41. 41
42. 42
43. 43
44. 44
45. Aufruf 45
46. eine Anwendung des decorator-Musters streams 46
47. 47 Exkurs: Das Paket Paket java.io
48. 48 Dateisystem: Dateien Datenspeicherung auf Festplatte, CD, DVD etc. in Dateisystemen aus
Dateien (enthalten eigentliche Daten) und
Verzeichnisstruktur (organisiert Dateien)
Dateien haben Attribute
Name, Länge, Datum etc.
Verzeichnisstruktur organisiert Dateien
Baumstruktur
49. 49 Modellierung des Dateisystems in Java mit Objekten der Klasse java.io.File zum
Anlegen, Öffnen, Schließen und Löschen von Dateien
Anlegen und Löschen von Verzeichnissen
Abfragen/Setzen von Informationen über Dateien und Verzeichnisse
Blättern in der Verzeichnishierarchie
nicht zum Lesen und Schreiben in Dateien!
wird mit Streams realisiert
Beispiel: Länge ausgeben, wenn "java" existiert und eine Datei (kein Verzeichnis) ist
File datei = new File("java");
if (datei.exists() && datei.isFile()) {
System.out.println(datei.length() + " Bytes");
}
50. 50 präzise betrachtet, modelliert ein File-Objekteinen Pfad, der eine Datei/ein Verzeichnis identifiziert
u.a. mit folgenden Konstruktoren instanziierbar:
aus einem String:
public File(String pathname)
aus einem bereits modellierten Pfadund einem anzuhängenden String:
public File(File parent, String child)
aus zwei Strings:
public File(String parent, String child)
weitere Möglichkeiten ? Java API Specification Anlegen eines File-Objekts
51. 51 Format von Pfadnamen ist plattformspezifisch
Verzeichnis-Trennzeichen (z.B. Windows: \; Unix: /)
public static final String separator
Wurzelverzeichnisse (z.B. Windows: A:\, C:\, ...; Unix: /)
public static File[] listRoots()
Schnittstellen zwischen abstrakter Pfad-Modellierung im File-Objekt und plattformspezifischen Pfadnamen
Datei-/Verzeichnisname: public String getName()
Pfadname: public String getPath()
kanonischer Pfadname: public String getCanonicalPath()
übergeordneter Pfad: public String getParent()
äquivalente Methoden auch mit Rückgabetyp File, um mit den umgeformten Pfaden in abstrakter Form weiter zu arbeiten ? API Arbeit mit Pfadnamen in File
52. 52 Methoden zur Abfrage diverser Eigenschaftenvon durch File identifizierten Dateien/Verzeichnissen:
public boolean exists()
public boolean canRead()
public boolean canWrite()
public boolean isFile()
public boolean isDirectory()
public boolean isHidden()
public long length()
public long lastModified()
public boolean equals(Object o)
public int compareTo(File pathname)
public String toString()
und viele mehr ? Java API Specification Prüfen von Eigenschaften mit File
53. 53 leere Datei anlegen
public boolean createNewFile()
Verzeichnis anlegen
public boolean mkdir() nur letztes Verzeichnis im Pfad
public boolean mkdirs() ggf. incl. Mutterverzeichnisse
Datei/Verzeichnis löschen
public boolean delete() sofort
public void deleteOnExit() erst bei Beendigung der JVM
Datei umbenennen
public boolean renameTo(File dest)
Änderungsdatum setzen
public boolean setLastModified(long time)
Schreibschutz setzen
public boolean setReadOnly() Datei/Verzeichnis-Operationen auf File
54. 54 wenn das File-Objekt ein Verzeichnis identifiziert:
alle im Verzeichnis enthaltene Einträge
public String[] list()
allen im Verzeichnis enthaltenen Einträge,die bestimmten Filterkriterien entsprechen
public String[] list(FilenameFilter filter)
Festlegung der Filterkriterien ist dem Entwickler überlassen
werden definiert in einem Objekt, das das Interface FilenameFilter implementiert Auflistung von Verzeichnisinhalten
55. 55 Herausforderungen bei der Datenübertragung verschiedene Datenformate
Bytes oder Unicode-Zeichen
viele verschiedene Datenquellen und -senken
Dateisystem, Datenstrukturen, Netzwerk, andere Threads
viele verschiedene Datentypen
primitive Typen, Strings, Klassen (eigene oder von Java)
viele verschiedene Vor-/Nachverarbeitungsmöglichkeiten
puffern, codieren, komprimieren...
eigene Lösung dieser Herausforderungen wäre aufwendig, oft redundant und u.U. nicht plattformunabhängig Java I/O is based on the concept of streams. This is the technique used in C++. A stream is a connection between a source or a sink and a program. Bytes flow from the source one at a time into the program and from the program to the sink in the same way. A stream providing input is an input stream. A stream accepting output is an output stream.
There are two abstract classes associated with I/O streams. As with all abstract classes they collect in one place all the essential functions that a stream should implement. The two classes are InputStream and OutputStream. as we shall see these two classes stand at the top of two large hierarchies of streams. The philosophy of Java is to provide a vast collection of streams so that the compiler can check that a user is not accidentally misusing a stream by carrying out an illegal operation on it. C in contrast has one stream type FILE*. Visual Basic has three. C++ has more stream classes than these languages but not as many as Java 1.1 which has 58!
Classes which inherit from InputStream or OutputStream are based on single byte input or output. If Java used standard ASCII this would be sufficient for character I/O. However in Java, characters are represented by 16 bit Unicode characters. For this reason two further abstract classes Reader and Writer and their associated hierarchies are required to implement character I/O.
Java I/O is based on the concept of streams. This is the technique used in C++. A stream is a connection between a source or a sink and a program. Bytes flow from the source one at a time into the program and from the program to the sink in the same way. A stream providing input is an input stream. A stream accepting output is an output stream.
There are two abstract classes associated with I/O streams. As with all abstract classes they collect in one place all the essential functions that a stream should implement. The two classes are InputStream and OutputStream. as we shall see these two classes stand at the top of two large hierarchies of streams. The philosophy of Java is to provide a vast collection of streams so that the compiler can check that a user is not accidentally misusing a stream by carrying out an illegal operation on it. C in contrast has one stream type FILE*. Visual Basic has three. C++ has more stream classes than these languages but not as many as Java 1.1 which has 58!
Classes which inherit from InputStream or OutputStream are based on single byte input or output. If Java used standard ASCII this would be sufficient for character I/O. However in Java, characters are represented by 16 bit Unicode characters. For this reason two further abstract classes Reader and Writer and their associated hierarchies are required to implement character I/O.
56. 56 Lösung in Java: Datenströme (Streams) generelle Konstrukte mit der Fähigkeit,
Daten von einer Datenquelle zu empfangen
Daten an eine Datensenke zu senden
ein bestimmter Stream weiß, wie ein bestimmtes Problem (Quellen-/Senkentyp, Datentyp, Verarbeitung) zu lösen ist
Java hat Stream-Klassen für verschiedenste Aufgaben
Entwickler muss sich nicht um Details kümmern, sondern ruft einfach Methoden wie "lesen" oder "schreiben" auf
Streams erlauben i.d.R. nur fortlaufenden Datenzugriff
wahlfreier Zugriff bei einigen Streams über Methoden mark() und reset() oder mit Klasse RandomAccessFile möglich ? API
57. 57 Grundlegende (abstrakte) Stream-Klassen Unterscheidung nach Datenflussrichtung
Eingabestreams vs. Ausgabestreams
Unterscheidung nach Datenformat
Bytestreams
lesen/schreiben einzelne Bytes
Zeichenstreams
lesen/schreiben Unicode-Zeichen
vier abstrakte Oberklassen für alle Stream-Arten von Java:
für Bytes für Zeichen
zur Eingabe InputStream Reader
zur Ausgabe OutputStream Writer
58. 58 Eingabestreams (abstrakt) InputStream Reader
int available() boolean ready()
liefert Zahl lesbarer Bytes einlesbare Zeichen vorhanden?
int read() int read()
nächstes Byte lesen nächstes Zeichen lesen
liefert 0-255 oder -1 (Ende) liefert 0-65535 oder -1 (Ende)
int read(byte[] b) int read(char[] c)
Bytes in Array einlesen Zeichen in Array einlesen
liefert Zahl gelesener Bytes liefert Zahl gelesener Zeichen
void close() void close()
Stream schließen Stream schließen
(Öffnen der Streams implizit beim Konstruktoraufruf)
alle Methoden werfen bei Fehlern java.io.IOException
59. 59 Ausgabestreams (abstrakt) OutputStream Writer
void write(int b) void write(int c)
übergebenes Byte schreiben übergebenes Zeichen schreiben
(nur untere 8 Bits betrachtet) (nur untere 16 Bits betrachtet)
void write(byte[] b) void write(char[] c)
Bytes aus Array schreiben Zeichen aus Array schreiben
void write(String s)
Zeichen aus String schreiben
void flush() void flush()
gepufferte Bytes schreiben gepufferte Zeichen schreiben
void close() void close()
Stream schließen Stream schließen
(Öffnen der Streams implizit beim Konstruktoraufruf)
alle Methoden werfen bei Fehlern java.io.IOException
60. 60 Eigenschaften von Streams
Lesen und Schreiben blockiert Ausführung (des Threads)
Methoden warten, bis etwas gelesen oder geschrieben wurde
Achtung: falls keine zu lesenden Daten vorliegen, steht read() !
available() blockiert nicht und kann zur Prüfung verwendet werden, um zu lesende Daten vorliegen
Streams sollten mit close() geschlossen werden. The mechanism shown on the previous slide means that methods read() and write() are rarely used explicitly in programs. They are usually invoked indirectly by methods of a subclass of InputStream or OutputStream.
Regardless of whether they are explicitly called or not, calls to read() and write() cause a thread to block.
In the case of an input operation a thread which calls read() may block because the data it requires is not yet available. The method available() returns an int which gives the number of bytes which are available for reading. Threads that wish to avoid waiting for input can make use of this method by not invoking read() when there are no bytes available..
All streams require buffer space etc. When a stream is no longer required this buffer space can be released. All I/O streams implement a method close() which will achieve this.
In order to optimise disk I/O, streams will buffer data. Typically an output stream will hold data in main memory until enough has been generated to make it worthwhile to write to disk. The programmer can cause buffers to be emptied on demand by invoking the method flush().
The mechanism shown on the previous slide means that methods read() and write() are rarely used explicitly in programs. They are usually invoked indirectly by methods of a subclass of InputStream or OutputStream.
Regardless of whether they are explicitly called or not, calls to read() and write() cause a thread to block.
In the case of an input operation a thread which calls read() may block because the data it requires is not yet available. The method available() returns an int which gives the number of bytes which are available for reading. Threads that wish to avoid waiting for input can make use of this method by not invoking read() when there are no bytes available..
All streams require buffer space etc. When a stream is no longer required this buffer space can be released. All I/O streams implement a method close() which will achieve this.
In order to optimise disk I/O, streams will buffer data. Typically an output stream will hold data in main memory until enough has been generated to make it worthwhile to write to disk. The programmer can cause buffers to be emptied on demand by invoking the method flush().
62. 62 konkrete Streams Unterklassen zur Erfüllung bestimmter Aufgaben
Lesen/Schreiben aus/in Datenquellen/-senken
Verwendung anderer Streams als Datenquellen/-senken
Vor/-Nachverarbeitung der Daten im Stream
Ein/-Ausgabe verschiedener Datentypen
i.d.R. müssen mehrere (aber nicht unbedingt alle)dieser Aufgaben gelöst werden
63. 63 Streams zum Medien-Zugriff Zugriff auf verschiedene Quellen/Senken
Lesen/Schreiben aus/in Dateien im Dateisystem
FileInputStream FileReader
FileOutputStream FileWriter
Lesen/Schreiben aus/in Datenstrukturen im Hauptspeicher
ByteArrayInputStream CharArrayReader
ByteArrayOutputStream CharArrayWriter
Lesen/Schreiben aus/in Netzwerken
später behandelt
65. 65 Verwendung von Medienstreams Beispiel: FileOutputStream
Konstruktor öffnet die Datei und
überschreibt ggf. zuvor bestehende Datei
FileOutputStream(File file)
FileOutputStream(String name)
hängt bei append==true an Datei an, überschreibt sonst ggf.
FileOutputStream(File file, boolean append)
FileOutputStream(String name, boolean append)
(alle können FileNotFoundException werfen)
implementiert Methoden vom abstrakten OutputStream
write (Byte oder Byte-Array schreiben), flush (Puffer leeren), etc.
arbeiten auf der vom Stream gekapselten Datei
67. 67 Streams zur Verknüpfung von Streams
Wandeln zwischen Byte- und Unicode-Streams:
InputStreamReader
OutputStreamWriter
Lesen von Daten aus mehreren Streams nacheinander
SequenceInputStream
68. 68 Streams zur Filterung von Daten Verarbeitung oder Veränderung ("Filterung") von Daten
Zwischenspeicherung von Daten in einem Puffer
BufferedInputStream BufferedReader
BufferedOutputStream BufferedWriter
Lesen/Schreiben von Daten mit (De-)Komprimierung
java.util.zip.InflaterInputStream
java.util.zip.DeflaterOutputStream
Lesen/Schreiben von Daten mit Ent-/Verschlüsselung
javax.crypto.CipherInputStream
javax.crypto.CipherOutputStream
71. Text packen und speichern
72. 72 Verw. von Verknüpfungs-/Filterstreams Beispiel: BufferedOutputStream
Konstruktor nimmt zugrundeliegenden Streamund ggf. Puffergröße entgegen
BufferedOutputStream(OutputStream out)
BufferedOutputStream(OutputStream out, int size)
Methoden wie abstrakter OutputStream
write (Byte oder Byte-Array schreiben), flush (Puffer leeren), etc.
Daten werden in objektinternem Puffer zwischengespeichert
bei Erreichen der angegebenen Größe (oder Vorgabe 512 Bytes):
Pufferinhalt wird in den zugrundeliegenden OutputStream geschrieben; Pufferinhalt wird gelöscht
Zyklus beginnt von vorn
73.
ZipOutputStream z =
new ZipOutputStream(
new BufferedOutputStream(
new FileOutputStream(f))));
- ein zweifach dekorierter FileOutputStream 73
74. 74 Implementierung eigener Stream-Filter Oberklassen zur Definition eigener Filter
FilterInputStream FilterReader
FilterOutputStream FilterWriter
eigene Filter bekommen im Konstruktor den zugrundeliegenden Stream übergeben
zugrundeliegender Stream wird mit super(stream);zur Verknüpfung an Oberklasse weitergegeben
nötige Methoden der Oberklasse sind zu überschreiben.