Benutzer:Rolf b/Objektbeziehungen

Aus SELFHTML-Wiki
Wechseln zu: Navigation, Suche

Objektbeziehungen

Ein Aspekt von Objekten ist, zusammengehörige Daten und die dafür benötigten Operationen an einer Stelle zu bündeln, damit eine inhaltliche Trennung zu anderer Funktionalität möglich ist. Ein Objekt wie "Person" gehört eher zum Bereich der Datenhaltung einer Anwendung und benötigt weniger Methoden. Aber dafür hat eine Person etwas anderes: Beziehungen. Eine Person A hat eine oder mehrere Adressen, Kinder, Verträge, Besitzgegenstände - all dies sind Daten, die nicht direkt zur Person A gehören, sondern eigene Objekte bilden. Man spricht hier allgemein von einer Assoziation zwischen Objekten.

Um eine solche Assoziation im Programm abbilden zu können, ist es nicht ungewöhnlich, dass in einer Eigenschaft eines Objekts ein anderes Objekt gespeichert ist. Beispielsweise könnte eine Person eine Eigenschaft adresse besitzen, worin sich ein Objekt findet, das die Wohnort-Adresse dieser Person beschreibt. Tatsächlich könnte eine Person auch mehrere Adressen besitzen, beispielsweise eine Wohnortadresse, ein Postfach und die Adresse einer Zweitwohnung. In diesem Fall würde man die adresse-Eigenschaft in adressen umbenennen und darin ein Array speichern, das die Adressen enthält, die dieser Person zugeordnet sind.

Ein Programm, das das Person-Objekt nutzt, kann dann über die adressen-Eigenschaft die gewünschte Adresse erhalten. Für das folgende Beispiel nehmen Sie bitte an, dass wir Konstruktorfunktionen für Personen und Straßenadressen hätten, und der Person-Konstruktor eine Eigenschaft adressen erzeugt, die ein leeres Array enthält. Die Objekte werden im Beispiel mit festen Werten erzeugt, in einer praktischen Anwendung würden sie aus einer Datenbank oder über einen Webservice geladen.

Von der Person zur Adresse
// Person und Adresse erzeugen
const person = new Person("Max", "Mustermann");
const adresse = new Adresse("12345", "Musterstadt", "Maxistraße 15");
// Adresse der Person im adressen-Array speichern
person.adressen.push(adresse);

// an anderer Stelle
if (person.adressen.length > 0)      // Wenn Adressen da sind
   plz = person.adressen[0].plz;     // PLZ aus erster Adresse lesen

Die letzte Codezeile zeigt, wie in einer solchen Mischung aus Objekten und Arrays von einem Objekt zum nächsten weiternavigiert wird. person.adressen liefert das Adressen-Array. person.adressen.length die Anzahl seiner Einträge, person.adressen[0] den ersten Eintrag darin und person.adressen[0].plz die plz-Eigenschaft des ersten Eintrags. JavaScript arbeitet sich einfach von links nach rechts durch diese Ketten.

Die adressen-Eigenschaft bringt uns zu einer weiteren Eigenschaft von Beziehungen: Die Rolle. Wenn zwei Objekte miteinander in Beziehung stehen, drückt das Vorhandensein dieser Beziehung etwas aus. Wenn eine Person eine Eigenschaft "erstWohnsitz" hat und darin eine Adresse gespeichert ist, so hat diese Adresse die Rolle des Erstwohnsitzes dieser Person. Eine andere Person könnte ebenfalls in Beziehung zu dieser Adresse stehen, aber über die Eigenschaft "dienstAdresse". Die Adresse hat in dieser Beziehung eine andere Rolle.

Hat man mehrere Adressen unter einer Eigenschaft gesammelt, wie im oben gezeigten Codebeispiel, ist das Darstellen einer Rolle nicht mehr so einfach. An der Adresse kann man die Rolle nicht speichern, denn sie könnte ja von mehreren Personen in verschiedenen Rollen genutzt werden. In solchen Fällen schaltet man ein weiteres Objekt zwischen, das die Rolle repräsentiert. Die adressen-Tabelle der Person enthält die AdresseRolle-Objekte, und die AdresseRolle-Objekte verweisen auf die eigentliche Adresse.

Die Person könnte dann eine Methode findeAdresse befinden, der man die Rollenbezeichnung als Argument übergibt. Diese Methode geht die AdresseRolle-Objekte durch und sucht die richtige heraus.

Wenn das Programm nur das Adresse-Objekt im Zugriff hat, fehlt allerdings der Rückweg zur Person. Deswegen werden solche Beziehungen oft auf beiden Seiten gespeichert, d.h. das Adresse-Objekt könnte eine Eigenschaft bewohner besitzen, in der das Person-Objekt abgelegt wird.

Die Beziehung zwischen Personen und Adressen hat die Besonderheit, dass eine Person ohne Adresse und eine Adresse ohne Person existieren kann. Die Objekte sind gleichwertig. Anders ist es beispielsweise bei einer Rechnung. Die wird ebenfalls an eine Adresse geschickt, aber die Rechnungsposten, die sich darauf befinden, ergeben ohne die Rechnung keinen Sinn, und das Rechnung-Objekt allein ergibt ohne die zugehörigen Posten ebenfalls wenig Sinn. Diese Form der Assoziation nennt man Komposition. Sie hat ein eindeutiges führendes Objekt, dem die beteiligten Komponenten untergeordnet sind. An Stelle einer Beziehung der Art "X hat ein Y" hat man nun die Beziehung "Y ist Teil von X". Bei einer Komposition ist es eher unüblich, den untergeordneten Objekten einen Verweis auf das übergeordnete Objekt mitzugeben.

Was man dafür bei Kompositionen finden kann, sind Methoden am führenden Objekt, die untergeordnete Objekte zusammenfassen. Ein Beispiel wäre die Rechnungssumme:

Zusammenfassen von Rechnungsposten
Rechnung.prototype.ermittleRechungsSumme = function() {
   let summe = 0;
   for (let rechnungsposten of this.posten) {
      summe += rechnungsposten.betrag;
   } 
   return summe;
};
Diese Methode könnte man dann so anwenden:
let summe = rechnung.ermittleRechnungsSumme();

An dieser Stelle ein Hinweis auf die Benennung: Methoden tun etwas. Deshalb enthält ihr Name zumeist irgendein Verb. Würde man die Methode einfach nur rechnungsSumme nennen, könnte man dahinter eine Eigenschaft vermuten, statt einer Methode, und die Klammern für den Funktionsaufruf vergessen. An dieser Stelle bieten sich selbstdefinierte get-Methoden an, die wie eine Eigenschaft aussehen, aber keine sind. Dazu später mehr.