Zum Menü springen.

Aufgabe 5-4

(Übungsblatt 5)

Betrachten Sie Ihre Klassenstruktur aus Aufgabe 5-3 und das folgende Code-Fragment.

GeographicPosition p1, p2;
…  // Konstruktion der Objekte
System.out.println(p1.distanceFrom(p2));
  1. Ist dieses Code-Fragment syntaktisch korrekt? Begründen Sie Ihre Antwort.
  2. Ist dieses Code-Fragment semantisch korrekt? Begründen Sie Ihre Antwort.
  3. Was folgern Sie aus dieser Situation in Bezug auf das Prinzip der Vererbung in der objektorientierten Programmierung?

Lösungsvorschlag

zu den Teilaufgaben:

  1. Das Code-Fragment ist syntaktisch korrekt. Nachgewiesen werden kann dies am Einfachsten durch Compilieren; sofern diese Anweisungen dazu in eine Methode geschrieben werden (wo sie nämlich hingehören, wie alle Anweisungen) und die Klassen GeographicPosition und Position beide zur Verfügung stehen, treten keine Fehler zur Compile-Zeit auf.

    Ein formaler Nachweis wäre mit Hilfe der Java Language Specification möglich.

    Für uns genügt sicherlich eine grobe Beschreibung der einzelnen Anweisungen. In der ersten Zeile werden zwei (lokale) Variablen vom Typ GeographicPosition deklariert. Die Variablen werden nicht gleichzeitig initialisiert; eine Zuweisung entsprechender Objekte erfolgt im zweiten (nicht dargestellten) Schritt. Die letzte Zeile ruft die Objektmethode distanceFrom(Position) auf und gibt den Rückgabewert auf der Standardausgabe aus.

    Dieser Methodenaufruf ist erlaubt, weil Position eine Superklasse von GeographicPosition ist (class GeographicPosition extends Position). Anschaulich kann man dieses Verhältnis auch anders formulieren: Jede geographische Position ist gleichzeitig auch eine (allgemeine) Position.

  2. Wie die Entfernung zwischen zwei nicht näher spezifizierten Koordinatenpaaren ermittelt wird, hängt immer von der Art der Koordinaten ab. Kartesische Koordinaten werden zum Beispiel anders behandelt als Polarkoordinaten. Folglich ist es nicht möglich, eine Methode zur Entfernungsberechnung aus nichts weiter als zwei beliebigen Koordinatenpaaren allgemeingültig anzugeben.

    Im Lösungsvorschlag zu Aufgabe 5-3 (c) wurde von kartesischen Koordinaten ausgegangen und folglich der Satz des Pythagoras verwendet. Dies ist für geographische Koordinaten offensichtlich unzulässig, weil es zu einem falschen Ergebnis führt. (Beispiel: φ1 = 60°, λ1 = 0°, φ2 = 60°, λ2 = 10° ergibt eine mit Pythagoras errechnete Distanz von 10° [≈ 1100 km auf der Erde], aber die tatsächliche Entfernung beträgt auf der Erde nur etwa 550 km [5°].)

    Folglich ist dieser Code-Abschnitt nicht semantisch korrekt.

  3. Offensichtlich ist das objektorientierte Prinzip der Erweiterung von Klassenstrukturen durch Vererbung nicht immer problemlos.

    Das Problem war in dieser Klassenstruktur das Hinzufügen der Methode für die Entfernungsberechnung zur allgemeinen Oberklasse Position. Instanzen der Unterklassen erben solche neuen Methoden automatisch – selbst dann, wenn sie im Kontext der Unterklasse gar nicht sinnvoll sind.

    Solche Probleme lassen sich umgehen, indem man Klassenstrukturen sorgfältig plant. In Fällen wie dem vorliegenden würde man für jede Art von Koordinaten eine eigene Unterklasse von Position erstellen und Position selbst dann so deklarieren, dass sie nicht instanziiert werden kann (also nur Objekte der verschiedenen Unterklassen konstruiert werden können). (Dazu setzt man entweder das Zugriffsrecht aller Konstruktoren auf private oder man deklariert die Klasse als abstrakt (abstract class).)

  4. (Eine moderne Lösung dieser Problematik stellt das Decorator-Pattern dar.)

Arne Johannessen, 4. Dezember 2007