5.1 Einführung Objektorientierung

5.1 Einführung Objektorientierung

"Information Hiding" und Datenkapselung im abstrakten Datentyp

Ein Bestandteil der Objektorientierung ist das "information Hiding" welches schon von den abstrakten Datentypen her bekannt ist. Der Zustand des Objekts wird durch seine Attribute bestimmt. Die Attribute sollen aber nicht beliebig geändert werden können. Die Methoden agieren als Wächter für die Zustandsübergänge und "bewachen" so zu sagen die Attribute des Objekts. Dies hat zwei wesentliche Vorteile

  • Der Entwickler kann denn Zustand seines Objekts bzw. Datentyps immer genau kontrollieren
  • Der Entwickler kann die interne Implementierung des Objekts an neue Anforderungen anpassen ohne, dass er dies mit den Benutzern des Objekts kommunizieren muss. Die Methoden bilden hierdurch eine Schnittstelle zwischen der Implementierung und der externen Sicht des Objekts

Methoden erfüllen in diesem Kontext mehrere Aufgaben:

  • Sie lesen die internen, geschützten Datenstrukturen aus
  • Sie ändern die internen Datenstrukturen
  • Sie können komplexe Berechnungen durchführen
  • Sie können wiederum andere Objekte manipulieren (von denen der Benutzer nichts weiß)

Information Hiding: Ein Teilsystem darf nichts von der Implementierung eines anderen Teilsystems wissen

Klasse

Nach Wikipedia:

Unter einer Klasse versteht man in der objektorientierten Programmierung ein abstraktes Modell bzw. einen „Bauplan“ für eine Reihe von ähnlichen Objekten.

Die Klasse dient als Bauplan für Abbildung von realen „Objekten“ in Softwareobjekten und enthält Attribute (Eigenschaften) und Methoden (Verhaltensweisen) der Objekte. Verallgemeinernd könnte man auch sagen, dass eine Klasse dem Datentyp eines Objekts entspricht.

Klassen

  • sind eine Menge von gleichartigen, individuellen Objekten
  • sind ein schematische Modell
  • beschreiben
    • Eigenschaften (die Attribute einer Klasse)
    • Verhalten (Methoden)

Objekt

Nach Wikipedia:

Ein Objekt bezeichnet in der objektorientierten Programmierung (OOP) ein Exemplar eines bestimmten Datentyps oder einer bestimmten Klasse (auch „Objekttyp“ genannt). In diesem Zusammenhang werden Objekte auch als „Instanzen einer Klasse“ bezeichnet. Objekte sind also konkrete Ausprägungen („Instanzen“) eines Objekttyps.

Stefan Schneider Mon, 08/23/2010 - 19:39

5.1.1 Datenkapselung

5.1.1 Datenkapselung

Das erste Konzept, die Datenkapselung, kann man als eine technische Weiterentwicklung der abstrakten Datentypen sehen.

  1. Primitive Datentypen (z.Bsp. int x = 10;)
  2. Strukturierte Datentypen wie Felder oder struct in der Programmiersprache C erlauben mehrere Typen in einer Struktur zusammenzufassen.
  3. Klassen, die es erlauben mehrere Datentypen (diese werden Attribute genannt) mit den dazugehörigen Methoden zusammenzufassen und zu kapseln.
    • Beispiel: Eine Linie, die aus zwei Punkten besteht und den Zugriff auf die Punkte nur nach bestimmten Vorschriften in Methoden kapselt.

Datenkapselung ist das Verbergen von Attributen und Methoden durch Einschränkung des Zugriffs von Ausserhalb der Klasse.

Durch dieses Prinzip ergeben sich beim Entwurf und bei der Wartung von Anwendungen eine Reihe von Vorteilen:

  • Divide et impera (Teile und herrsche): Benutzer und Implementierer einer Klasse können unabhängig von einander entwickeln. Der Entwickler muss nur darauf achten die externen Schnittstellen (öffentliche Methoden und Attribute) stabil zu halten.
  • Integrität: Unbeabsichtigte Zustandsänderungen werden unterbunden. Beim Setzen eines Attributs müssen eventuell noch andere Operationen durchgeführt werden.

Datenkapselung ist die Voraussetzung zur Implementierung von Schnittstellen:

Schnittstelle
Die Gesamtheit der öffentlichen Strukturen einer Datenstruktur(Klasse) mit der Konsumenten(Verwender) einer Datenstruktur interagieren können. Schnittstellen stellen die Funktionalität einer Datenstruktur(Klasse) nach außen zur Verfügung.

 Entwickler sollten beim Anwendungsentwurf eine:

  • maximale Datenkapselung und
  • minimale Schnittstelle

einplanen. Klassen sollten möglichst autark sein und auf möglichst wenig andere Schnittstellen und Klassen zugreifen.

Sichtbarkeitssteuerung in Java mit Hilfe der Schlüsselwörter public und private

Java erlaubt den Zugriff auf Methoden und Attribute mit Hilfe der Schlüsselwörter private und public vor dem Namen des Attributs oder Methode zu steuern:

  • public: Methoden und Attribute einer Klasse können
    • von Methoden der Klasse selbst genutzt werden
    • von Methoden andere Klassen genutzt werden (externe Benutzung)
  • private: Methoden und Attribute einer Klasse können
    • von Methoden der Klasse selbst genutzt werden
    • nicht von Methoden ausserhalb der Klasse genutzt werden

Diese Zugriffssteuerung erlaubt die Implementierung der folgenden Empfehlung

  • Eine Klasse sollte nur die Attribute und Methoden veröffentlichen die externe Konsumenten unbedingt brauchen
  • Man sollte als Standard alle Attribute als private deklarieren
  • Man sollte als Standard Zugriff auf Attribute immer nur indirekt über öffentliche Methoden (public) gewährleisten

 Attribute und Methoden ohne ein Schlüsselwort werden in Java als public Attribute und Methoden behandelt um den Zugriff im gleichen Paket zu erlauben.

Java verfügt auch über das Schlüsselwort protected welches den Zugriff nur innerhalb eines Pakets erlaubt. Pakete werden erst in der weiterführenden Vorlesung eingeführt werden.

Zugriffssteuerung mit Get- und Set- Methoden

Es ist eine Konvention (und guter Programmierstil) in Java den Zugriff auf private Attribute mit Methoden zu gewähren denen man vor dem Attributnamen get- bzw. set- voranstellt:

class Person() {
   private String name;
   public void setName(String n) { name = n;}
   public String getName() { return name;}
}
getter und setter Methoden

Dieser Programmierstil bietet eine Reihe von Vorteilen:

  • zukünftige Wartungsaufwände und Erweiterungen können leichter implementiert werden, da externe Benutzer ihre Implementierung nicht ändern müssen
    • Die interne Implementierung kann vollständig geändert werden solange die Signatur der öffentlichen Methoden unverändert bleibt.
  • get-, set- Methoden erlauben das Implementieren weitergehender Konsistenzprüfungen.

Anmerkung: Laufzeiteinbußen durch solche Trivialmethoden sind in der Regel nicht zu befürchten. Der Java "Just in Time" (JIT) Übersetzer des Laufzeitsystems wird mit hoher Wahrscheinlichkeit solche Methoden zur Laufzeit durch Methoden-inlining wegoptimieren.

Stefan Schneider Fri, 10/15/2010 - 09:15

5.1.2 Architekturprinzipien

5.1.2 Architekturprinzipien

Trennung der Zuständigkeiten

Trennung von Zuständigkeiten(Separation of Concerns) ist ein Konzept welches auf Datenkapselung aufbaut.

Die Idee besteht darin Zuständigkeiten Klassen zu zuordnen.

Alle Aufgaben die in einen Bereich fallen sollen möglichst von genau einer Klasse implementiert werden. Ziel ist es, dass unabhängige Dinge auch in der Implementierung unabhängig voneinander bleiben. Hierdurch

  • sinkt die Gesamtkomplexität und Systeme sind einfacher zu verstehen 
  • unterschiedliche Komponenten können unabhängig von einander gepflegt werden
  • Fehler in einem Bereich sollen sich möglichst nicht in einem anderen Bereich bemerkbar machen

Ziel ist es Klassen so zu modellieren, dass sie möglichst in sich abgeschlossen sind.

Ein Beispiel hierfür:

  • Die Webarchitektur
    • html (Hypertext Markup Language) ist die Seitenbeschreibungssprache
      • css (Cascading Style Sheets) ist die Sprache zur Beschreibung des Layouts der Seite (getrennt vom Inhalt)
    • http ist das Protokoll zur Übertragung der html Seiten (getrennt vom Inhalt)

Entwurfsmuster "Model View Controller" (MVC)

MVC ist ein Entwurfmuster welches aus den folgenden drei Einheiten besteht:

  • Model (Datenmodell) Alle Aspekte die die Daten betreffen (Integrität, Speicherung, Konvertierung etc.)
  • View (Präsentation): typischerweise die Benutzerschnittstelle einer Anwendung mit allen graphischen und interaktiven Komponenten
  • Controller(Programmsteuerung): Die Ablauflogik und Steuerung eines Programmes
MVC pattern

Die Einteilung einer Anwendung in die folgenden drei Bereich ist oft vorteilhaft da häufig

  • die Benutzerschnittstellen angepasst oder ausgetauscht werden müssen. Das Datenmodell ist dann nicht betroffen. Die Benutzerschnittstelle sollte unabhängig von den anderen Komponenten sein um unterschiedliche Technologien (Web, rich client, OS spezifische Bibliotheken) nutzen zu können
  • das Datenmodell auf andere Datenbankprodukte angepasst werden muss ohne das andere Komponenten davon betroffen sein sollen
  • die Ablauflogik angepasst werden muss und die Änderungen in den Benutzerschnittstellen minimal gehalten werden sollen

Wichtig ist zu verstehen, dass die drei Komponenten zusammenarbeiten und idealerweise unabhängig voneinander sind. Das Model sollte zum Beispiel auf Aufrufe von View und Controller reagieren, jedoch nicht selbst diese Komponenten aufrufen.

Schichtenarchitektur

Schichtenarchitekuren sind eine andere Ausprägug der "Separation of Concerns".

Java selbst und Javaanwendungen basieren auf dem Schichtenmodell.

Eine Javaanwendung soll nur auf die Dienste der Java Runtime zurückgreifen. Die Java Runtime bietet hierfür eine reichhaltige Infrastruktur für GUI Programmierung, Datenbankzugriff, Netzwerkkommunikation, Dateizugriff etc.

Beschränkt man sich auf die von der Java Runtime angebotenen Dienste wird man unabhängig vom Betriebssystem und der darunter liegenden Hardware.

Ziel bei der Entwicklung einer Anwendung sollte es sein unterschiedliche Schichten zu identifizieren und von Klassen nur auf die eigene Schicht oder die darunter liegende Schicht zu beschränken.

Stefan Schneider Fri, 10/15/2010 - 13:17

5.1.3 Entwurfsmuster (Design Patterns)

5.1.3 Entwurfsmuster (Design Patterns)

Duke mit Blueprint

Nach Wikipedia:

Entwurfsmuster

Entwurfsmuster (engl. design patterns) sind bewährte Lösungs-Schablonen für wiederkehrende Entwurfsprobleme in der Softwarearchitektur und -entwicklung.

Sie stellen damit eine wiederverwendbare  Vorlage zur Problemlösung dar, die in einem bestimmten Zusammenhang einsetzbar sind

Referenzen

Im zweiten Semester werden die Entwurfsmuster

benutzt.

In der Vorlesung des ersten Semesters werden einige wenige, ausgewählte Entwurfsmuster vorgestellt:

Stefan Schneider Tue, 03/29/2011 - 20:53

Factory (Fabrikmethode)

Factory (Fabrikmethode)

Es gibt Situation, in denen möchte man die Erzeugung neuer Objekte nicht im Konstruktor einer Klasse durchführen weil man z.Bsp.

  • Zusätzliche Verwaltungsaufgaben durchführen möchte (z.Bsp. Registrierung des Objekts)
  • Nicht mehr benötigte Objekte wieder verwenden möchte ( z.Bsp. Datenbankverbindungen)
  • Die Wahl haben möchte Unterschiedliche Spezialisierungen einer Klasse oder die Implementierung einer Schnittstelle nutzen möchte.

Dieser Anwendungsfall wird mit dem Entwurfsmuster "Factory" (Fabrikmethode) beschrieben. 

Verwendung

Eine Fabrikmethode

  • erzeugt bei jedem Aufruf neue Objekte
  • unterbindet den direkten Zugriff auf die Konstruktoren einer Klasse

Eine Fabrikmethode (Factory) besteht typischer Weise aus

  • einem privaten Konstruktor
  • einer öffentlichen statischen Methode die den privaten Konstruktor nutzt

Kategorie

Eine Fabrikmethode (Factory) gehört zur Kategorie der Erzeugungsmuster (Creational Pattern).

UML Diagramm

Naive Javaimplementierung

/**
 * Einfache Implementierung der Fabrikmethode (Factory)
 */
public class Factory {
     /**
     * privater Konstruktor der nur innerhalb der Klasse
     * aufgerufen werden kann
     */
    private Factory() {
      // Individuelle Initialisierung erfolgt hier
    }
     /**
     * Erzeugen der Objekte.
     */    
   public static Factory getInstance() {
        // Vorarbeiten
        instanz = new Factory();
        // Nacharbeiten
        return instanz;
    }}

 

Stefan Schneider Sat, 12/15/2018 - 13:56

Singleton (Einzelstück)

Singleton (Einzelstück)

Es gibt Anwendungsfälle in denen es gewünscht ist genau ein Objekt global zur Verfügung zu stellen. Dieser Anwendungsfall wird mit dem Entwurfsmuster "Singleton" (Einzelstück) beschrieben. Beispiele für solche Anwendungsfälle sind:

  • Implementierung eines seriellen logging Mechanismus
  • Implementierung eines Puffers für einen Drucker

Verwendung

Ein Einzelstück

  • verwaltet genau ein eine Klasse mit genau einem Objekt
  • unterbindet die Erzeugung von anderen Objekten einer Klasse
  • erlaubt einfachen Zugriff auf ein solches Objekt

Ein Singleton (Einzelstück) implementiert eine ähnliche Struktur wie eine globale Variable.

Kategorie

Das Einzelstück (Singleton) gehört zur Kategorie der Erzeugungsmuster (Creational Pattern).

UML Diagramm

Naive Javaimplementierung (Lazy initialization)

/**
 * Einfache Implementierung des Einzelstueck (Singleton
 */
public class Einzelstueck {
    private static final Einzelstueck instanz;
     /**
     * privater Konstruktor der nur innerhalb der Klasse
     * aufgerufen werden kann
     */
    private Einzelstueck() {
      // Individuelle Initialisierung erfolgt hier
    }
     /**
     * Erzeugen des einzigen Objekts falls noch keines existiert.
     * Rückgabe des Objekts falls es schon existiert
     * Diese Methode ist statisch. Sie kann auch ohne die Existenz einer Instanz aufgerufen werden.
     * Die Methode ist die einzige öffentliche Methode
     */    
   public static Einzelstueck getInstance() {
        if (instanz == null) {
            instanz = new Einzelstueck();
        }
        return instanz;
    }}

Das gezeigte Beispiel verwendet eine "Lazy initialization". Das Objekt wird erst erzeugt wenn es auch wirklich benötigt wird. Hierdurch kann das unnötige Allokieren von Ressourcen vermieden werden.

Der Nachteil dieser Implementierung besteht darin, dass sie nicht threadsicher ist. In einem Javaprogramm mit mehreren Threads (Ausführungseinheiten) können zwei Threads gleichzeitig ein Objekt erzeugen und damit das gewünschte Ziel des Einzelstücks durchkreuzen.

Threadsichere Javaimplementierung

/**
* Threadsichere Implementierung des Entwurfsmuster Einzelstueck (Singleton)
*/
public class Einzelstueck {
    private static Einzelstueck instanz = new Einzelstueck();
     /**     
     * privater Konstruktor der nur innerhalb der Klasse
     * aufgerufen werden kann
     */
    private Einzelstueck() {
      // Individuelle Initialisierung erfolgt hier
    }
     /**
     * Diese Methode ist statisch. Sie kann auch ohne die Existenz einer Instanz aufgerufen werden.
     * Die Methode ist die einzige öffentliche Methode
     */
    public static Einzelstueck getInstance() {
        return instanz;
    }
}

Die hier gezeigte Implementierung ist threadsicher da die Instanz schon beim Laden der Klasse erzeugt wird.

 

Stefan Schneider Tue, 03/29/2011 - 20:56