6. Assoziation
Für die Assoziation gilt:
Während in der OOA vorzugsweise zunächst
nur ungerichtete Assoziationen gezeichnet werden sollten, |
 |
kann im Entwurf
eine gerichtete Assoziation bereits Hinweise auf die Richtung des
Zugriffs und die Art der
Implementation geben. Beispiel: Dem Kunden wird ein Kundenbetreuer zugeordnet. |
 |
a) gerichtete Assoziation
Dazu ist es erforderlich, dass in der Klientenklasse
-
ein Referenzattribut auf das Serverobjekt vereinbart wird
-
Methoden eingeführt werden, die die Beziehungen aufbauen und
wieder entfernen können.
TKunde = class (TObject)
private
Nummer :
integer;
Name :
string[15];
Betreuer:
TBetreuer;
// Referenzattribut
public
constructor
Create;
procedure
SetLink (betr : TBetreuer);
// Verbindung herstellen
function
GetLink : TBetreuer;
// Ref. holen
procedure
RemoveLink;
// Ref. löschen
procedure
SetNummer (n: integer);
...
end;
Die Set-/GetMethoden werden wie üblich implementiert; RemoveLink so:
procedure RemoveLink;
(* ----------------- *)
begin
Betreuer:= NIL;
end;
Bis hierher sind das alles nur die technischen Vorbereitungen
(Deklaration). Die Verknüpfung selbst wird in einer operativen Einheit (z.
B. GUI) bei Bedarf hergestellt
TFensterFrm = class(TForm)
SteuerPnl : TPanel;
...
private
Kunde : TKunde; //
Referenzattribute auf die Objekte
Betreuer: TBetreuer;
procedure Init;
..
end;
IMPLEMENTATION
...
procedure TFensterFrm.ErfassenBtnClick(Sender: TObject);
(* --------------------------------------------------------------- *)
begin
Kunde := TKunde.Create;
//
Clientobjekt erzeugen
Betreuer := TBetreuer.Create;
// Serverobjekt erzeugen
PersDatenAktualisieren;
// Daten aus
dem Fenster übernehmen
BetreuerDatenAktualisieren; // ""
Kunde.SetLink(Betreuer);
// Assoziation
herstellen
Kundenliste.Append (Kunde); //
komplett in die Liste übernehmen
end;
Das Lesen und Anzeigen des dazugehörigen Betreuers läuft wieder über
die Referenz in Kunde:
procedure TFensterFrm.ErsterBtnClick(Sender: TObject);
(* ------------------------------------------------------------------- *)
begin
Kundenliste.First;
Kunde := Kundenliste.GetElement;
KundenMaskeAktualisieren;
Betreuer:= Kunde.GetLink;
// Referenz auf das Serverobjekt holen
BetreuerMaskeAktualisieren;
// und jetzt kann es angezeigt werden
end;
b) bidirektionale Assoziation
Dieser Abschnitt
ist bisher aus guten Gründen nicht veröffentlicht worden, soll aber wegen
mehrfacher Nachfragen angefügt werden. In leicht lesbaren Einführungen
heißt es oft, in der OOP treten die Objekte mit einander in Beziehung und
tauschen Nachrichten aus. Das suggeriert, daß die Objekte scheinbar
beliebig in Kontakt treten können und sich gegenseitig kennen. Wäre dem
so, dann könnte man in einem Programm unterschiedliche Objekte einfach
aufeinander loslassen und die erledigen dann irgendwas. Eine derartige
Programmstruktur könnte man (temporär) netzartig nennen. Leider ist das
nicht so einfach. Wenn zwei Objekte sich gegenseitig ansprechen können,
nennt man das eine bidirektionale Assoziation. In Programmstrukturen, die
hierarchisch aufgebaut sind und daher relativ sicher und übersichtlich,
vermeidet man nach Möglichkeit bidirektionale Assoziationen. Wenn in einem
Entwurf derartige Situationen auftreten, deutet es oft darauf hin, daß der
Entwurf in der OOA nicht sauber aufgelöst ist. Sollte aus sehr guten Gründen dann
doch einmal eine derartige Beziehung implementiert werden, bietet Delphi
nur eine eingeschränkte Möglichkeit an. Den Import der
gegenseitigen Units im Interface-Teil wie üblich quittiert Delphi mit der
Fehlermeldung 'Überkreuzender Bezug zweier Units ..' und bietet dafür den
Import im Implementation-Teil an.
Beispiel:
Eine Firma stellt den Mitarbeitern einen Firmenwagen. Beim
Mitarbeiter soll der KFZ-Typ gespeichert werden und beim KFZ der
Mitarbeiter. Man soll also fragen können: Welches Auto hat Müller? Wer
fährt den BMW? |
 |
Dieses Beispiel soll nur zur Demonstration einer möglichen
Implementierung dienen, keinesfalls aber als Vorlage für einen
Entwurf! |
In uMitarbeiter ist die Vorgehensweise gezeigt. Um den Linkaufbau variabel zu halten,
soll der Parameter vom Typ TObject
sein. Der Operator IS führt
eine dynamische Typprüfung durch und AS die erforderliche Typumwandlung
zur Laufzeit.
procedure TMitarbeiter.SetLink (obj : TObject);
(*
-------------------------------------------------------------------- *)
begin
if obj IS TAuto // Typprüfung
then ...
end;
Die Klasse TAuto wird analog implementiert.
Die GUI-KLasse bietet keine besonderen Probleme. Es können ein
oder auch mehrere Objekte assoziiert werden.
UNIT uMitarbeiter;
(* ******************************************************************** *)
(* K L A S S E : TMitarbeiter *)
(* -------------------------------------------------------------------- *)
(* Version : 0.9 *)
(* Autor : S. Spolwig, OSZ-Handel I, 10997 Berlin *)
(* Aufgabe : bildet das Objekt Mitarbeiter ab, *)
(* speichert aktuellen Firmenwagen *)
(* Compiler : DELPHI 6.0 *)
(* Aenderung : V. 1.1 30-DEZ-06 *)
(* ******************************************************************** *)
INTERFACE
(* ========================== Export ================================== *)
type
TMitarbeiter = class (TObject)
private
Name,
Vorname : string[15];
AutoID : string[10]; // Firmenwagen
public
constructor Create;
procedure Init;
procedure SetName (n: string);
procedure SetVorName (vn: string);
function GetName : string;
function GetVorName : string;
function GetAutoID : string;
procedure SetLink (obj : TObject);
function GetLink : TObject;
procedure RemoveLink;
end; (* TMitarbeiter *)
(* -------------------- B e s c h r e i b u n g -------------------------
Oberklasse : -
Bezugsklassen : TAuto
Methoden
--------
Create
Auftrag: Mitarbeiter erzeugen und Initialisieren
vorher : -
nachher: Mitarbeiter ist erzeugt
Init
Auftrag: Mitarbeiter Initialisieren
vorher : ist erzeugt
nachher: Name ist 'Müller'; andere Attribute sind leer.
Set...
Auftrag: Attribut schreiben
vorher : Mitarbeiter ist vorhanden.
nachher: Attribut ist gesetzt
Get...
Anfrage: Attribut aus dem Objekt lesen
vorher : Mitarbeiter ist vorhanden.
nachher: -
SetLink (obj : TObject);
Auftrag: Link mit externem Objekt herstellen
vorher : obj ist vorhanden.
nachher: Linkobjekt erzeugt; ev. Zugriffe
GetLink : TObject;
Anfrage: nach Linkobjekt
vorher : Linkobjekt ist vorhanden.
nachher: -
RemoveLink
Auftrag: Link mit externem Objekt unterbrechen
vorher : obj ist vorhanden.
nachher: Linkobjekt ist NIL
----------------------------------------------------------------------- *)
IMPLEMENTATION
(* ==================================================================== *)
uses uAuto; // importiert Bezugsklasse
var Link : TAuto; // Linkobjekt; Mitarbeiter kennt Auto
constructor TMitarbeiter.Create;
(* -------------------------------------------------------------------- *)
begin
inherited Create;
Init;
end;
procedure TMitarbeiter.Init;
(* -------------------------------------------------------------------- *)
begin
Name := 'Müller';
Vorname := '';
AutoID := '';
end;
procedure TMitarbeiter.SetName (n: string);
(* -------------------------------------------------------------------- *)
begin
Name := n;
end;
procedure TMitarbeiter.SetVorName (vn: string);
(* -------------------------------------------------------------------- *)
begin
VorName := vn;
end;
function TMitarbeiter.GetName : string;
(* -------------------------------------------------------------------- *)
begin
result := Name;
end;
function TMitarbeiter.GetVorName : string;
(* -------------------------------------------------------------------- *)
begin
result := Vorname;
end;
function TMitarbeiter.GetAutoID: string;
(* -------------------------------------------------------------------- *)
begin
result := AutoID;
end;
(* -------------------------------------------------------------------- *)
(* --------------------- Der Link auf Auto -------------------------- *)
(* -------------------------------------------------------------------- *)
procedure TMitarbeiter.SetLink (obj : TObject);
(* -------------------------------------------------------------------- *)
begin
if obj is TAuto // Typprüfung
then
begin
Link := obj AS TAuto; // Typwandlung
AutoID := Link.GetID; // Zuweisung aus der Assoziation
end;
end;
function TMitarbeiter.GetLink : TObject;
(* -------------------------------------------------------------------- *)
begin
Result := Link;
end;
procedure TMitarbeiter.RemoveLink;
(* -------------------------------------------------------------------- *)
begin
Link := NIL;
end;
END.
|
unit uFenster;
// ***********************************************************************
// K L A S S E : TFensterFrm
// -----------------------------------------------------------------------
// Version : 0.9
// Autor : S. Spolwig, OSZ-Handel I, 10997 Berlin
// Aufgabe : GUI fuer Demo mit bidirektionaler Assoziation
// verschiedener Objekte: Person - Firmenwagen
//
// Welches Auto hat Müller ?
// Wer fährt den BMW ?
// Compiler : DELPHI 6
// Aenderung : V. 0.9 - 30-DEZ-06
// ***********************************************************************
interface
// =======================================================================
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, ExtCtrls, StdCtrls,
uAuto,
uMitarbeiter;
type
TForm1 = class(TForm)
AutoBtn : TButton;
PersonBtn : TButton;
PersonPnl : TPanel;
AutoPnl : TPanel;
procedure FormCreate(Sender: TObject);
procedure PersonBtnClick(Sender: TObject);
procedure AutoBtnClick(Sender: TObject);
end;
var
Form1 : TForm1;
Mitarbeiter : TMitarbeiter;
Auto,
pkw : TAuto;
implementation
// =======================================================================
{$R *.dfm}
procedure TForm1.FormCreate(Sender: TObject);
(* -------------------------------------------------------------------- *)
begin
Mitarbeiter := TMitarbeiter.Create;
Auto := TAuto.Create;
// pkw := TAuto.Create; // geht auch mit mehreren
end;
procedure TForm1.AutoBtnClick(Sender: TObject);
(* -------------------------------------------------------------------- *)
begin
Auto.SetLink(Mitarbeiter); // Auto ----> Mitarbeiter
PersonPnl.Caption := Auto.GetBesitzer; // Auto hat jetzt den Namen
end;
procedure TForm1.PersonBtnClick(Sender: TObject);
(* -------------------------------------------------------------------- *)
begin
Mitarbeiter.SetLink(Auto); // Mitarbeiter ---> Auto
AutoPnl.Caption := Mitarbeiter.GetAutoID;// Mitarbeiter hat jetzt AutoID
end;
END.
|
|