Step 01 - OOP und was nun noch gesagt werden muss (Teil 1/3)

 

1. Eckstein, Echstein, alles muss versteckt sein ;)

...oder: Das Geheimnisprinzip

 
Im Kurs Anfängerwissen haben wir angeschnitten, wo man Variablen deklarieren kann. Was wir hier nicht so genau dabei betrachtet haben ist, was die Gründe dafür sind. Wieso soll man es so machen und nicht anders? Zum Beispiel kann man ja ein Array einfach global deklarieren. Also direkt in var im Interface-Abschnitt, direkt unter der Zeile, in der Form1 deklariert ist. Aber was bringt es uns, wenn wir in einer anderen Unit auch ein Array mit dem gleichen Namen, aber für einen anderen Zweck nutzen wollen?
Und hier kommt die wichtigste Regel ins Spiel, wenn es um die Deklaration von Variablen/Feldern/Zugriffsgedöns geht:
Deklariere so global wie nötig, so lokal wie möglich!
 
Beachte zudem:
  • alle Variablen sollten möglichst aussagekräftig bezeichnet werden. (Lesbarkeit)
  • hat man nur globale Variablen, schafft dies Unübersichtlichkeit - wo wird was wann benutzt? (Wartbarkeit)
  • globale Variablen oder Objekte können von überall benutzt werden. In der OOP benutzt man hierfür jedoch s.g. "Properties" in den Objekten. Damit kann eine Eigenschafft eines Objekts als "Globale Variable" benutzt werden, wenn auf das Objekt zugegriffen wird. Näheres folgt noch.
  • globale Variablen verbrauchen immer den Speicher, den sie verbrauchen; lokale nur dann, wenn sie direkt gebraucht werden. (Speichereffizienz, sollte auch heutzutage bedacht werden!)
 
Beispiel für Deklaration und Verwendung von Properties:
type
  TAuto = class(TForm)
  private
    fColor     : TColor;
    fHeight    : Integer;
    fWidth     : Integer;
    fMaxWeight : Integer;
  public
    property Color             : TColor  read fColor     write fColor;
    property Height            : Integer read fHeight    write fHeight;
    property Width             : Integer read fWidth     write fWidth;
    property WeightLoadMaximum : Integer read fMaxWeight;

    constructor Create( AColor:TColor; AHeight, AWidth, AMaxWeight: Integer);
  end;
 
Das Schlüsselwort "write"/"read" sorgt dafür, dass wir auf die Eigenschafft schreibend/lesend zugreifen können.
 
Ist MyCar eine erstellte Instanz unseres Objektes...
  // so wäre das möglich:
  MyCar.Color  := clBlue;
  MyCar.Height := 1.3;
  MyCar.Width  := 1.6;
  MyCar.Length := 2.4;
  
  // das jedoch nicht:
  MyCar.WeightMaximum := 10000;
Grund hierfür ist einfach, dass wir keine Schreibberechtigung für die Eigenschafft WeightMaximum erstellt haben.
Ok, eigentlich geht es hierbei nicht darum es einfach zu "verstecken", aber wir können hier durch die Verminderung der Zugriffsmöglichkeit auch noch Logik kapseln. Was ist, wenn bei jedem schreibenden Zugriff ein bestimmter Sensor-Wert im Auto geprüft sein muss? Z.B. beim selbstfahrenden Auto wollen wir, dass es nur Gas gibt, wenn der Sensor für den Frontabstand genügend "Luft" für noch mehr Geschwindigkeit hat. Das ganze wäre zwar bestimmt ein Tick komplizierter im Detail, lässt sich aber durchaus auf so "kleine" Logik-Bausteine herunterbrechen.
 

2. Methoden - Sichtbarkeit und Zugreifbarkeit "kompakt"

Wie wir es aus dem Anfängerbereich bereits kennengelernt haben, gibt es verschiedene Möglichkeiten beim deklarieren von Parametern. Zur kurzen Wiederholung und Vertiefung einmal folgende Methode als Beispiel:
procedure initGame( APlayerName: String; var ALevel: Integer;
    const AGameType: Integer; APlayerList: TStrings);
 
Beschreibung der Parameter:
Parameter Beschreibung
APlayerName: String; Dies ist eine ganz normale Definition eines Parameters; Hierbei werden die Werte der Variable übergeben. d.h. wenn in der Methode initGame die Variable APlayerName verändert wurde so ist die ursprüngliche Variable dennoch unverändert.
=> Call by Value
var ALevel: Integer Hierbei wird auf jeden Fall eine Variable verlangt, da hierbei nur der Zeiger auf die Adresse, in der sich der Wert befindet, übertragen wird.
=> Call by Reference
const AGameType: Integer; Hierbei kann alles mögliche übergeben werden. Der Clue bei der Geschichte ist, dass weder der Wert noch die Referenz verändert werden kann.
=> geschützter Parameter
APlayerList: TStrings Bei Parametern, die nicht grundsätzliche Datentypen sondern eigene Klassen sind, wird stets die Referenz, also "der Zeiger" übertragen.
 
Somit dürfte der OOP-Bereich zum Thema der Sichtbarkeit erstmals erledigt sein :)