Prinzipien der Objektorientierung

Werbung
Prinzipien der Objektorientierung
Problem bei der Softwareentwicklung: Die Welt ist sehr komplex
Lösungsansatz:
- Problem auf das Wesentliche reduzieren
- Modularisierung
- strukturierte Einordnung (Hierarchie)
- Kapselung zusammengehöriger Informationen
Die Objektorientierung (OO) versucht eine Methode anzubieten, die dem menschlichen Denken
nachempfunden ist.
Daraus ergeben sich folgende Prinzipien der OO:
- Abstraktion
- Kapselung
- Vererbung
- Polymorphismus (als Funktionsweise innerhalb der Vererbung)
Abstraktion
Der Mensch bedient sich des Prinzips Abstraktion, um mit Komplexität umgehen zu können.
Abstraktion bedeutet, sich auf das Wesentliche zu konzentrieren, also Unwichtiges außer acht zu
lassen, und Gemeinsamkeiten zwischen verschiedenen Objekten zu erkennen.
Die (Um)welt ist von sich aus komplex. Um sie einfacher verstehen zu können, werden diejenigen
Informationen bewußt ausgewählt, die benötigt werden, um einen Sachverhalt verständlich zu machen.
Dabei wird in Kauf genommen (und sogar absichtlich darauf abgezielt), daß ein Teil der Realität nicht
berücksichtigt wird.
Durch die Anwendung von Abstraktion erhalten wir also ein Modell der Realität. Dadurch werden
Objekte identifiziert, deren Beziehungen und Abhängigkeiten, sowie deren Verhalten.
Das Resultat ist eine Klassenhierarchie.
Schwierigkeit: Grad der Abstraktion entsprechend dem Anwendungsfall geeignet zu wählen.
Eine Klasse von Objekten wird beschrieben durch
- Beschreibung der Vorgehensweise zum Erzeugen einer neuen Instanz (Konstruktor)
- gemeinsame Attribute
- gemeinsame (interne) Verhaltensweisen (private Methoden)
- gemeinsame Reaktionen (Verhaltensweisen nach Nachrichtenempfang, öffentliche
Methoden)
Hierarchiebildung
Beziehungen und Abhängigkeiten zwischen Objekten bilden Klassenhierarchien. Diese dienen dem
Problemverständnis, denn je weiter „oben“ in der Hierarchie ein Objekt einzuordnen ist, desto
allgemeiner ist es (Generalisierung). Dagegen ist ein Objekt weiter „unten“ immer eine
Spezialisierung.
Kapselung
Durch das Prinzip Kapselung wird jedes Objekt zu einer abgeschlossenen Einheit, die über definierte
Schnittstellen mit der Umwelt kommunizieren kann (Beispiel: Black Box mit Knöpfen, Schaltern und
Anzeigefeldern). Diese Form der Modularisierung hilft dabei, Problemlösungen durch Lösung von
Teilproblemen zu erzielen; dies bedeutet also eine Vereinfachung des Lösungsverfahrens.
Kapselung bedeutet, daß Attribute (Eigenschaften) und Methoden (Verhaltensweisen) in einem Objekt
zusammengefaßt werden. Der interne Aufbau und das interne Verhalten eines Objektes (Innensicht)
werden nach außen nicht gezeigt (Geheimnisprinzip, information hiding).
Von außen sind nur die zugehörigen Methodennamen eines Objektes sichtbar, aber nicht ihre konkrete
Implementation (Programmcode), d.h. ein Objekt kann nur über Botschaften (Nachrichten) die
Methoden eines anderen Objektes über klar definierte Schnittstellen auslösen, ohne die internen
Implementationsdetails zu kennen (Außensicht).
Unter Umständen beinhaltet ein Objekt eine Reihe von Attributen und Methoden, die nur intern
benötigt werden (private Methoden) und deshalb von außen (d.h. für andere Objekte) nicht verfügbar
sind. Dies verhindert z.B., daß interne Methoden und Attribute versehentlich geändert würden, was zu
Fehlern führen könnte.
Ein Vorteil der Kapselung von Attributen und Methoden ist, daß nur erlaubte Zugriffe möglich sind.
Bei der Arbeit mit einem Objekt ist somit ein unbeabsichtigter Zugriff auf interne Informationen nicht
möglich, da für diese Daten keine Schnittstelle nach außen definiert ist.
Des weiteren ermöglicht das Prinzip der Kapselung, daß die interne Struktur eines Objektes beliebig
verändert werden kann, ohne daß Programme, die dieses Objekt nutzen, umgestellt werden müssen,
denn diese bedienen sich ausschließlich der öffentlichen Schnittstellen. Anders ausgedrückt ist die
Verwendung eines Objektes unabhängig von dessen Implementierung.
Zusammenfassung Kapselung:
-
Attribute und Methoden werden in einem Objekt zusammengefaßt
Programmcode ist nach außen nicht sichtbar
Kommunikation nur über definierte Schnittstellen
Lese-/Schreibzugriff auf Attribute wird dadurch kontrolliert
Implementation kann geändert werden, sofern Schnittstellen beibehalten werden
Vererbung
Bei der Betrachtung von Klassenhierarchien werden alle Vorgänger einer Klasse als Oberklassen
(super classes, Superklassen) und alle Nachfolger als Unterklassen (sub classes, Subklassen)
bezeichnet. Eine Klasse erbt alle Eigenschaften der unmittelbaren Oberklasse und gibt all ihre
Eigenschaften an die unmittelbare Unterklasse weiter. Geerbte Eigenschaften werden dabei ebenfalls
weitergegeben. Dieser Vorgang wird als Vererbung bezeichnet. Mit Eigenschaften sind dabei
Methoden und Attribute der jeweils betrachteten Klasse gemeint.
In Java besitzt eine Klasse genau eine unmittelbare Oberklasse (mit Ausnahme der Klasse Object, die
den Kopf jeder Klassenhierarchie in Java darstellt). Ist keine konkrete Oberklasse angegeben, wird
standardmäßig Object als Oberklasse festgelegt. Durch diese Strukturierung lassen sich eindeutige
Pfade innerhalb einer Klassenhierarchie bilden.
Jede Ebene in der Hierarchie stellt eine Abstraktionsebene dar. Im Hinblick auf Wiederverwendbarkeit
ist es wichtig, daß eine Klasse der jeweiligen Hierarchieebene nur Methoden und Attribute enthält, die
diese Ebene allgemein beschreiben.
Wie erstelle ich eine Subklasse?
Zu einer Klasse kann eine Oberklasse angegeben werden. Dies geschieht durch das Schlüsselwort
extends.
Beispiel:
public class Auto extends Fortbewegungsmittel {
Was geschieht mit den Konstruktoren?
Wird in einer Subklasse kein Konstruktor implementiert, wird der Default-Konstruktor der
Subklasse ausgeführt, der seinerseits den parameterlosen Konstruktor der Oberklasse aufruft.
Wird in einer Subklasse mindestens ein Konstruktor implementiert, werden alle Konstruktoren aus
der Oberklasse überschrieben.
Was geschieht mit den Attributen?
Alle Attribute, die nicht als private in der Oberklasse deklariert sind, werden vererbt. D.h. man kann
direkt auf sie zugreifen. Vererbte Attribute können „überschrieben“ werden, indem Attribute gleichen
Namens in der Subklasse deklariert werden.
Was geschieht mit den Methoden?
Alle Methode, die nicht als private in der Oberklasse deklariert sind, werden vererbt. D.h. man kann
direkt auf sie zugreifen. Vererbte Methoden können „überschrieben“ werden, indem Methoden
gleicher Signatur (d.h. auch gleichen Namens) deklariert werden. Methoden gleichen Namens mit
anders lautender Signatur bestehen danach weiterhin (s. MSKonto.java aus der Vorlesung).
Polymorphismus (Teil 1)
Zur menschlichen Denkweise gehört es, kontextabhängig zu denken, Nachrichten also entsprechend
ihrem jeweiligen Kontext einzuordnen. In der OO, die versucht, die menschliche Denkweise
abzubilden, können Methoden kontextabhängig verwendet werden. Das wird Polymorphismus
genannt.
Im Rahmen der Vererbung werden „kontextabhängige Methoden“ weit oben in der Klassenhierarchie
angesiedelt, oft in so genannten „abstrakten Klassen“. Die konkrete Ausprägung einer Methode wird
dann weiter unten in den jeweiligen konkreten Klassen individuell realisiert (durch „Überladen“ der
Methoden).
Nehmen wir als Beispiel eine Oberklasse Fortbewegungsmittel, die eine Methode fahre() besitzt.
Fortbewegungsmittel hat die Unterklassen Auto, Flugzeug und Schiff. Jede dieser Klassen
implementiert die Methode fahre(). Trifft die Nachricht „fahre!“ in einem dieser Objekte ein (fahre()
wird aufgerufen), reagiert jedes Objekt unterschiedlich, nämlich gemäß seinem Kontext: das Auto
fährt auf dem Land, das Flugzeug fliegt in der Luft, und das Schiff bewegt sich auf dem Wasser.
In Java existieren zwei Ausprägungen von Polymorphismus:
Statisches Binden (early binding, frühes Binden) und Dynamisches Binden (late binding, spätes
Binden)
Statisches Binden:
Einfache Form von Polymorphismus, wird auch als Overloading (Überladen) bezeichnet. Dabei haben
verschiedene Methoden den gleichen Namen und den gleichen Rückgabewert, aber unterschiedliche
Signaturen. Dabei ist es unerheblich, ob diese Methoden innerhalb einer Klasse oder innerhalb einer
Klassenhierarchie implementiert sind.
Eine (Methoden-)Signatur besteht aus drei Bestandteilen:
- Rückgabewert
- Methodenname
- Datentypen der Argumentliste
Manchmal wird allein der dritte Teil als Signatur bezeichnet.
Beispiele:
public void dummy(String s, int i) hat die Signatur void dummy(String, int)
public void dummy(String s, int j) hat die Signatur void dummy(String, int)
public void dummy(int i, String s) hat die Signatur void dummy(int, String)
public void dummy(int j, String s, int i) hat die Signatur void dummy(int, String, int)
Einfach gesagt erhält man die Signatur einer Methode aus dem Implementationskopf, aus dem
Zugriffsbezeichner (public, protected, private) und Argumentbezeichner entfernt werden.
Warum heißt es statisches oder frühes Binden? Weil schon beim Kompilieren offensichtlich ist,
welche Methode gemeint ist (durch entsprechenden Methodenaufruf, d.h. die Argumentliste der
Methode, bzw. die Signatur dieser Methode). Die Entscheidung fällt also zur „Build Time“.
Dynamisches Binden:
Wird auch als Overriding (ungenau übersetzt „Überschreiben“) bezeichnet. Tritt auf, wenn in einer
Unterklasse eine Methode implementiert wird, die dieselbe Signatur (also auch denselben Namen)
besitzt wie eine Methode einer übergeordneten Klasse. Im Gegensatz zum statischen Binden kann hier
erst zur Laufzeit („Runtime“) entschieden werden, welche Methode aufgerufen werden soll, denn das
ist abhängig davon, in welchem Objekt diese Methode angesprochen wird.
Wir werden diese Form von Polymorphismus genauer im zweiten Teil betrachten.
Herunterladen