Thomas Macht OOP WS 09/10 Konzepte Objektorientierter Programmierung Ziel der Objektorientierten Programmierung: Verbesserung der Wartbarkeit Objekt: Kapselung (encapsulation) zusammengehöriger Variablen und Routinen (Funktionen, Prozeduren, Methoden) Zugriff von außen nur über Nachrichten Identität (identity): o eindeutig, unveränderlich o identische Objekte (identical objects) liegen am selben Speicherplatz ein Objekt mit zwei Namen Zustand (state): o Werte der Variablen, änderbar o gleiche Objekte (equal objects): selber Zustand und selbes Verhalten Verhalten (behavior): o beim Aufruf einer Routine o abhängig von Parametern, aufgerufener Methode, Zustand des Objekts Schnittstelle (interface): o Beschreibung des Objektverhaltens in einem Detaillierungsgrad, der für Zugriffe von außen notwendig ist o Objekt kann mehrere Schnittstellen haben (unterschiedliche Verwendungen) o enthalten oft nur Köpfe aufrufbarer Routinen, manchmal Konstanten o data hiding + Kapselung = Datenabstraktion o entspricht Typ des Objekts Klasse: jedes Objekt ist Instanz einer Klasse, die seine Struktur beschreibt Konstruktoren (constructors): Routinen zur Erzeugung und Initialisierung neuer Objekte Klasse: spezifischte Schnittstelle – Schnittstelle eines Objekts: beliebe Schnittstelle alle Instanzen haben dieselben Schnittstellen, aber unterschiedliche Identitäten, Instanzvariable und Zustände Seite 1 von 22 Thomas Macht OOP WS 09/10 Polymorphismus (Gegenteil: Monomorphismus): Variable/Routine (polymorpher Parameter: an Argumente von mehr als einem Typ gebunden) kann gleichzeitig mehrere Typen haben: o deklarierter Typ o statischer Typ: vom Compiler ermittelt, kann spezifischer als deklarierter Typ sein (Programmoptimierungen) o dynamischer Typ: spezifischter Typ, steht erst zur Laufzeit fest (dynamisches Binden/dynamic binding) universeller Polymorphismus: zueinander in Beziehung stehende Typen haben gleichförmige Struktur o Generizität (genericity): Ausdrücke können Parameter enthalten, für die Typen eingesetzt werden (zB List<String>) o enthaltender Polymorphismus (subtyping): Objekte der Untertypen sind auch Objekte des Obertypen Ersetzbarkeitsprinzip: Typ U ist Untertyp von Typ T wenn Instanz von U überall verwendbar, wo Instanz von T erwartet Ad-hoc-Polymorphismus (nicht spezifisch für objektorientierte Programmierung): o Überladen (overloading): deklarierte Typen der Argumente entscheiden, welche Routine ausgeführt wird Typen müssen in keiner Relation zueinander stehen oft syntaktische Vereinfachung o Typumwandlung (type coercion): semantische Operation Vererbung (inheritance): abgeleitete/Unterklasse (derived/subclass) – Basisklasse/Oberklasse (base class/superclass) Codewiederverwendung Änderungen der Unterklassen in populären Programmiersprachen: o Erweiterung um neue Methoden, Variable, Konstruktoren o Überschreiben von Methoden der Oberklasse in Java und C++ enger Zusammenhang zu enthaltendem Polymorphismus (Grund für eingeschränkte Änderungsmöglichkeiten) Einfachvererbung (single inheritance) – Mehrfachvererbung (in Java nur mit Interfaces) Seite 2 von 22 Thomas Macht OOP WS 09/10 Qualität in der Programmierung Qualität von Programmen: o Brauchbarkeit/Usability Zweckerfüllung (Features) Bedienbarkeit (Einlernaufwand) Effizienz des Programms o Zuverlässigkeit o Wartbarkeit (bis zu 70 % der Gesamtkosten): Einfachheit Lesbarkeit Lokalität Faktorisierung: Ersetzen von ähnlichen Befehlssequenzen durch Routinen, Objekte Effizienz der Programmerstellung/-wartung o Softwareentwicklungsprozess: Analyse (analysis) Entwurf (design) Implementierung (implementation) Verifikation (Anforderungen, verification) und Validierung (Funktion, validation) o Wasserfallmodell – zyklische Softwareentwicklungsprozesse (Anforderungsänderungen besser, Zeit und Kosten schwerer planbar) Rezept für gute Programme Verantwortlichkeiten (responsibilities) einer Klasse: Was weiß ich? (Zustand der Instanzen) Was mache ich? (Verhalten der Instanzen) Wen kenne ich? (sichtbare Objekte/Klassen) Entwickler der Klasse zuständig Klassen-Zusammenhalt (class coherence): hoch, wenn alle Variablen und Methoden der Klasse eng zusammenarbeiten und durch den Klassennamen gut beschrieben sind es fehlt etwas Wichtiges, wenn man beliebige Variablen/Methoden entfernt Zusammenhalt sinkt bei sinnändernder Umbenennung sollte hoch sein (gute Zerlegung des Programms in Klassen/Objekte, gute Faktorisierung) Objekt-Koppelung (object coupling): Abhängigkeit der Objekte voneinander stark, wenn: o große Anzahl nach außen sichtbarer Methoden und Variablen o im laufenden System häufige Nachrichten zwischen unterschiedlichen Objekten, große Parameteranzahl bei diesen Methoden sollte schwach sein (gute Kapselung, Objekte sind so unabhängig wie möglich) Refaktorisierung: rechtzeitig, vernünftiges Maß gutes Programm Seite 3 von 22 Thomas Macht OOP WS 09/10 Wiederverwendung (reuse): Programme Daten Erfahrungen Code: o globale Bibliotheken o fachspezifische Bibliotheken o projektinterne Wiederverwendung o programminterne Wiederverwendung Programm wird kleiner, einfacher, leichter wartbar Abwägen zwischen investierter Zeit – Nutzen Entwurfsmuster (design patterns): Wiederverwendung von (kollektiver) Erfahrung Name Problemstellung Lösung Konsequenzen (Vor- und Nachteile) Paradigmen der Programmierung Stil Objektorientierte Programmierung für Systeme, deren Gesamtkomplexität jene der einzelnen Algorithmen deutlich übersteigt Imperative Programmierung: Programme sind aus Anweisungen aufgebaut (in fester Reihenfolge ausgeführt) grundlegende Sprachelemente: Variablen, Konstanten, Routinen wichtigster Befehl: destruktive Zuweisung (neuer Wert unabhängig vom alten) Programmzustand: o Menge aller Werte, Zeiger auf nächsten auszuführenden Befehl o ändert sich mit Ausführung einer Anweisung Prozedurale Programmierung: o konventioneller Programmierstil, zB C o Programme in sich gegenseitig aufrufende Prozeduren zerlegt o strukturierte Programmierung Objektorientierte Programmierung: o Weiterentwicklung der strukturierten Programmierung o zusammengehörige Routinen und Daten zu Objekten zusammengefasst Seite 4 von 22 Thomas Macht OOP WS 09/10 Deklarative Programmierung: Beziehungen zwischen Ausdrücken in einem System keine zustandsändernden Anweisungen mathematische Modelle, höhere Abstraktionsniveau als imperative Sprachen grundlegende Sprachelemente: Symbole (in Gruppen wie Variablen-, Funktionssymbole und Prädikate einteilbar) Funktionale Programmierung: o Lambda-Kalkül: definiert mathematischen Formelbegriff formal o alle Ausdrücke als Funktionen aufgefasst o wesentlicher Berechnungsschritt: Anwendung einer Funktion auf einen Ausdruck o referentielle Transparenz: Ausdruck in einem Programm bedeutet immer dasselbe, egal wann und wo ausgewertet Logikorientierte Programmierung: o beruht auf einer Teilmenge der Prädikatenlogik erster Stufe o zB Prolog Paradigmen für Modularisierungseinheiten: abstrakte Datentypen: o verstecken interne Darstellung ihrer Instanzen, auf Objekten nur vom ADT exportierte Operationen anwendbar o structs (im Großen und Ganzen Klassen ohne enthaltendem Polymorphismus und Vererbung) Module: o Gruppierungen von Variablen, Routinen, Typen, Klassen o entsprechen Objekten, die direkt (ohne Klassen, nicht zur Laufzeit) erzeugt werden o zyklenfrei (A kann nicht B, und B A verwenden, für Kompilierungsreihenfolge) Komponentenprogrammierung: o selbe Komponente soll in unterschiedlichen Programmen einsetzbar und austauschbar sein o nur Schnittstellen anstatt namentlicher Verweise o Zusammensetzung erst zur Laufzeit o zB .Net Komponetenmodell o Zuordnung zu Klasse nicht nötig, aber idR vorgesehen Generische Programmierung: o Entwicklung generischer Abstraktionen als modulare Programmeinheiten o generische Einheiten zur Laufzeit zu konkreten Datenstrukturen/Klassen/Typen/Funktionen/Prozeduren instanziert, die benötigt werden o zB List <A> Seite 5 von 22 Thomas Macht OOP WS 09/10 Enthaltender Polymorphismus und Vererbung meist Vererbung so eingeschränkt, dass sie wichtigste Anforderungen des enthaltenden Polymorphismus erfüllen kann in Java ist Vererbung Voraussetzung für Untertypbeziehungen Ersetzbarkeitsprinzip wichtigste Grundlage des enthaltenden Polymorphismus Typ U ist Untertyp von Typ T, wenn Instanz von U überall verwendbar, wo Instanz von T erwartet Aufruf einer Routine mit einem Argument, dessen Typ ein Untertyp des Typs des entsprechenden formalen Parameters ist Zuweisung eines Objektes an eine Variable, wobei der Typ des Objekts ein Untertyp des deklarierten Typs der Variablen ist Untertypbeziehungen sind … reflexiv transitiv antisymmetrisch U ist ein Untertyp von T wenn … für jede Konstante in T gibt es eine entsprechende in U, deklarierter Typ U der Konstante in U ist ein Untertyp des deklarierten Typs der Konstante in T kovariant für jede Variable in T gibt es eine entsprechende in U, deklarierte Typen sind gleich invariant für jede Methode in T gibt es eine entsprechende in U, deklarierter Ergebnistyp in U ist Untertyp des Ergebnistyps in T, gleiche Anzahl formaler Parameter, deklarierter Typ jedes formalen Parameters in U ist Obertyp des entsprechenden Parameters in T (gilt nur für Eingangsparameter, Ausgangsparameter sind kovariant, Durchgangsparameter invariant) Kovarianz: deklarierter Typ eines Elements in U ist Untertyp des deklarierten Typs in T Konstante (nicht in Java), Ergebnisse von Methoden (ab Java 1.5), Ausgangsparameter Typen und darin betrachtete Elementtypen variieren in dieselbe Richtung Kontravarianz: deklarierter Typ eines Elements in U ist Obertyp des deklarierten Typs in T deklarierte Typen von formalen Eingangsparametern Typen und darin betrachtete Elementtypen variieren in entgegengesetzte Richtungen Invarianz: deklarierter Typ eines Elements in U ist gleich dem deklarierten Typ in T Variable, Durchgangsparameter Seite 6 von 22 Thomas Macht OOP WS 09/10 Binäre Methode: formaler Parametertyp gleich der Klasse, in der die Methode definiert ist widerspricht Ersetzbarkeitsprinzip (in Java überladen, nicht überschrieben) Realisierung in Java: alle Typen invariant (außer Ergebnistypen ab Version 1.5) Konstanten als spezielle Variable angesehen überladene Methoden kaum von Methoden mit kontravariant veränderten Typen auseinanderzuhalten Untertypen und Codewiederverwendung: Ersetzbarkeit Codewiederverwendung zwischen Versionen und intern im Programm, Programmänderungen werden lokal gehalten Schnittstellen können im Wesentlichen nur erweitert werden Schnittstellen, besonders an der Wurzel, sollten stabil bleiben (gute Faktorisierung hilft) Parametertypen sollten allgemein gewählt werden Dynamisches Binden: bei Verwendung von enthaltendem Polymorphismus kann der dynamische Typ einer Variablen/eines Parameters ein Untertyp des statischen/deklarierten Typs sein Java: unabhängig vom statischen Typ immer in der Klasse des Objekts definierte Methode ausgeführt (spezifischter dynamischer Typ der Variablen) verwandt mit switch-Anweisungen, aber bessere Lesbarkeit und Änderungen können lokal gehalten werden Seite 7 von 22 Thomas Macht OOP WS 09/10 Ersetzbarkeit und Objektverhalten weitere, nicht vom Compiler überprüfbare Bedingungen für Ersetzbarkeit Client-Server-Beziehungen: Objekt stellt als Server anderen Dienste zur Verfügung Objekt nimmt als Client Dienste anderer Objekte in Anspruch Objekt gegen anderes austauschbar, wenn es zumindest dieselben Dienste anbietet Objektverhalten: Wie verhält sich das Objekt beim Empfang einer Nachricht? Zusicherungen (assertions): Vorbedingungen (preconditions): o Client vor Erfüllung vor Ausführung verantwortlich o hauptsächlich Eigenschaften der Argumente o können Zustand des Servers einbeziehen, sofern der Client ihn kennt Nachbedingungen (postconditions): o Server für Erfüllung nach Ausführung verantwortlich o Methodenergebnisse und Änderungen/Eigenschaften des Objektzustands Invarianten (invariants): o Server für Erfüllung vor und nach Ausführung verantwortlich o impliziert eine Nachbedingung auf jeder Methode des Servers sollten stabil bleiben (keine unnötigen Details festlegen) so einsetzen, dass Klassenzusammenhalt maximiert und Objektkoppelung minimiert wird alle benötigten Zusicherungen sollen explizit oder implizit im Programm stehen gehören zum Typ des Objekts Typ besteht aus: Name einer Klasse, eines Interfaces oder eines einfachen Typs entsprechender Schnittstelle dazugehörigen Zusicherungen Untertypen und Verhalten: damit U Untertyp von T ist: jede Vorbedingung auf einer Methode in T impliziert eine in U (Vorbedingungen in Untertypen können schwächer, aber nicht stärker sein) jede Nachbedingung auf einer Methode in U impliziert eine in T (Nachbedingungen in Untertypen können stärker, aber nicht schwächer sein) jede Invariante in U impliziert eine in T (Invariante in Untertypen können stärker, aber nicht schwächer sein) Seite 8 von 22 Thomas Macht OOP WS 09/10 Abstrakte Klassen: nur zur Festlegung des Typs, es können keine Instanzen erzeugt werden dürfen sowohl abstrakte Klassen (müssen in Unterklassen implementiert werden) als auch konkrete (werden vererbt) enthalten als Obertypen und Parametertypen sollten abstrakte Klassen ohne Implementierungen und Interfaces verwendet werden (leichter stabil zu halten) Vererbung versus Ersetzbarkeit Untertypbeziehung: o beruht auf Ersetzbarkeitsprinzip o bei Nichtbeachtung erschwerte Wartung (Programmänderungen bleiben nicht lokal) Vererbungsbeziehung: o Klasse entsteht durch Abänderung einer anderen o Ziel: Codewiederverwendung o sollten sich Untertypbeziehungen unterordnen keine Vererbungsbeziehung, die nicht Untertypbeziehung ist Reale-Welt-Beziehung: angenommene „is a“-Beziehungen in Analyse und Entwurf (zB Student ist Person), entwickeln sich vor allem zu Untertyp-, gelegentlich zu Vererbungsbeziehungen weiter Untertypbeziehungen in Java: setzen Vererbungsbeziehungen voraus derart eingeschränkt, dass vom Compiler überprüfbare Bedingungen immer erfüllt wesentliches Unterscheidungskriterium: Zusicherungen kompatibel? Seite 9 von 22 Thomas Macht OOP WS 09/10 Klassen und Vererbung in Java aktuelle Instanz: this Basisklasse: super Konstruktor der Basisklasse: super() Destruktor: finalize() Klassenvariable und -methoden: static static initializer (Initialisierung von Klassenvariablen): static {} Konstanten: final Geschachelte Klassen (nested classes): o Statische geschachtelte Klassen: können nur auf Klassenvariablen und statische Methoden der umschließenden Klasse zugreifen o Innere Klassen: gehören zu einer Instanz der umschließenden Klasse, dürfen keine statischen Methoden oder Klassenvariablen enthalten o hohe Objektkoppelung Klassen sind Objekte (Instanzen der vordefinierten Klasse Class): o statische Methoden und Klassenvariable nur verwenden, wenn als Variable/Methode einer Instanz von Class betrachtet o NICHT Klassenvariable als Variable sehen, die allen Instanzen einer Klasse gemeinsam gehört, Zugriff wie auf ein anderes Objekt (mit Methoden, nicht direkt) 2 Variablen mit selben Namen können in Unter- und Oberklasse existieren (nicht überschrieben wie Methoden) verdeckt, ansprechen mit super final-Methoden: o dürfen in Unterklasse nicht überschrieben werden statisches Binden o nur in Spezialfällen final-Klassen: haben keine Unterklassen Paketkonzept: mehrere Klassen in einer Quellcodedatei (.java) möglich, aber nur eine public (Name = Dateiname) jede kompilierte Klasse in einer eigenen Datei (.class) Paket = Verzeichnis import: o von einzelnen Klassen/allen Klassen eines Paketes o nur am Dateianfang package paketPfadName: o Aufruf von javac oder java muss vorgegebenen Pfad enthalten o Datei wird nicht aus dem Kontext gerissen/in anderem Paket verwendet Sichtbarkeiten: public: sichtbar und ererbbar im selben und in anderen Paketen, nicht für Variable (Zusicherungen) protected: nicht in anderen Paketen sichtbar, aber ererbbar Default (package): in anderen Paketen weder sichtbar noch ererbbar private Variable sollen nicht public sein (geeignete Zusicherungen) getter und setter (deuten auf starke Objektkoppelung und niedrigen Klassenzusammenhalt hin) Seite 10 von 22 Thomas Macht OOP WS 09/10 Interfaces: im Wesentlichen eingeschränkte abstrakte Klassen (alle Methoden abstrakt, abstract kann weggelassen werden) Mehrfachvererbung von Interfaces wird in Java unterstützt (nach extends mehrere durch Komma getrennte Namen von Interfaces) keine Variablen, aber Konstanten (static final) alle Methoden und Konstanten sind public (kann weggelassen werden) stabiler als Klassen mit Implementierung, sind abstrakten Klassen vorzuziehen Seite 11 von 22 Thomas Macht OOP WS 09/10 Generizität und Ad-hoc-Polymorphismus Generische Klassen, Typen und Routinen enthalten Typparamater, für die Typen eingesetzt werden. statischer Mechanismus: kleiner Zusatzaufwand für Compiler, aber keiner zur Laufzeit Generizität Einfache Generizität in Java: Generische Klassen/Interfaces haben ein/mehrere Typparameter: <A,B> Autoboxing/-unboxing: Umwandlung primitive Datentypen Referenztypen generische Methoden bezüglich Parameter oder Rückgabewert (für Typparameter zu verwendende Typen müssen nicht explizit angegeben werden, Berechnung = Typinferenz) Gebundene Generizität in Java: einfache Generizität: nichts über Typ, den der Typparameter ersetzt, bekannt (Methoden, Variable) Angeben einer Schranken Instanzen des Typparameters können wie Instanzen der Schranke verwendet werden zB class Hashtable<Key extends Hashable, Value> (Hashable als Schranke auf Key definiert) eine Klasse und/oder mehrere Interfaces <Key extends Hashable & Interface1 & Interface2> ungebundener Typparameter: keine Schranke angegeben Object als Schranke angenommen F-gebundene Generizität: o mit rekursiven Typparametern o zB interface Comparable<A> – class Integer implements Comparable<Integer> o keine sicheren impliziten Untertypbeziehungen (zB List<String> – List<Object>, auch nicht wenn String Untertyp von Object ist!) o Arrays unterstützen implizite Untertypbeziehungen bei Verwendung von Generizität vom Compiler abgefangen gebundene Wildcards: o als Typen ersetzen Typparameter (zB void drawAll (List<? extends Polygon> p) { ... }) o nur Lesezugriffe auf Parameter p (Kovarianz) o bei Verwendung ohne Schranken nur Lesezugriffe <? extends Object> super: o jeder Obertyp erlaubt (zB List <? super Square) o Schreibzugriffe (Kontravarianz) new A(): illegal, wenn A Typparameter new A[n]: in einigen Fällen nicht statisch Typsicher Seite 12 von 22 Thomas Macht OOP WS 09/10 Verwendung von Generizität gleich strukturierte Klassen und Routinen (Containerklassen wie Listen, Stacks, Hashtabellen, Mengen; Routinen die auf Containerklassen zugreifen wie sortieren, suchen) viele Klassen und Routinen in Bibliotheken Typparameter als Typen formaler Parameter, wenn Änderungen der Parametertypen absehbar (zB neue Währung: Dollar Euro) Untertypbeziehungen Vorzug gegenüber Generizität geben Codeänderungen mit klaren Grenzen oft gegeneinander austauschbar, aber homogene Listen nur mit Generizität, ohne Untertypbeziehungen (gebundene Generizität) keine heterogenen Listen mit Elementen verschiedener Typen Arten der Generizität: Übersetzung generische Klassen/Routinen in ausführbaren Code: homogene Übersetzung: o Java o jede generische Klasse in genau eine Klasse mit JVM-Code übersetzt o jeder gebundene Typparameter durch erste Schranke des Typparameters (ungebundener Object) ersetzt o gibt eine Methode eine Instanz eines Typparameters zurück dynamisch in Typ, der den Typparameter ersetzt, umgewandelt o Speichereffizienz heterogene Übersetzung: o für jede Verwendung mit anderen Typparametern eigener übersetzter Code erzeugt o „copy and paste“ o Laufzeiteffizienz (keine Typumwandlungen Überprüfungen) o bei gebundener Generizität müssen keine Schranken (kein gemeinsamer Obertyp erforderlich) angegeben werden Überprüfung für jede übersetzte Klasse, ob Typen vorausgesetzte Eigenschaften erfüllen (templates in C++; Java: dafür mehrere Interfaces) Seite 13 von 22 Thomas Macht OOP WS 09/10 Typfragen und Typumwandlungen prozedurale und funktionale Programmiersprachen: strenge Unterscheidung Typinformationen (stehen nur Compiler bei der Übersetzung zur Verfügung) – dynamische Programminformationen, keine dynamischen Typinformationen objektorientierte Programmiersprachen: dynamische Typinformationen für dynamisches Binden benötigt, oft direkter Zugriff darauf (Überprüfung, Umwandlung) Verwendung dynamischer Typinformation: getClass() instanceof (Ist dynamischer Typ eines Referenzobjekts Untertyp eines gegebenen Typs?; wenn null false) explizite Typumwandlung: ((Zieltyp)Variable) Fehler werden verdeckt, schlecht wartbar (switch-Anweisungen) Ersatz durch dynamisches Binden wenn möglich, außer: o Klassen können nicht erweitert werden o Methode muss in vielen Klassen implementiert werden wenn nicht in gemeinsamer Oberklasse möglich Typumwandlungen auf primitiven Typen: o dynamischer Typ immer gleich deklariertem Typ o tatsächlich Umwandlung der Instanzen, nicht deklarierter Typen o Informationen können verloren gehen Typumwandlungen und Generizität: homogene Übersetzung einer generischen Klasse/Routine: o alle Ausdrücke in spitzen Klammern weggelassen, jedes andere Vorkommen eines Typparameters durch Object/Schranke ersetzt o Ergebnis generischer Routinen muss in Instanz des Typs, der den Typparameter ersetzt, umgewandelt werden Nachteil: statt Compilerfehlermeldungen Ausnahmebehandlungen erst zur Laufzeit (höhere Typsicherheit von Generizität) nur sichere Typumwandlungen einsetzen: o in Obertyp des deklarierten Typs (up-cast, Gegenteil: down-cast) o vorherige dynamische Typabfrage (down-casts) o schreiben als ob man Generizität verwenden würde, händische Überprüfung auf mögliche Typfehler, dann homogene Übersetzung keine unnötigen dynamischen Typabfragen (down-casts) Generizität ist Typumwandlungen vorzuziehen Raw Types: generische Typen ohne Typparameter keine Typüberprüfung der Generizität Seite 14 von 22 Thomas Macht OOP WS 09/10 Kovariante Probleme: Kovarianz: o Typ eines Elements im Untertyp ist Untertyp des Typs des Elements im Obertyp o Typen und darin betrachtete Elementtypen variieren in dieselbe Richtung o Konstanten, Ergebnisse von Methoden, Ausgangsparameter o kovariante Eingangsparameter verletzen Ersetzbarkeitsprinzip! dynamische Typabfragen und -umwandlungen (allgemeinere Sichtweise) o Bsp: Tier – Rind – Tiger, Futter – Fleisch – Gras (Lösung: auch Rind kann Fleisch angeboten werden) häufig binäre Methoden (Parametertyp = Klasse, die Methode enthält) Überladen vs. Multimethoden dynamisches Binden in Java: nur deklarierter Typ eines Parameters für Auswahl einer überladenen Methode relevant, nicht dynamischer allgemein: dynamisches Binden kann dynamischen Typ des Parameters in Methodenauswahl mit einbeziehen Multimethoden dynamisches Binden nur so verwenden, daß es keine Rolle spielt, ob bei der Methodenauswahl deklarierte oder dynamische Typen der Argumente verwendet werden! Typumwandlungen ändern deklarierten Typ! für je zwei überladene Methoden gleicher Parameteranzahl: o zumindest eine Parameterposition, an der sich die Parametertypen unterscheiden, nicht in Untertyprelation zueinander stehen und keinen gemeinsamen Untertyp haben o oder alle Parametertypen der einen Methode sollen Obertypen der Parametertypen der anderen Methode sein, bei Aufruf der einen Methode nur auf andere Methode verzweigt, wenn dynamische Typen der Argumente das erlauben Multimethoden höhere Komplexität der Methodenauswahl Simulation von Multimethoden durch wiederholtes einfaches (anstelle mehrfaches) dynamisches Binden: auszuführende Methode durch Typen mehrerer Argumente bestimmt Visitor Pattern: o Visitorklassen und Elementklassen (oft gegeneinander austauschbar) o zB Futter – Tier o Nachteil: große Anzahl benötigter Methoden Seite 15 von 22 Thomas Macht OOP WS 09/10 Ausnahmebehandlung Ausnahmen in Java: Objekte von Throwable (in der Praxis nur Instanzen von Error: schwerwiegend und Exception: vom Programmierer selbst definiert/Instanz von vordefinierter Klasse RuntimeException) werfen mit throw, abfangen mit try-catch (wenn mehrere passende, erste gewählt) Methoden dürfen nur Instanzen von Error, RuntimeException und von Typen die (mittels throws) ausdrücklich angegeben sind zurückgeben. Ausführung einer Methode von U darf nur bei Ausführung der Methode in T erwartete Ausnahmen zurückliefern (Ausnahmen dürfen aber in Untertypen weggelassen werden) finally: in jedem Fall ausgeführt (bei Ausnahme im catch-Block vor Weitergabe der Ausnahme), Freigabe von Ressourcen Einsatz: o Unvorhergesehene Programmabbrüche (Ausgabe von Informationen) o Kontrolliertes Wiederaufsetzen o Ausstieg aus Sprachkonstrukten o Rückgabe alternativer Ergebniswerte o sparsam, nur in echten Ausnahmesituationen und wenn die Programmlogik vereinfacht wird Nebenläufige Programmierung mehrere Threads gleichzeitig nebeneinander (tatsächlich auf mehreren Prozessorkernen oder scheinbar auf einem) Synchronisation um inkonsistente Werte zu vermeiden synchronized: Schlüsselwort bei Methode, in jedem Objekt zu jedem Zeitpunkt höchstens eine synchronized Methode ausgeführt, atomare Ausführung synchronized-Blöcke: synchronized (this) { … }, Argument bestimmt Objekt auf dem ein Lock gesetzt wird, bei Methoden immer this wait() in Object vordefiniert, blockiert Thread bis explizit aufgeweckt oder mit Argument für bestimmte Zeit notifyAll() notify(): nur ein zufällig gewählter Thread aufgeweckt Runnable: Interface, spezifiziert nur run() Erzeugen eines neuen Threads mit new Thread(p), p ist Instanz von Runnable, bewirkt Ausführung von run() in p Collections.synchronizedList(new LinkedList()) Deadlock: zyklische Abhängigkeiten zwischen zwei oder mehreren Threads in Java verwendet: Monitor-Konzept Seite 16 von 22 Thomas Macht OOP WS 09/10 Softwareentwurfsmuster Erzeugende Entwurfsmuster (creational patterns) Factory Method (Virtual Constructor): Definition einer Schnittstelle für die Objekterzeugung (abstrakt oder DefaultImplementierung) tatsächliche Erzeugung in Unterklassen, diese entscheiden von welcher Klasse erzeugte Objekte sein sollen zB BakingMachine – RoundMachine/StarMachine/SquareMachine Anwendung: o Klasse soll neue Objekte erzeugen, kennt deren Klasse aber nicht o Unterklassen sollen Objekte bestimmen, die Klasse erzeugt o Klassen delegieren Verantwortlichkeiten an Unterklassen und Wissen, an welche, soll lokal gehalten werden flexibler (Entwicklung von Unterklassen) Verknüpfung paralleler Klassenhierarchien (zB Maschinen – Kekse) viele Klassen Generizität (nicht in Java: new A()) Seite 17 von 22 Thomas Macht OOP WS 09/10 Prototype: Art eines neu zu erzeugenden Objekts durch Prototyp-Objekt spezifiziert, neue Objekte durch kopieren Anwendung: o wenn System unabhängig davon sein soll, wie seine Produkte erzeugt, zusammengesetzt und dargestellt werden o Klassen, von denen Instanzen erzeugt werden sollen erst zur Laufzeit bekannt o Vermeidung einer Hierarchie von Creator-Klassen, die paralleler Hierarchie von Product-Klassen entspricht (Factory Method) o wenn jede Instanz einer Klasse nur wenige unterschiedliche Zustände haben kann oft einfacher für jeden möglichen einen Prototyp zu erzeugen als bei jedem new passende Zustände anzugeben verstecken konkrete Produktklassen vor Anwendern in Java clone() bereits in Object definiert (flache Kopie, für tiefe überschreiben), Klasse muss Interface Cloneable implementieren sonst Ausnahmebehandlung Singleton: eine Klasse hat nur eine Instanz (globale Variable würde nicht Erzeugung weiterer verhindern), globaler Zugriff darauf zB ein globaler Drucker-Spooler Klasse soll durch Vererbung erweiterbar sein, erweiterte Klasse ohne Änderungen verwendbar flexibler als statische Methoden statische Methode instance gibt einzige Instanz zurück (oder erzeugt sie, wenn nicht vorhanden) auch mehrere Instanzen möglich Konstruktor ist protected Seite 18 von 22 Thomas Macht OOP WS 09/10 Strukturelle Entwurfsmuster (structural patterns) Decorator (Wrapper): gibt einzelnen Objekten (anstelle ganzer Klassen) dynamisch zusätzliche Verantwortlichkeiten (können wieder entzogen werden) flexible Alternative zur Vererbung weniger Unterklassen (dafür viele kleine Objekte), nicht unterstützt (final) zB ein Fenster erhält eine Scrollbar, andere Fenster nicht Nachteil: Instanzen von ConcreteComponent und Decorator sind nicht identisch für Erweiterungen der Oberfläche/des Erscheinungsbilds, nicht für inhaltliche Erweiterungen und von Grund auf umfangreiche Objekte Window w = new WindowImpl(); // no scroll bar w = new ScrollBar(w); // add scroll bar w = ((ScrollBar)w).noScrollBar(); // remove scroll bar Seite 19 von 22 Thomas Macht OOP WS 09/10 Proxy (Surrogate): Platzhalter für anderes Objekt, kontrolliert Zugriffe darauf teures Objekt erst erzeugt, wenn nötig (zB umfangreiche Daten aus dem Internet geladen) Zeiger auf teures Objekt. leitet Aufrufe (nach evtl. weiteren Aktionen, zB erzeugen) weiter Schnittstelle von Proxy entspricht Subject kann als Ersatz für eigentliches Objekt verwendet werden intelligentere Referenz als simpler Zeiger Arten: o Remote Proxies: Platzhalter für Objekte in anderen Namensräumen (zB andere Rechner), Weiterleitung über komplexere Kommunikationskanäle o Virtual Proxies: erzeugen aufwendige Objekte bei Bedarf o Protection Proxies: kontrollieren Zugriffe auf Objekte o Smart References: ersetzen einfache Zeiger, Mitzählen der Referenzen (kann entfernt werden, wenn keine mehr vorhanden), Zusicherung des exklusiven Zugriffs Seite 20 von 22 Thomas Macht OOP WS 09/10 Entwurfsmuster für Verhalten (behavioral patterns) Iterator (Cursor): ermöglicht sequentiellen Zugriff auf Elemente eines Aggregats (Sammlung von Elementen, zB Collection) ohne dessen innere Darstellung offen zu legen einheitliche Schnittstelle für Abarbeitung verschiedene Aggregatstrukturen unterstützen unterschiedliche Varianten in der Abarbeitung von Aggregaten (zB Bäume) gleichzeitig mehrere Abarbeitungen auf selbem Aggregat interner – externer Iterator: Iterator führt übergebene Routine auf allen Elementen aus (zB max()) – Anwender fragt nächstes Element an (flexibler, hauptsächlich) Java 1.5: for (String s: l) ist abgekürzte Schreibeweise für for (Iterator<String> i = l.iterator(); i.hasNext();) Algorithmus zum Durchwandern des Aggregats kann im Iterator (flexibler) oder im Aggregat selbst (private Implementierungsdetails) implementiert sein in Java Iteratoren durch geschachtelte Klassen in Aggregaten starke Abhängigkeit Aggregat – Iterator Robuster Iterator: funktioniert trotz Löschen/Hinzufügen von Elementen (ohne ganzes Aggregat zu kopieren) Seite 21 von 22 Thomas Macht OOP WS 09/10 Template Method: definiert unveränderliches Grundgerüst eines Algorithmus in einer Operation, überlässt Implementierung einiger veränderlicher Schritte aber Unterklassen (primitive Methoden idR protected) Codewiederverwendung hooks (Operationen mit Default-Verhalten, dürfen überschrieben werden) – abstrakte Operationen Template Method selbst soll nicht überschrieben werden final Hollywood-Prinzip: „Don’t call us, we call you“: Oberklasse ruft Methoden der Unterklasse auf wenige primitive Operationen Seite 22 von 22