MezData-Logo

Zen oder die Objekt-Orientierte Flasche

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:

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:

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) unterschieden

Die 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

  • Klassenname beginnt immer mit Grossbuchstaben
  • Attribute beginnt immer mit Kleinbuchstaben
  • Methoden beginnen klein mit einem Verb und enden mit ()

Objektregeln

  • Instanzname beginnt immer klein und wird unterstrichen
  • jedem Attribut wird ein Wert zugeordnet
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-Klasse

class 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:

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:

FrageSchwierigkeit 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

FrageWorin liegen die Vorteile der objektorientierten Programmierung?

FrageUnterschied zwischen Klasse und Objekt?

FrageWas ist Konstruktor?

FrageWozu braucht man einen Destruktor?

FrageWas versteht man unter dem Überladen von Funktionen?