OSZ Handel I
Informatik

Objektorientierte Programmierung (OOP)
Implementierung

S. Spolwig


[Home | Gymn. Oberstufe | Informatik | Unterrichtsmaterialien |OOP]
 

Hinweise zur Implementation in OOP mit DELPHI

  1. Attribute
  2. Methoden
  3. GUI - Fenster
  4. Vererbung
  5. Aggregation
  6. Assoziation
  7. Einfache Nutzung von Serverobjekten

Verschiedene Sprachen - verschiedene Möglichkeiten

Sprachen, die einen objektorientierten Entwurf umzusetzen vermögen, warten mit unterschiedlichen Konzepten (objektbasiert, klassenbasiert, objektorientiert) und Möglichkeiten dafür auf. So wird beispielsweise die Mehrfachvererbung nicht von allen unterstützt. C++ bietet die Möglichkeit, echte Aggregationen durch Variablensemantik zu realisieren und einfache  Aggregationen mit Zeigersemantik. Java hat kein spezielles Konzept dafür; Assoziationen und Aggregationen sehen daher ziemlich gleich aus, was dazu führt, dass zumindest ein namhafter Autor (Balzert, 1999) in einem neuen Lehrbuch auf die Aggregation völlig verzichtet. Delphi erlaubt Referenzen im Datenraum der Unit, also auch außerhalb des Klassenkonstruktes.
Ein objektorientierter Entwurf sollte angemessen in die Programmsprache übersetzt werden. Dabei dient die Spezifikation der Klassen und ihrer Methoden sozusagen als Programmieranweisung, die so präzise formuliert sein muss, dass sie als ‚Lohnauftrag nach Indien‘ geschickt werden kann.

Im folgenden wird auf  spezielle Probleme bei der Implementierung mit DELPHI eingegangen.

1.  Attribute

Die Attribute eines Objekts müssen natürlich veränderbar sein, denn sie stellen den jeweiligen Zustand eines Objekts dar.

TPerson = class (TObject)
           private
             Name,
             Vorname : string[15];
           public
             constructor Create; virtual;
             procedure SetName (n: string); virtual;
             ...
          end;

Die Attribute der Klasse werden i. d. R. als private deklariert. Damit wird erreicht, dass die Attributwerte von außen, also von anderen Objekten, nicht direkt manipuliert werden können. Das dient der Erhöhung der Softwaresicherheit und Qualität. Wünschenswert ist sogar, dass die Attribute gar nicht bekannt bzw. einsehbar wären (Geheimnisprinzip), um jeden verbotenen Zugriff zu verhindern. Der Zugriff auf die Attribute darf daher nur durch die öffentlichen Methoden (public) gestattet sein. Die Methoden schützen damit die Attribute (Datenkapselung). Aus diesem Grunde bilden Attribute und Methoden, d. h. die erlaubten Operationen in einer Klasse, eine Einheit.

2.  Methoden

Jede Klasse verfügt über eine Reihe von Standardmethoden, die immer gleich sind. Sie werden entweder in der Klasse selbst deklariert oder können aus einer Oberklasse geerbt werden. Diese Methoden sind i. d. R. public. Andere, die nur internen Hilfszwecken dienen, werden unter private deklariert.

 

3.  Hinweise zum GUI

Das GUI-Fenster heißt standardmäßig FensterFrm, die Unit uFenster (natürlich nur, wenn es nur ein Fenster gibt).

Im GUI-Fenster finden wir zwei Arten von Methoden: die Ereignisprozeduren, die vom System selbst angelegt und vom Programmierer durch Doppelklick erzeugt werden. Sie sind am Parameter (Sender : TObject ) zu  erkennen. Daneben gibt es häufig Prozeduren, die Teile des Ablaufs der Anwendung betreffen. Aus Gründen der Klarheit der Softwarearchitektur sollte man sie auch getrennt einsetzen.

Ein Beispiel:

unter public deklariert

procedure TFensterFrm.OkBtnClick (Sender: TObject);  // Die Ereignismethode
(* -------------------------------------------- *)
begin
  NeuenPatientenErfassen;
end;

unter private deklariert

procedure TFenster.NeuenPatientenErfassen;          // Private Anwendungsmethode
(* --------------------------------------- *)  
var NeuerPatient : TPatient;

begin
  if NameEdt.Text <> ''
  then
    begin
      NeuerPatient := TPatient.Create;
      Datenaktualisieren (NeuerPatient);
      Patientenliste.Append (NeuerPatient);
   end;
end;

Die Ereignismethode OKBtnClick ruft nur die Anwendungsprozedur auf. Damit wird deutlich, dass GUI-Komponenten nur reine Aufruffunktionen erledigen, also nur Ereignisse anstoßen, eine Nachricht abschicken und sich nicht um interne Abläufe des Datenmodells kümmern.

 

4. Vererbung

Wenn eine Oberklasse ihre Attribute unter private deklariert hat, dann sind sie eben auch nicht für die abgeleiteten Unterklassen sichtbar. Da sie aber natürlich dort gebraucht werden, sieht DELPHI dafür die Anweisung protected vor.

Wenn ein Exemplar einer Unterklasse erzeugt wird, muss man dafür sorgen, dass das Exemplar, das aus der Oberklasse geerbt wird, ebenfalls mit erzeugt wird. (Sonst gibt es einen Absturz.) Für ererbte Teile gibt es die Anweisung inherited.

TPatient = class (TPerson)
            private
              Krankenkasse: string[25];
              ...
            public
             constructor Create; override; // weil der geerbte überschrieben wird
             ...
           end;

....

constructor TPatient.Create;
(* -------------------------------------------------------------------- *)
begin
  inherited Create; // die Person erzeugen, die man erbt
  Init;
end;  

 

5. Aggregation

Für die Aggregation gilt:

  • Komponenten sind vom Aggregat existenzabhängig
    – Erzeugung des Aggregats erzeugt auch die Komponenten
    – Löschung des Aggregats löscht auch die Komponenten

  • Die echte Aggregation (Komposition) übernimmt die dynamische Weiterleitung von Botschaften an die Komponenten  z. B. Aggregat.Zeigen stößt Komponente.Zeigen an.

Deshalb muss in der Create-Methode auch die Komponente Adresse erzeugt werden.

TPerson = class (TObject)
            Adresse : TAdresse;
            Name    : string[15];
            ...
           public
            constructor Create; virtual;
            procedure Init; virtual;
            procedure SetName (n: string); virtual;
           ...
          end;   

constructor TPerson.Create;
(* ----------------------------------------------- *)
begin
  inherited Create;            // erst mal die geerbte Person erzeugen
  Adresse := TAdresse.Create;  // dann die eingefügte Adresse
  Init;
end;

und wenn Person initialisiert wird, muss auch automatisch hierbei die Adresse initialisiert werden.

procedure TPerson.Init;
(* ----------------------------------------------- *)
begin
  Name := '';
  Vorname := '';
  Geburtstag := '';
  Adresse.Init;
end;

 

6. Assoziation

Für die Assoziation gilt:

  • Zwei völlig voneinander unabhängige Objekte (Exemplare), die auf der gleichen Abstraktionsebene stehen, werden unter einem bestimmten Gesichtspunkt mit einander verknüpft.

Beispiel: Dem Kunden wird ein Kundenbetreuer zugeordnet.

Dazu ist es erforderlich, dass in der Klientenklasse

  1. ein Referenzattribut auf das Serverobjekt vereinbart wird
  2. 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
  AdrDatenAktualisieren;       // "" 

  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;

 

7.  Die einfache Nutzung von Serverobjekten

Die Beziehungen zwischen Klassen sollen im Normalfall auch innerhalb der Klasse implementiert sein. DELPHI und auch andere Sprachen verfügen auf Grund ihres Konzepts über einen Datenraum der die gesamte Unit umfasst, also weitergeht als das darin befindliche Klassenkonstrukt.

Insbesondere bei Hauptprogrammen und Objekten mit Steuerungsfunktion (GUI-Fenster) bei denen ein anderes unabhängiges Objekt der Fachklasse nicht als Komponentenobjekt (Attribut) eingebunden werden soll, bietet sich eine einfache Nutzung des Serverobjekts als Vereinbarung an, hier z. B. wenn das Fenster geschlossen wird, der Kunde jedoch weiterleben soll, um in einem neuen anderen Fenster dargestellt zu werden.

                                          

UNIT uSteuerung;
INTERFACE
Uses uKunde;  // import: TKunde

type TSteuerFrm = class(TForm)
                     SteuerPnl : TPanel;                   
                     NeuBtn    : TButton;
                     ...
                  end;

var AktuellerKunde : TKunde;           // Referenz mit Objektnamen vereinbaren

IMPLEMENTATION

procedure TSteuerFrm.OkBtnClick(Sender: TObject);
(* ------------------------------------------------------------------- *)
begin
  DatenAktualisieren(AktuellerKunde);  // Referenzieren und
end;                                   // Daten aus der Eingabemaske uebernehmen

Hier ist die Vereinbarung der Referenzierung im Deklarations-/Interface-Teil vorgenommen. Ebenso könnte die Referenzierung bzw. die Instanzierung im Implementation-Teil gemacht werden, wenn es angebracht scheint. Damit läge dann die Nutzung versteckt im privaten Teil und ist nach außen nicht sichtbar.

In besonderen Situationen könnte das Serverobjekt auch direkt in seiner eigenen Klasse vereinbart sein, erzeugt und exportiert werden. Dann lässt es sich durch einfachen Import nutzen. Jedoch stellt diese Variante den Export einer globalen Variablen dar mit allen damit verbundenen Nachteilen.



 

©    29. März 2007    Siegfried Spolwig

Seitenanfang