Das Wesen des Objekt-Orientierten Ansatzes soll hier am Beispiel eines Flaschen-Objektes verdeutlicht werden. Im Mittelpunkt stehen dabei die notwendigen Fragestellungen bei der Transformation der Realität in ein OO-Modell. Die "Flaschen-Welt" mag hierzu zwar etwas komisch anmuten, es wurde jedoch bewusst ein konkretes greifbares Objekt gewählt über dessen Anwendungsfälle, Eigenschaften und Methoden sehr schnell Konsens und Klarheit hergestellt werden kann.
Wieso die Orientierung auf Objekte?
Früher zu Zeiten der prozeduralen Programmierung, zu Zeiten von DOS und Terminal-Anwendungen war alles noch einfach und überschaubar:
- Es lief nur ein Programm zur selben Zeit auf dem Bildschirm.
- Das Betriebssystem wurde mit Befehlen wie dir, copy usw. bedient.
- Die Applikation, das Programm stand im Vordergrund.
Menschen ohne entsprechenden technischem Hintergrund fällt der Umgang mit solchen Systemen schwer, sie sind nicht nutzer-gefällig, eine Alternative wurde entwickelt, die graphische Oberfläche:
- Nachbildung der Büro-Welt der Nutzer mit Schreibtisch und Ordnern usw.
- Die Aktionsumgebung wird graphisch dargestellt, visualisiert.
- Grundprinzip: Der Nutzer kann aus einer Auswahl von Möglichkeiten auswählen
- Die Dokumente stehen nun im Vordergrund, nicht mehr die Programme.
Probleme für die Software Entwickler: Komplexität dieser Systeme ist mit "klassischen" Programmiermodellen nicht mehr zu beherschen.
Lösung: Auch die Programmierumgebung an die Denkwelt der Entwickler anpassen. Menschen nehmen Ihre Umgebung als Objekte mit Eigenschaften und Methoden war:
Flasche mit Wasser aufschrauben. Brief in RTF-Format öffnen und anzeigen.
Gelingt es möglichst viel notwendige Information (Eigenschaften und Verhalten) über ein Objekt bei der Implementierung zu modellieren, kann die Komplexität (hervorgerufen durch die Interaktion der Objekte untereinander und ihr Eigenleben) für den Entwickler reduziert werden. Irrtümer über die Objekte oder Logische Fehler können so schneller erkannt werden...
Praktische Darstellung der Objekte mit ihren Eigenschaften, Methoden und Beziehungen
Es gibt nicht nur eine Objekt-Orientierte Programmiersprache: Eiffel, Java, C++, Delphi, PHP, Rubi usw.
Daher ist es sinnvoll, die Darstellung der Objekt-Informationen unabhängig von der späteren Implementierungs-Sprache zu entwickeln, auch weil sprachspezifischer Ballast dadurch keine Rolle spielt.
UML (Unified Modeling Language)
Obgleich es "Vereinheitlichte Modellierungs Sprache" heist, interessiert vor allem die graphische Modell Darstellung.
Umfassende Information findet man hier: www.uml.org
Klassen- und Objekt-Diagramm
Am Beispiel einer Flasche:
Welche Eigenschaften, Attribute (z.B. Hersteller) und Methoden, Operationen, Funktionen (z.B. aufschrauben()) sind wichtig und sollen später bei allen Flaschen vorhanden sein? Hinweis: FKZ = FließKommaZahl | ||||||||
Es wird zwischen Klassen und Objekten (Instanzen) unterschiedenDie Klasse kann als eine Art Objekt-Plan verstanden werden, in dem die Attribute beschrieben werden, die später im Objekt (Instanz der Klasse) mit Werten belegt sind. In der Klasse werden auch die Methoden (auch Operationen oder Funktionen genannt) beschrieben die mit den Objekten möglich sind. |
||||||||
Klassenregeln
Objektregeln
|
Objekte können auch so dargestellt werden: | |||||||
Anonymes Objekt ohne Instanznamen | ||||||||
Vollständige Darstellung mit Instanzname und Klassenname | ||||||||
Java-Quelltext zur Flaschen-Klasse
class Flasche { String hersteller; float fuellstand; boolean offen; void aufschrauben(){ offen = true; } void zuschrauben(){ offen = false; } }
Das Geheimnisprinzip
Nun nehmen wir einen Schluck aus der Falsche, ändern den Füllstand: dieFlasche.fuellstand = dieFlasche.fuellstand -0.05. Aber moment, die Flasche ist doch gar nicht offen! Trotzdem konnte der Füllstand geändert werden, das entspricht nicht der Realität. Um die Realität nachzubilden sollte zuerst überprüft werden, ob die Falsche offen ist, ein direkter Zugriff auf den Füllstand von aussen darf es nicht geben. Die Attribute sollen privat sein, durch Methoden geschützt werden. Das nennt man das Geheimnisprinzip. Private Dinge werden mit '-' und öffentliche Dinge mit '+' im Klassendiagramm gekennzeichnet. Da man nun von aussen nicht mehr auf den Füllstand zugreifen, kann muss eine öffentliche Methode getFuellstand() eingefügt werden um den Füllstand abfragen zu können. Die Attribute hersteller und fuellstand lassen sich nun aber nicht mehr mit Werten von aussen belegen, es fehlen die set- und get-Methoden.. Oder ein anderes Verfahren... |
Java-Quelltext zur Flaschen-Klasseclass Flasche { private String hersteller; private float fuellstand; private boolean offen; public void trinken(float n){ if (offen){ if (fuellstand > n) fuellstand -= n; else fuellstand = 0.0; } } public float getFuellstand(){ return fuellstand; } public void aufschrauben(){ offen = true; } public void zuschrauben(){ offen = false; } } |
Die Geburt einer Flasche -der Konstruktor
Alle Klassen erben von der Mutter aller Klassen "Objekt" einen Standardkonstruktor. Ein Konstruktor ist eine Methode, die ein Objekt erzeugt.
In Java haben die Konstruktoren den Namen der Klasse:
Flasche dieFlasche = new Flasche();
Hier wird eine Varible vom Typ "Flasche" mit dem Namen "dieFlasche" deklariert und mit einem neuen Objekt vom Typ "Flasche" initialisiert.
Genauer: "dieFlasche" ist ein Verweis (in C++ ein Zeiger oder Pointer) auf ein Flaschen-Objekt. Wird kein Objekt zugewiesen hat der Verweis den Wert "null".
In dem Beispiel wird jedoch durch den Standardkonstruktor "Flasche()" ein Objekt gebaut. Der Standardkonstruktor initialisiert alle Attribute mit Standardwerten:
- Zahlen mit 0 bzw. 0.0
- Strings mit "", leerer String
- Verweise mit null
Eigenen Konstruktor bauen
Will man mehr als der Standardkonstruktor leistet, überschreibt man ihn einfach durch einen eigenen Konstruktor:
class Flasche { .... public Flasche(){ hersteller = "Wildbadquelle"; fuellstand = 0.7; } ... }
Wird nun ein neues Flaschen-Objekt mit new Flasche() erzeugt, so sind die Attribute hersteller und fuellstand richtig initialisiert.
Der Tod: Destruktoren in Java?
In Java ist es nicht erforderlich, nicht mehr gebrauchte Objekte mittels eines Destruktors weg zu räumen. Existiert kein Verweis mehr auf ein Objekt gibt der Garbage Collector (Müllsammler) des Java-Laufzeitsystems den Speicherplatz wieder frei. Der Garbage Collector ist ein Prozess, der nur bei Bedarf aufgerufen wird, weil z.B. freier Speicherplatz gebraucht wird, man kann ihn auch explizit mit System.gc() aufrufen.
Wer bei der Bestattung des Objekts noch Aktionen (Aufräumarbeiten) ausführen möchte, implementiert die Methode finalize(), die zur Beerdigung vom Garbage Collector aufgerufen wird.
Überladen von Methoden -selber Name andere Funktion
Es gibt nicht nur 0.7 Liter Flaschen eines speziellen Herstellers. Praktisch wäre noch ein Konstruktor mit dem man andere Flaschen bauen kann:
class Flasche { .... public Flasche(){ hersteller = "Wildbadquelle"; fuellstand = 0.7; } public Flasche(String s, float f){ hersteller = s; fuellstand = f; } ... }
Nun kann eine 0.7 Liter WiBa einfach mit new Flasche() erzeugt werden und eine 0.5 Liter Hahnen mit new Flasche("Hahnen",0.5).
Signatur
Der Compiler kann anhand der Signatur, das ist das Aufrufmuster, unterscheiden welche Flaschen-Methode gemeint ist.
Die Signatur ist der Name einer Methode zusammen mit der Reihenfolge und den Typen der Parameter.
Beispiel:
Methode plus für ganze Zahlen (GZ) | Methode plus für Fliesskommazahlen (FKZ) |
---|---|
int plus(int a, int b){ return a+b; } |
float plus(float a, float b){ return a+b+1; } |
plus (3,4) ergibt 7, plus (3.0,4.0) ergibt hier 8.0 weil das plus für Fliesskommazahlen verwendet wird.
Statische Polymorphie
Polymorphie bedeutet Vielgestaltigkeit. Es gibt hier zwei Plus-Methoden. Da der Compiler bereits zur Compile-Zeit weis welche Methode aufgerufen werden soll spricht man hier von Statischer Polymorphie.
Wozu braucht man this?
Wir beziehen uns auf das Objekt.
Static hilft merken, die Existenz der Information ohne Objekt
Flaschen sollen automatisch Seriennummern kriegen..
Vererbung
super
Dynamische Polymorphie
Gruppenarbeit: Finde UML-Darstellung zu folgenden Dingen:
- Auto
- Buch
- Spinne
Schwierigkeit hierbei: Was ist wirklich wichtig, welche Information muss tatsächlich erfasst werden?
Der Anwendungsfall ist wichtig -> Use Case
OOA -> jage und sammle Information
Implementierung der Flasche in Java: Einführung in die Umgebung wenn notwendig..
Static main()
Weitere Attribute sind notwendig: Position der Flasche in dem Fenster.
Konstruktor / Destruktor
Geheimnisprinzip
Modifizierer
Kann der Füllstand einfach so geändert werden?
Nein erst muss die Flasche aufgeschraubt werden, wie kann man das implementieren?
Beziehungen
Aggregation
Komposition
Vererbung
Überladen, Überschreiben
Sequenzdiagramm
Zustandsdiagramm
Worin liegen die Vorteile der objektorientierten Programmierung?
Unterschied zwischen Klasse und Objekt?
Was ist Konstruktor?
Wozu braucht man einen Destruktor?
Was versteht man unter dem Überladen von Funktionen?