Kapitel 2: OO Grundlagen 2.1 Objekte zum Leben erwecken (und Grundmechanismen verstehen) 2.2 Statische Elemente nutzen & vererben 2.3 Kooperation über Interfaces Lothar Schmitz UniBwM (teils nach Prof. Hußmann TUD) Objektoiertierte Programmierung K2-1
Das laufende Beispiel: verschiedene Zettel Ein Zettel hat ähnlich einer Karteikarte eine Überschrift (kurz: Titel ) und einen Inhalt. Im einfachsten Fall sind Titel und Inhalt beides Zeichenreihen. Zettel kann man zählen und mit Seriennummern veredeln. Dann ähneln sie Banknoten oder Reisepässen. Auf Zettel kann man Eintragungen vornehmen, überschreiben, wieder rückgängig machen, erneut beschreiben... Die Programme dieses Kapitels demonstrieren anhand dieser Anwendungsbeispiele die wichtigsten OO Konzepte. Da praktisch weder Kontrollstrukturen noch Datenstrukturen vorkommen, zeigen die Beispiele ausschließlich OO Elemente und ihre Verwendungsmöglichkeiten. Lothar Schmitz UniBwM (teils nach Prof. Hußmann TUD) Objektoiertierte Programmierung K2-2
2.1 Objekte zum Leben erwecken Aus Gründen der Beschreibungsökonomie modelliert man nicht einzelne Objekte, sondern Objektarten, d.h. Klassen von Objekten. Zu modellieren sind dabei: der Zustand durch geeignete Exemplarvariablen ( Attribute ), die in der Regel privat, d.h. von aussen unsichtbar sind; mindestens eine Konstruktormethode zum Erschaffen und Initialisieren von Objekten der Klasse; öffentliche ( public ) getter - und setter -Methoden zum Zugriff auf die Attribute, soweit freizugeben; eine tostring() -Methode, mit der für Testzwecke der Inhalt des Objekts in lesbarer Form dargestellt werden kann; als Rest des Protokolls ggfs weitere, klassenspezifische Methoden. Lothar Schmitz UniBwM (teils nach Prof. Hußmann TUD) Objektoiertierte Programmierung K2-3
Die Zettel-Klasse in UML und Java Zettel-Objekte haben konkret einen Titel und einen Inhalt (hier Zeichenketten) einen Konstruktor, der einen Zettel mit gegebenem Titel und Inhalt herstellt getter und setter für den Inhalt (der Titel ist damit von außen nicht zu verändern) eine tostring() -Methode Zettel - titel : String - inhalt : String + Zettel(String,String) + getinhalt() : String + setinhalt(string) : void Zwei Exemplarvariablen Ein Konstruktor Zugriff auf Inhalt mit getter / setter tostring() -Methode zur Darstellung Lothar Schmitz UniBwM (teils nach Prof. Hußmann TUD) Objektoiertierte Programmierung K2-4
Programme ausführen: die main() -Methode Eine Klasse ausführen heißt immer: ihre main()-methode starten. Die main()-methode hat immer den gleichen Rahmen: public static void main(string[] args) { }... Zur Übernahme von Kommandozeilenparametern Die main()-methode kann in einer eigenen Testklasse stehen oder auch in der zu testenden (bzw. auszuführenden) Klasse. Die main()-methode erzeugt Testobjekte per Konstruktoraufruf: Zettel meiner = new Zettel("z","z-Inhalt") Lothar Schmitz UniBwM (teils nach Prof. Hußmann TUD) Objektoiertierte Programmierung K2-5
Java: Variablen, Objekte und Parameter Variablen enthalten entweder elementare Werte (int, char, boolean o.ä.) oder Objekt-Referenzen (vgl. Ada "access types"), aber niemals Objekte selbst!! Parameter werden stets "per value" übergeben: beim Aufruf werden die in den aktuellen Parametern vorliegenden Referenzen in die formalen Parameter (Variablen) kopiert; am Ende des Methodenaufrufs werden die formalen Parameter gelöscht (also nicht zurückgegeben!!); die Inhalte eines Parameterobjekts / Methodenempfängers können verändert werden, nicht aber seine Identität (der Referenz-Wert)! Die Pseudovariable this bezeichnet den Methodenempfänger. Lothar Schmitz UniBwM (teils nach Prof. Hußmann TUD) Objektoiertierte Programmierung K2-6
Java: Object, Casts und Clones "Object" heißt die Wurzelklasse der Vererbungshierarchie. => Jedes Objekt ist ein spezielles Object-Exemplar. Variablen vom Typ Object können beliebige Objekt-Referenzen aufnehmen. Bei einer Wertzuweisung werden nur die Referenzen kopiert. => Es entstehen keine echten Kopien, sondern nur mehrfache Referenzen auf das selbe Objekt! Um echte Kopien zu erstellen, redefiniert man die Methode public Object clone() aus Object geeignet und "castet" das Ergebnis passend: (Zettel)z.clone() Lothar Schmitz UniBwM (teils nach Prof. Hußmann TUD) Objektoiertierte Programmierung K2-7
2.2 Statische Elemente nutzen & vererben Es gibt zweierlei statische Elemente: analog zu den Exemplarvariablen, die spezifisch für Objekte sind, die Klassenvariablen von Klassen; Klassenmethoden wie main(), die sich auf die Klasse, d.h. den Prägestempel selbst beziehen. Normale Methoden haben Zugriff auf die Parameter der Methode; lokal (in der Methode) deklarierte Hilfsvariablen; die Klassenvariablen der Klasse des Empfänger-Objekts; die Exemplarvariablen des Empfänger-Objekts. Eine Klassenmethode hat als Empfänger die Klasse, kein Objekt. Zugriff auf Exemplarvariablen kann es daher nicht geben! Lothar Schmitz UniBwM (teils nach Prof. Hußmann TUD) Objektoiertierte Programmierung K2-8
Gezählte Zettel Als Zähler wird eine mit 0 initialisierte Klassenvariable verwendet: static int zaehler = 0 deren getter dementsprechend eine Klassenmethode ist: public static int getzaehler() Die Klasse Gezaehlt ist Unterklasse von Zettel. Gezaehlt hat zwei überladene Konstruktoren, wobei der mit einem Parameter sich per this(...) auf den anderen stützt. Der andere Konstruktor stützt sich seinerseits per super(...) auf den Konstruktor der Oberklasse Zettel. Die Methoden clone() und tostring() werden geeignet redefiniert. Lothar Schmitz UniBwM (teils nach Prof. Hußmann TUD) Objektoiertierte Programmierung K2-9
Nummerierte Zettel Der Zählerwert wird bei Initialisierung im Konstruktor aus der ererbten Klassenvariablen zaehler in eine Exemplarvariable nummer übernommen, die von da an unverändert bleibt, aber per getter erreichbar ist: public static int getnummer() Die Klasse Nummeriert ist Unterklasse von Gezaehlt. Nummeriert hat zwei überladene Konstruktoren, wobei der mit einem Parameter sich per this(...) auf den anderen stützt. Der andere Konstruktor stützt sich seinerseits per super(...) auf den Konstruktor der Oberklasse Gezaehlt. Die Methoden clone() und tostring() werden geeignet redefiniert. Lothar Schmitz UniBwM (teils nach Prof. Hußmann TUD) Objektoiertierte Programmierung K2-10
Nutzanwendung Parkausweis Die Klasse Parkausweis ist Unterklasse von Nummeriert. Parkausweis hat eine Exemplarvariable kennzeichen Parkausweis hat zwei überladene Konstruktoren, wobei der mit einem Parameter sich per this(...) auf den anderen stützt. Der andere Konstruktor stützt sich seinerseits per super(...) auf den Konstruktor der Oberklasse Nummeriert. Die Methoden clone() und tostring() werden geeignet redefiniert. Eine Feinheit: Damit tostring() in der gezeigten Weise auf die ererbte Exemplarvariable titel zugreifen kann, muß diese in Zettel als protected, d.h. als in Unterklassen zugreifbar deklariert werden. Lothar Schmitz UniBwM (teils nach Prof. Hußmann TUD) Objektoiertierte Programmierung K2-11
Entstandene Klassenhierachie Zettel # titel : String - inhalt : Object + getinhalt() : Object + setinhalt(object) : void Gezaehlt - zaehler : int + getzaehler(): int + clone() : Object Legende: + public - private # protected Nummeriert - nummer : int + getnummer(): int + clone() : Object Konstruktoren sind hier nicht explizit dargestellt! Parkausweis - kennzeichen: String + clone() : Object Lothar Schmitz UniBwM (teils nach Prof. Hußmann TUD) Objektoiertierte Programmierung K2-12
2.3 Kooperation über Interfaces Neue Aufgabe: Eintragungen wieder rückgängig machen; zunächst einen Schritt ( Undo/Redo ), später beliebig viele Schritte. Die Aufgabe wird auf mehrere Schultern verteilt. Dazu Trennung von Zettel und seiner Info. Alles, was den Inhalt betrifft, delegiert Zettel an Info: Ein Zettel, der aufgefordert wird, etwas an seinem Inhalt zu tun, leitet die Aufgabe an seinen Partner Info weiter. Wichtig ist nicht, wer der Partner ist, sondern was er kann. Das beschreibt das Interface InfoInterface. Zettelpartner implementieren dieses Interface. Lothar Schmitz UniBwM (teils nach Prof. Hußmann TUD) Objektoiertierte Programmierung K2-13
Delegation in UML Zettel - titel : String # info : InfoInterface + getinhalt() : Object + setinhalt(object) : void «interface» InfoInterface + getinhalt() : Object + setinhalt(object) : void enthält -Beziehung, hier als Komposition sonst meist Aggregation Delegation u.a. Zettel.getInhalt() => Zettel.info.getInhalt() Partner info leistet die Arbeit Lothar Schmitz UniBwM (teils nach Prof. Hußmann TUD) Objektoiertierte Programmierung K2-14
Info-Anpassungen (Implementierung) Vererbungs -Beziehung zwischen Interfaces «interface» InfoInterface + getinhalt() : Object + setinhalt(object) : void «interface» RueckInterface + undo() : void implementiert - Beziehung von Klasse zu Interface EinfacheInfo - inhalt : Object + getinhalt() : Object + setinhalt(object) : void SimpleRueckInfo - aktinhalt : Object - voriger : Object + getinhalt() : Object + setinhalt(object) : void + undo() : void MultiRueckInfo - aktinhalt : Object - voriger : MultiRueckInfo + getinhalt() : Object + setinhalt(object) : void + undo() : void Lothar Schmitz UniBwM (teils nach Prof. Hußmann TUD) Objektoiertierte Programmierung K2-15
Zettel-Anpassungen (Reimplementierung) Zettel - titel : String # info : InfoInterface + getinhalt() : Object + setinhalt(object) : void Vererbungs - Beziehung EinfacherZettel SimpleRueckZettel MultiRueckZettel + undo() : void + undo() : void Lothar Schmitz UniBwM (teils nach Prof. Hußmann TUD) Objektoiertierte Programmierung K2-16
Zusammenfassung: UML-Elemente <objektname> : <Klasse> <attribute> : <werte> Exemplar / Instanz von <zugriff> : + public - private # protected <Klasse> <attribute> <methoden> <Klasse> : konkret oder abstrakt <attribute> : <zugriff> <name> : <typ> <methoden> : <zugriff> <name> (<parameter>) : <typ> konkret oder abstrakt enthält Unterklasse von i.d.r. Klasse oder Interface <Klasse> <attribute> <methoden> implementiert «interface» <Name> <abstrakte Methoden> Lothar Schmitz UniBwM (teils nach Prof. Hußmann TUD) Objektoiertierte Programmierung K2-17
Mehrfachvererbung In Analysemodellen treten oft unabhängige Dimensionen der Spezialisierung auf (Mehrfachvererbung). Termin persönl. Termin Hausveranstaltung Reise Teamveranstaltung Teambesprechung Vortrag In Entwurfsmodellen sollten Mehrfachvererbung beseitigt werden. Techniken dazu sind: Ersatz von Vererbung durch Komposition Definition von Schnittstellen Lothar Schmitz UniBwM (teils nach Prof. Hußmann TUD) Objektoiertierte Programmierung K2-18
Ersatz von Vererbung durch Komposition Termin Teamveranstaltung 1 1 Team- Ort- Rolle Rolle persönl. Termin Hausveranstaltung Reise Teambesprechung nun wie realisiert? Lothar Schmitz UniBwM (teils nach Prof. Hußmann TUD) Objektoiertierte Programmierung K2-19
Ersatz von Vererbung durch Schnittstellen Guter Software-Entwurf sichert Homogenität. Gleichartige Funktionalität soll in gleicher Weise aufrufbar sein. Schnittstelle (interface) ist ein Sprachkonstrukt von UML und Java. Termin <<interface>> Hausveranstaltung einladen() absagen() implementiert Teambesprechung einladen() absagen() Vortrag einladen() absagen() Lollipop -Notation: Teambesprechung Hausveranstaltung Lothar Schmitz UniBwM (teils nach Prof. Hußmann TUD) Objektoiertierte Programmierung K2-20
Schnittstellen und abstrakte Klassen Abstrakte Klasse Schnittstelle ( Interface ) Enthält Attribute und Operationen Kann Default-Verhalten festlegen Default-Verhalten kann in Unterklassen überdefiniert werden Enthält nur Operationen (und ggf. Konstante) Kann kein Default-Verhalten festlegen => Redefinition unmöglich Java: Unterklasse kann nur von einer Klasse erben Java: Eine Klasse kann mehrere Schnittstellen implementieren Schnittstelle ist eine spezielle Sicht auf eine Klasse Lothar Schmitz UniBwM (teils nach Prof. Hußmann TUD) Objektoiertierte Programmierung K2-21