Erzeugung und Vernichtung von Tochterobjekten bei der Aggregation
Es soll an einem kleinen Beispiel eine mögliche Realisierung einer
"hat-Beziehung" aufgezeigt werden. Wie in folgendem Klassendiagramm gezeigt,
soll ein Spiel-Objekt zwei Würfel-Objekte "haben".
Das Spiel-Objekt soll für Erzeugung und Vernichtung der beiden Würfel-Objekte
verantwortlich gemacht werden. Bei Erzeugung des Spiel-Objekts sollen
automatisch die Wuerfel-Objekte mit erzeugt werden. Das kann durch eine
Erweiterung des TSpiel-Konstruktors geschehen. Ebenso soll der Destruktor die
Freigabe des Speichers der Würfel-Objekte übernehmen. In einem ersten Schritt
wird die Beziehung durch die beiden Referenzvariablen Wuerfel1 und Wuerfel2
in der Klassendefinition von TSpiel zum Ausdruck gebracht. Die zusätzliche
Funktionalität des Konstruktors und des Destruktors macht eine Erweiterung der
ererbten Methoden "Create" und "Destroy" erforderlich.
TSpiel = class(TObject)
private
Wuerfel1, Wuerfel2 : TWuerfel;
public
constructor Create;
destructor Destroy;
procedure wuerfeln;
function wurf1 : byte;
function wurf2 : byte;
end;
|
Es ist zu bedenken, dass eine "Neudefinition" des Konstruktors den alten nicht
ersetzt, sondern nur "überdeckt". Dh. es gibt (mindestens) zwei Konstruktoren
mit dem gleichen Namen. Der "alte" Konstruktor hat nun aber eine Funktionalität,
die erhalten bleiben muss. Daher besteht die Möglichkeit, mit Hilfe eines
vorangestellten "inherited" den alten Konstruktor aufzurufen, der dann z.B.
nötige Speicherbelegungen durchführt. Anschließend können die eigenen
Erweiterungen angefügt werden. Diese Reihenfolge muss eingehalten werden. So
würde ein Zugriff auf ein Datenfeld "Wuerfel1" eines noch nicht existierenden
Objekts natürlich zu einem Fehler führen.
constructor TSpiel.Create;
begin
inherited Create; // inherited; hat gleiche Wirkung
Wuerfel1 := TWuerfel.Create;
Wuerfel2 := TWuerfel.Create;
end;
|
Bei der Freigabe des Speichers muss die umgekehrte Reihenfolge eingehalten
werden. Zuerst wird der Speicher der Tochter-Objekte, dann der eigene Speicher
freigegeben.
destructor TSpiel.Destroy;
begin
Wuerfel1.Free;
Wuerfel2.Free;
inherited Destroy;
end;
|
"Eine wesentlichr Eigenart für Aggregationen ist, dass das Ganze stellvertretend
und übergreifend für seine Einzelteile handelt, d.h. Operationen übernimmt, die
dann an die Einzelteile weitergeleitet (propagiert) werden." [Oesterreich,
Objektorientierte Softwareentwicklung, S.57]
Im Beispiel werden Anfragen nach den Wurfergebnissen vom Spiel-Objekt zu den
Würfel-Objekten weitergeleitet. Für den Benutzer bleibt das transparent.
function TSpiel.wurf1 : byte;
begin
Result := Wuerfel1.GetAugen;
end;
|
Ein kleines Test-Projekt führt das Gesagte aus.
Download