Prg08-Objekte und Interfaces
Transcrição
Prg08-Objekte und Interfaces
Programmieren 1 08 – Objekte und Interfaces Bachelor Medieninformatik Sommersemester 2015 Dipl.-Inform. Ilse Schmiedecke [email protected] Schmiedecke – Programmieren 1 1 Objektorientierung: Von Static zu Instance Klasse Novosketch bietet nur statische Methoden: Schmiedecke – Programmieren 1 2 Statisch – nur ein Zeichenfeld Wenn alles statisch ist, dann gibt es genau eine Zeichenfläche Mit NovoSketch.drawLineTo(...) wird genau in diese Zeichenfläche gemalt. Schmiedecke – Programmieren 1 3 3 Statische Initialisierung Dadurch, dass die Klasse NovoSketch im Programm benutzt (geladen) wird, wird sie initialisiert: die statischen Attribute werden initialisert der statische Initialisierer wird aufgerufen – die Zeichenfläche erscheint Schmiedecke – Programmieren 1 4 We wäre es mit 2-3 Zeichenflächen? Schmiedecke – Programmieren 1 5 Von Static nach Instance Was muss sich ändern? 1. Alle Methoden müssen Instanzmethoden werden 2. Die statische Initialisierung muss durch einen Konstruktor ersetzt werden 3. An der Aufrufstelle müssen die Novosketch-Instanzen erzeugt und dann die Instanzmethoden aufgerufen werden Schmiedecke – Programmieren 1 6 6 Konstruktion der Instanzen 1. Alle Methoden müssen Instanzmethoden werden static entfernen 2. Konstruktor statt statischer Initialisierung Index für die Position auf dem Bildschirm Schmiedecke – Programmieren 1 7 7 Objektorientierung: Von Static zu Instance Die objektorientierte Klasse NovoSketch sieht ganz ähnlich aus: Schmiedecke – Programmieren 1 8 8 Benutzung der Instanzen Zeichenfläche 2x instanziieren jeweils Titel und Startpunkt setzen Zeichen auf 1. Zeichenfläche Zeichnen auf 2. Zeichenfläche Schmiedecke – Programmieren 1 9 Zwei austauschbare Implementierungen 2 NovoSketch-Implementierungen für X3 Etch-a-Sketch die "einfache" novosketch.NovoSketch mit "Macken" bei langen Linien die robustere canvassketch.NovoSketch austauschbar ohne Änderung Ihres Codes einfach beim Import entscheiden, welches Paket gewählt wird Instanzen können auch simultan existieren: der Rest bleibt unverändert Grund: alle Methodensignaturen sind gleich Schmiedecke – Programmieren 1 10 10 Interfaces Die Methodensignatur beschreibt die äußere Form einer Methode Um eine Methode zu (syntaktisch korrekt) zu benutzen, braucht man nur die Signatur. Java erlaubt es, reine Signaturen zu definieren, ohne Implementierung. public void drawInRed(); eine Sammlung solcher Signaturen heißt Interface ein Interface ist eine besondere Klasse Interfaces kann man nicht instanziieren Schmiedecke – Programmieren 1 11 11 Das Interface SketchboardInterface Schmiedecke – Programmieren 1 12 12 ... Wir wechseln jetzt zu einem einfacheren Beispiel Schmiedecke – Programmieren 1 13 13 Beispiel String Interface Von der Klasse String kennen wir nur die Schnittstelle In Java kann man sie so definieren: interface StringInterface { String toUpperCase(); String toLowerCase(); String trim(); int length(); char charAt(int pos); int indexOf(char c); // etc.... } Schmiedecke – Programmieren 1 Das Interface StringInterface beschreibt die Dienste, die der Typ String anbietet. 14 String und StringInterface man kann sagen, die Klasse String implementiert das Interface StringInterface das ist kein Exklusivrecht: eine andere Klasse, z.B. Zeichenkette, kann dasselbe Interface implementieren. StringInterface "implementiert" String "implementiert" Sting und Zeichenkette können auf dieselbe Art benutzt werden, egal, wie verschieden sie "innerlich" sind. Zeichenkette Schmiedecke – Programmieren 1 15 Interfaces und Typen Eigentlich könnte man sagen, String und Zeichenkette haben denselben Typ – schließlich verhalten sie sich identisch. String string = "lalala"; Zeichenkette kette = "hahaha"; string = string.toUpperCase(); string = kette; string = string.toUpperCase(); Typfehler!!! Java weiß nichts über ihre Gemeinsamkeit... Man kann es mitteilen: class Zeichenkette implements StringInterface {...} class String implements StringInterface {...} String ist allerdings bereits implementiert – nur Denkmodell - Schmiedecke – Programmieren 1 16 Interfaces als Typen class Zeichenkette implements StringInterface {...} class MyString implements StringInterface {...} MyString und Zeichenkette haben denselben Typ, also kann man ihre Objekte jetzt derselben Variable zuweisen und identisch benutzen: StringInterface irgendwas; Zeichenkette kette; MyString mystring; irgendwas = kette; irgendwas.toUpperCase(); irgendwas = mystring; irgendwas.toUpperCase(); StringInterface implementiert implementiert MyString Schmiedecke – Programmieren 1 Zeichenkette 17 Vertrag und Zulassung implements ist wie ein Türschild: Dr.Frauke Wurzel "Steuerberater" oder "Kieferorthopäde" Kieferorthopädin Alle Kassen Auch wer die Person nicht kennt, weiß aufgrund des Schildes, welche Max Geldhahn Dienste er in Anspruch nehmen kann Steuerberater (und vertraut auf Kompetenz). Der Java-Compiler ist die Prüfbehörde: Eine Klasse wird nur dann kompiliert, wenn sie alle ihre implements-Behauptungen erfüllt (d.h. alle angegebenen Methoden implementiert). Damit ist "implements" vertrauenswürdig... Nico Roßberg vereidigter Kfz-Sachverständiger Schmiedecke – Programmieren 1 18 Beispiel Zähler Das sollte jeder Zähler anbieten: interface Zaehler { void zaehlen(); int wertLesen(); } // Name des Interface // Vertragsgegenstand: zählen // Vertragsgegenstand: Wert lesen Methodendeklaration Methodensignatur: (abstrakte Methodendeklaration) void zaehlen (); Rückgabetyp Name der Methode Parameterliste Semikolon (Implementierung) void zaehlen() { // hier folgt der // Algorithmus: // "Methodenrumpf" } Schmiedecke – Programmieren 1 19 Zähler-Interface und 2 Implementierungen interface Zaehler { void zaehlen(); int wertLesen(); } class Basiszaehler implements Zaehler { int wert = 0; void zaehlen() { wert ++; } int wertLesen() { return wert; } } class Countdownzaehler implements Zaehler { int wert = 0; void zaehlen() { wert --; } int wertLesen() { return wert; } void ssetzeStartwert (int startwert) { wert = startwert; } } Schmiedecke – Programmieren 1 zusätzliche Methode, nicht vom Interface gefordert 20 Zähler als Typ Zaehler schrittzaehler = new Basiszaehler(); Zaehler rueckzaehler = new Countdownzaehler(); int strecke = schrittzaehler.wertLesen(); int rueckweg = rueckzaehler.wertLesen(); rueckzaehler.setzeStartwert(5000); // Typfehler while while (laufend) (laufend) { schrittzaehler.zaehlen(); { schrittzaehler.zaehlen(); rueckzaehler.zaehlen(); rueckzaehler.zaehlen(); // negative werte! } } Schmiedecke – Programmieren 1 21 Zähler als Typ Zaehler schrittzaehler; Basiszaehler hinzaehler = new Basiszaehler(); Countdownzaehler rueckzaehler = new Countdownzaehler(); schrittzaehler = hinzaehler; while (laufend) schrittzaehler.zaehlen(); rueckzaehler.setzeStartwert(schrittzaehler.wertLesen()); schrittzaehler = rueckzaehler; while (laufend) schrittzaehler. zaehlen(); int schrittlaengenentwicklung = schrittzaehler.wertLesen(); // oder: schrittlaengenentwicklung = rueckzaehler.wertLesen() Schmiedecke – Programmieren 1 22 ...und noch einmal: Typanpassung Basiszaehler und Countdownzaehler haben nicht wirklich denselben Typ: Sie haben beide den Typ Zaehler, d.h. die Typbeschreibung von Zaehler passt auf beide. Aber die Spezifikation von Countdownzaehler umfasst eine Methode mehr als Zaehler! Schmiedecke – Programmieren 1 23 Typanpassung Countdownzaehler-Objekte können wie Zaehler benutzt werden: Zaehler zaehler = new Countdownzaehler(); zaehler.zaehlen(); Aber nicht jeder Zaehler kann, was Countdownzaehler können: zaehler = new Basiszaehler(); zaehler.startwertSetzen(500); // undefiniert! Bei der Zuweisung an eine Zaehler-Variable erfolgt eine implizite Typanpassung der Referenz (nicht des Objekts) Variable vom Typ Zaehler Referenz vom Typ Zaehler Objekt vom Typ Countdownzaehler Mit einer Referenz vom Typ Zaehler kann man nur Zaehler-Methoden rufen, egal welches Objekt sie referiert. Schmiedecke – Programmieren 1 24 Referenz-Typ als Aspekt Der Typ der Referenz entscheidet darüber, welcher (Teil-)Aspekt eines Objektes sichtbar ist. Der Objekttyp wird nicht verändert! Countdownzaehler down = new Countdownzaehler() Zaehler zaehler = down; down.startwertSetzen(100) // funktioniert zaehler.startwertSetzen(100) // geht nicht Variable vom Typ Zaehler Variable vom Typ Countdownzaehler Referenz vom Typ Countdownzaehler Referenz vom Typ Zaehler Objekt vom Typ Countdownzaehler Schmiedecke – Programmieren 1 25 Explizite Typanpassung Der Programmierer kann eine Zaehler-Referenz explizit an den Typ Countdownzaehler anpassen, um sie als Countdownzaehler-Referenz verwenden: Zaehler zaehler = new Countdownzaehler(); (Countdownzaehler)zaehler. startwertSetzen(); Die Anpassung geschieht "auf eigene Gefahr": Ist das referierte Objekt nicht vom Typ Countdouwnzaehler, bricht das Programm ab (Fehlermeldung: ClassCast Exception) Variable vom Typ Zaehler Referenz angepasst an Countdownzaehler Objekt vom Typ Zaehler ClassCastException! Schmiedecke – Programmieren 1 26 Objekttyp erfragen Zur Compilezeit ist (grundsätzlich) nicht entscheidbar, welchen genauen Typ ein Objekt hat, das eine Variable referiert. public class Typen { public Zaehler zaehler; public void ordneZaehlerZu(Zaehler z) { zaehler = z; } } Zur Laufzeit kann dies erfragt werden durch den Operator instanceof if (zaehler instanceof Countdownzaehler) zaehler.startwertSetzen(500); Schmiedecke – Programmieren 1 27 Zurück zu Etch-a-Sketch Schmiedecke – Programmieren 1 28 28 Das Interface SketchboardInterface Schmiedecke – Programmieren 1 29 29 Das Interface implementieren Beide Klassen implementieren das Interface SketchboardInterface Beide Klassen haben daher zusätzlich den Typ SketchboardInterface Instanzen beider Klassen können einer Variable vom Typ SketchboardInterface zugewiesen werden. Schmiedecke – Programmieren 1 30 SketchboardInterface als Variablentyp verwenden Beide Variablen haben jetzt den Typ SketchboardInterface Die Methoden des Interfaces sind damit aufrufbar. (Wie sie genau funktionieren, hängt vom Typ der Instanz ab, nicht vom Typ der Variable.) Schmiedecke – Programmieren 1 31 Verwendung Durch ein Interface wird festgelegt werden, worauf sich der Benutzer des Typs verlassen kann Gut für Teamwork: A implementiert das Interface B verwendet das Interface als Typ Gut für schnelle Prototypen Die erste Implementierung ist ein "Dummy" Dann folgt eine bessere Implementierung zum Testen Dann folgt die Produktivimplementierung Gut für Technologiewechsel Ersatztechnologie implementiert dasselbe Interface Wechsel ist unkompliziert Schmiedecke – Programmieren 1 32 32 Interfaces sind einfach... Nächstes Mal geht es um Vermeidung von Doppelarbeit Schmiedecke – Programmieren 1 33 33 Für Spezis: Die Zeichnung als Instanz main muss noch viel verwalten die Zeichenflächen-Instanzen die Titel der Zeichenflächen die Koordinaten der jeweiligen Figur das Malen der jeweiligen Figur Zeichnung als eigenständiges Objekt: erzeugt ihre Zeichenfläche setzt ihren eigenen Titel verwaltet ihre eigenen Koordinaten malt die Figur Schmiedecke – Programmieren 1 34 die Zeichnung als Instanz main muss nur noch Zeichnungen instanziieren für jede Zeichnung draw() rufen Schmiedecke – Programmieren 1 35 35