Programmierkurs: Delphi: Programmierstil

Aus Wikibooks
Zur Navigation springen Zur Suche springen

Der (richtige) Programmierstil[Bearbeiten]

Wie schon am Anfang des Buches beschrieben, unterscheidet Pascal nicht zwischen Groß- und Kleinschreibung. Ebenso ist es dem Compiler egal, wie viele Leerzeichen oder Tabulatoren man zwischen die einzelnen Schlüsselwörter, Rechenzeichen oder Ähnliches setzt, genauso wie man ein Programm auch komplett in einer Zeile unterbringen könnte.

Der Programmtext sollte jedoch sauber strukturiert sein und man sollte sich dabei an einige Regeln halten. Dies dient dazu, den Code später einfacher warten zu können. Falls man im Team arbeitet ist so auch sichergestellt, dass sich andere im Code schneller zurecht finden.

Hierfür haben sich einige Regeln eingebürgert, die nach Möglichkeit von jedem angewandt werden sollten.

Allgemeine Regeln[Bearbeiten]

Einrückung[Bearbeiten]

Um bestimmte Zusammenhänge, wie zum Beispiel Anweisungsblöcke, im Quelltext kenntlich zu machen, rückt man die Zeilen ein. Dabei sollten keine Tabulatoren sondern Leerzeichen verwendet werden, damit der Text auf jedem Rechner gleich aussieht. Standard sind 2 Leerzeichen je Ebene.

Seitenrand[Bearbeiten]

Gelegentlich wird man auch mal einen Programmtext ausdrucken wollen. Hierfür ist der rechte Seitenrand auf 80 einzustellen. Erkennbar ist dies über eine durchgezogene Linie im Editor. Wenn möglich, sollte diese Linie nicht überschrieben werden.

Kommentare[Bearbeiten]

Für Kommentare sollte man hauptsächlich die geschweiften Klammern { } verwenden. Den anderen Kommentarblock (* *) sollte man nur verwenden, um Programmabschnitte vorübergehend aus dem Programm auszuschließen (auszukommentieren). Kommentare mittels // bitte ausschließlich für einzeilige Kommentare verwenden.

Compilerdirektiven[Bearbeiten]

Direktiven werden immer in geschweifte Klammern gesetzt, wobei die Compileranweisung in Großbuchstaben geschrieben wird. Beim Einrücken gelten die gleichen Regeln wie oben.

Anweisungsblöcke[Bearbeiten]

Bei Anweisungsblöcken zwischen begin und end stehen diese beiden Schlüsselwörter jeweils auf einer eigenen Zeile. Anweisungen wie if ... then begin oder while ... do begin sollten vermieden werden. begin und end stehen immer auf der gleichen Ebene wie die zugehörige If- oder Schleifenabfrage:

if ... then
begin
  ...
end;

Klammern[Bearbeiten]

Nach einer geöffneten Klammer und vor der geschlossenen Klammer stehen keine Leerzeichen. Bei Klammern zur Parameterübergabe an Funktionen, Prozeduren und Methoden kein Leerzeichen zwischen dem Namen und der geöffneten Klammer verwenden. Dies gilt auch für die eckigen Klammer zur Angabe eines Index. Klammern nur angeben, wenn diese auch notwendig sind!

Writeln ( txt );    // falsch
Writeln (txt);      // falsch
Writeln( txt );     // falsch
Writeln(txt);       // die einzig richtige Variante

x := a * ( b + c ); // falsch
x := a * (b + c);   // richtig

x := (a * b);       // falsch, unnötige Klammer
x := a * b;         // richtig

i[1] := x;          // richtig

Interpunktion[Bearbeiten]

Semikola sowie der Punkt hinter dem letzten end stehen ohne Leerzeichen direkt hinter dem letzten Zeichen der Anweisung. Sie schließen die Zeile ab, danach folgt ein Zeilenumbruch, sprich: jede Anweisung steht auf einer eigenen Zeile. Ausnahme: Direktiven hinter der Deklaration von Funktionen.

Writeln('Zeilenende hinter Semikolon!');
Writeln('Nächste Anweisung.');

aber:

function Stellenanzahl(Zahl: Integer): Integer; forward;
procedure HilfeAusgeben; overload;
procedure HilfeAusgeben(Text: string); overload;

Vor Kommata zur Trennung von Parametern oder in anderen Auflistungen steht kein Leerzeichen, aber dahinter. Dasselbe gilt für Doppelpunkte bei der Deklaration von Variablen oder Parametern.

var
  x: Integer;
  a: array[0..2, 0..2] of Byte;
{ ... }
x := Pos(chr, zeichenkette);
a[0, 1] := 32;

Rechenoperatoren werden immer von Leerzeichen umschlossen.

Operatoren[Bearbeiten]

Mit Ausnahme der unären Operatoren @ und ^ stehen vor und nach Operatoren immer Leerzeichen. Hierzu zählt auch der Zuweisungsoperator :=.

z := x+y;        // falsch
z := x + y;      // richtig

a := @Funktion;  // richtig
p := Zeiger^;    // richtig

Reservierte Wörter[Bearbeiten]

Diese Wörter gehören fest zum Sprachumfang von Pascal/Delphi. Sie werden unter neueren Delphi-Versionen standardmäßig dunkelblau und fett hervorgehoben, unter Lazarus und älteren Delphi-Versionen schwarz und fett. Diese Wörter werden immer kleingeschrieben.

Beispiele:

program
const

aber auch:

string

Routinen und Methoden[Bearbeiten]

Namensvergabe[Bearbeiten]

Namen von Prozeduren und Funktionen (=Routinen) sowie Methoden sollten immer großgeschrieben sein. Falls sich der Name aus mehreren Wörtern zusammensetzt, beginnt jedes neue Wort ebenso mit einem Großbuchstaben. Der Name sollte so sinnvoll gewählt sein, dass man daraus bereits die Aufgabe der Routine ableiten kann. Um dies zu erreichen, empfiehlt es sich, ein entsprechendes Verb im Namen unterzubringen. Bei Routinen, die Werte von Variablen ändern, wird das Wort Set (oder deutsch Setze) davorgeschrieben. Bei Routinen, die Werte auslesen, steht das Wort Get bzw. Hole davor.

procedure Hilfe;          // falsch, Aufgabe nicht ganz eindeutig
procedure HilfeAnzeigen;  // richtig
procedure ausgabedateispeichernundschliessen;  // falsch, nur Kleinbuchstaben
procedure AusgabedateiSpeichernUndSchliessen;  // richtig
procedure SetzeTextfarbe;
function HolePersonalnr: Integer;

Parameter[Bearbeiten]

Die Bezeichnung von Parametern sollte ebenfalls so gewählt werden, dass man auf den ersten Blick den Zweck erkennen kann. Der Name wird auch groß geschrieben. Nach Möglichkeit sollte ihm ein großes A vorangestellt werden, um einen Parameter von Variablen und Klasseneigenschaften unterscheiden zu können.

Bei der Reihenfolge sollten die allgemeineren Parameter weiter links stehen, die spezielleren rechts, z.B. Ort, Straße, Hausnummer. Zusammengehörige Parameter sollten dabei nebeneinander stehen. Genauso sollten, wenn möglich, Parameter gleichen Typs zusammengefasst werden:

procedure ZeichnePunkt(R, F: Integer; L: TColor);                // falsch, Zweck der Parameter nicht erkennbar
procedure ZeichnePunkt(Y: Integer; AFarbe: TColor; X: Integer);  // falsch, unsinnige Reihenfolge
procedure ZeichnePunkt(X, Y: Integer; AFarbe: TColor);           // richtig

Parameter vom Typ Record, Array oder ShortString sollten als konstante Parameter deklariert werden, falls deren Wert in der Routine nicht geändert wird. Dies erhöht die Geschwindigkeit des Programms, da der Inhalt der Parameter nicht lokal kopiert wird. Bei anderen Parametertypen ist dies ebenfalls möglich, bringt aber keinen Geschwindigkeitsvorteil.

Variablen[Bearbeiten]

Variablen sollte ein Name gegeben werden, der ihren Zweck erkenntlich macht. Sie sollten ebenfalls grundsätzlich großgeschrieben werden. Bei Zählern und Indizes besteht der Name meist nur aus einem Buchstaben: z.B. I, J, K. Boolische Variablen sollten einen Namen haben, bei dem die Bedeutung der Werte True und False sofort klar ist.

var
  Wort: Boolean;           // falsch, Bedeutung von True und False nicht zu erkennen
  WortGeaendert: Boolean;  // richtig

Variablen werden jede auf einer eigenen Zeile deklariert (wie im Beispiel oben). Es sollten nicht mehrere Variablen gleichen Typs zusammengefasst werden.

Sie sollten es dringend vermeiden, globale Variablen zu benutzen. Falls Sie Variablen global benutzen müssen, dann schränken Sie dies so weit wie möglich ein. Deklarieren Sie z.B. eine solche Variable im Implementation-Teil einer Unit und nicht im Interface-Teil.

Typen[Bearbeiten]

Typen sollten so geschrieben werden, wie sie deklariert wurden. string ist z.B. ein reserviertes Wort und wird demnach auch als Typ klein geschrieben. Viele Typen aus der Windows-Schnittstelle sind vollständig in Großbuchstaben deklariert und sollten dann auch dementsprechend verwendet werden, z.B. HWND oder WPARAM. Andere von Delphi mitgelieferte Typen beginnen mit einem Großbuchstaben, z.B. Integer oder Char.

Typen, die Sie selbst anlegen, stellen Sie bitte ein großes T voran, bei Zeigertypen ein großes P. Ansonsten gilt die gleiche Schreibweise wie bei Variablen. Auch hier achten Sie bitte darauf, dass der Typ einen zweckmäßigen Namen erhält.

Gleitkommazahlen[Bearbeiten]

Benutzen Sie bitte hauptsächlich den Typ Double, hierfür sind alle Prozessoren ausgelegt. Real existiert nur noch um mit älteren Programmen kompatibel zu sein, in Delphi ist Real derzeit gleichbedeutend mit Double. Single sollten Sie nur verwenden, wenn Ihnen der Speicherbedarf der entsprechenden Variable wichtig ist. Extended ist ein Sonderformat von Intel und könnte beim Datenaustausch zwischen verschiedenen Rechnern zu Problemen führen. Sie sollten Extended daher nur verwenden, wenn Sie auf die erweiterte Genauigkeit angewiesen sind und Werte dieses Typs möglichst nicht in Dateien speichern, die für einen Datenaustausch verwendet werden.

Aufzählungen[Bearbeiten]

Geben Sie bitte Aufzählungen einen Namen, der dem Zweck des Typs entspricht. Die Bezeichner der Positionen benennen Sie so, dass die ersten zwei oder drei Buchstaben (kleingeschrieben) den Typ der Aufzählung wiedergeben:

TMitarbeiterArt = (maAngestellter, maLeitenderAngestellter, maVorstand);

Eine Variable vom Typ Aufzählung wird genau wie der Typ benannt, lediglich das führende T lässt man weg. Benötigt man mehrere Variablen eines Typs, kann man diese entweder durchnummerieren oder erweitert den Namen um einen passenden Begriff.

Varianten[Bearbeiten]

Verwenden Sie Varianten so sparsam wie möglich. Varianten sind nicht die bevorzugte Art, Daten unbekannten Typs zu konvertieren. Benutzen Sie stattdessen Zeiger und Typumwandlungen. Bei COM- und Datenbankapplikationen werden Sie vermutlich nicht umhin kommen, Varianten zu verwenden. Sie sollten in diesem Falle den Typ OleVariant nur bei COM-Anwendungen (z.B. ActiveX-Komponenten) verwenden und ansonsten den Typ Variant.

Arrays und Records[Bearbeiten]

Wie auch schon zuvor, sollte auch der Name von Arrays und Records sinnvoll zu deren Verwendungszweck vergeben werden. Auch vor diese Typbezeichner wird ein T gesetzt (bzw. P bei Zeigern). Ähnlich wie bei Aufzählungen, sollten Sie auch bei Variablen eines Array- bzw. Record-Typs den gleichen Namen nur ohne führendes T verwenden, falls möglich.

Anweisungen[Bearbeiten]

If-Anweisungen[Bearbeiten]

Bei Verzweigungen mit if sollten die wahrscheinlichsten Anweisungen nach dem then stehen, die seltender eintretenden Bedingungen nach dem else.

Wenn irgend möglich, sollten Sie vermeiden, mehrere If-Abfragen nacheinander zu schreiben. Verwenden Sie statt dessen die Verzweigung mittels case. Ebenso vermeiden Sie es bitte, If-Abfragen in mehr als fünf Ebenen zu verschachteln. Klammern bitte nur verwenden, wenn diese auch benötigt werden!

In Delphi gibt es die Möglichkeit, Bedingungsabfragen bereits nach der ersten falschen Bedingung abbrechen zu lassen. Dies spart in der Ausführung der Anwendung etwas an Zeit. Um diesen Zeitvorteil weiter auszubauen, sollte man die Abfragen sortieren. Dabei kann man von links nach rechts die Abfragen tätigen, die am wahrscheinlichsten auf "false" lauten werden. Eine weitere Möglichkeit ist, die am schnellsten zu berechnenden Bedingungen am weitesten nach links zu stellen.

Für gewöhnlich stehen die Bedingungen nebeneinander. Sollten dies zu viele werden, können sie auch untereinander geschrieben werden. Dabei sind sie linksbündig zu formatieren:

if Bedingung1 and Bedingung2 and Bedingung3 then
  ...

if Bedingung1 and
   Bedingung2 and
   Bedingung3 then
  ...

Wenn sich die auszuführende Anweisung nach dem then oder else über mehrere Zeilen erstreckt (zum Beispiel, weil sie am Zeilenende umgebrochen werden muss, oder weil Kommentare vorangesetzt werden), bitte alles zwischen begin und end einfassen:

{ Falsch }
if x = 1 then
  // Hier passiert was
  Writeln(x);

{ Richtig }
if x = 1 then
begin
  // Hier passiert was
  Writeln(x);
end;

{ Falsch }
if x = 1 then
  Writeln('Dies ist ein sehr langer Text, der ' +
          'am Zeilenende umgebrochen wurde, ' +
          'damit er auf Ausdrucken immer noch ' +
          'lesbar erscheint.');

{ Richtig }
if x = 1 then
begin
  Writeln('Dies ist ein sehr langer Text, der ' +
          'am Zeilenende umgebrochen wurde, ' +
          'damit er auf Ausdrucken immer noch ' +
          'lesbar erscheint.');
end;

Das Schlüsselwort else sollte immer den gleichen Einzug erhalten wie if.

Case-Anweisungen[Bearbeiten]

Die einzelnen Unterscheidungsmöglichkeiten einer Case-Verzweigung sollten numerisch, alphabetisch oder (bei anderen Aufzählungstypen) in der Reihenfolge ihrer Deklaration abgefragt werden.

Die Anweisungen, die den Abfragen folgen, sollten möglichst kurz und einfach gehalten werden, da der Programmtext sonst schnell unübersichtlich wird. Empfehlenswert sind vier bis fünf Zeilen, diese sollten immer zwischen begin und end stehen (auch bei einzelnen Zeilen). Größere Anweisungsfolgen am besten in eigene Routinen auslagern.

Den Else-Abschnitt sollten Sie nur verwenden, wenn Sie ein gültiges Default-Verhalten festlegen können.

Alle Abschnitte einer Case-Verzweigung sollen eingerückt werden. Das else steht auf der gleichen Höhe wie das case. Bei größeren Case-Blöcken, die einen Else-Abschnitt enthalten, sollte man das else zum besseren Überblick mit einem Kommentar versehen, um es eindeutig dem Case-Abschnitt zuzuordnen.

case Wert of
  Bedingung:
    begin
      ...
    end;
else  { case }
  ...
end;

While-, For- und Repeat-Schleifen[Bearbeiten]

Wenn Sie eine Schleife verlassen wollen, vermeiden Sie bitte die Anweisung Exit. Schleifen sollten immer über die Prüfbedingung beendet werden. Alle Variablen, die Sie innerhalb einer Schleife verwenden, sollten Sie direkt davor initialisieren und (wenn nötig) direkt anschließend wieder bereinigen. So stellt man sicher, dass man nichts vergisst.

With-Anweisungen[Bearbeiten]

With-Anweisungen sollten Sie nur sehr selten einsetzen, wenn Sie zum Beispiel mit einem sehr umfangreichen Record arbeiten. Ansonsten verwenden Sie bitte die Form Variable.Element in Ihrem Programm. Obwohl es möglich ist, verwenden Sie bitte nie mehrere Records in einer With-Anweisung, wie z.B. with Record1, Record2 do

Fehlerbehandlung[Bearbeiten]

Verwenden Sie die Funktion der Fehlerbehandlung so sparsam wie möglich. Prüfen Sie stattdessen die benötigten Daten vor der Verwendung auf Korrektheit.

Die Fehlerbehandlung sollte immer dann eingesetzt werden, wenn Speicherbereiche zugewiesen werden, um diese nach dem Auftreten einer Exception sauber wieder freizugeben.

Zur Fehlerbehandlung verwendet man gewöhnlich try...finally. Bei Speicherzuweisungen sollte man recht großzügig mit der Anzahl der Blöcke sein und nach jeder Zuweisung einen neuen Block beginnen.

Klasse1 := TKlasse1.Create;
Klasse2 := TKlasse2.Create;
try
  { ... }
finally
  Klasse1.Free;
  Klasse2.Free;
end;

besser:

Klasse1 := TKlasse1.Create;
try
  Klasse2 := TKlasse2.Create;
  try
    { ... }
  finally
    Klasse2.Free;
  end;
finally
  Klasse1.Free;
end;

Da try...finally den Fehler nicht abschließend behandelt sondern erneut auslöst, sollte man diesen Block in try...except verschachteln oder ausschließlich diese Art der Fehlerbehandlung verwenden.

Klassen[Bearbeiten]

Der Name einer Klasse beginnt immer mit einem T, da es sich hierbei um einen Typ handelt. Der Rest des Namens sollte dem Zweck der Klasse entsprechen. Bei mehreren Wörtern im Namen beginnt jedes Wort mit einem Großbuchstaben. Die dazugehörige Variable trägt den gleichen Namen wie die Klasse, nur ohne führendes T. Falls Sie weitere Variablen einer Klasse benötigen, können Sie diese nummerieren oder Sie verwenden weitere zusätzliche Begriffe im Namen der Variablen.

Felder[Bearbeiten]

Felder werden wie Variablen benannt, sollten jedoch mit einem F beginnen. Damit sind sie eindeutig von anderen Variablen zu unterscheiden. Weiterhin sollten Felder immer als private deklariert werden. Falls Sie die Daten von außerhalb der Klasse ändern möchten, erstellen Sie eine Methode oder Eigenschaft für diesen Zweck.

Ebenso wie Variablen sollten Felder jedes auf seiner eigenen Zeile deklariert werden. Bitte keine Felder gleichen Typs zusammenfassen.

Methoden[Bearbeiten]

Methoden benennen Sie wie Prozeduren und Funktionen.

Deklarieren Sie eine Methode als static, wenn diese in Nachkommenklassen nicht überschrieben werden sollen. Im Gegensatz dazu deklarieren Sie eine Methode als virtual, wenn sie ausdrücklich überschrieben werden soll. Verwenden Sie hierfür nicht dynamic! Deklarieren Sie eine Methode nur in Basisklassen als abstract, die niemals direkt verwendet werden.

Methoden zum Zugriff auf Eigenschaften werden immer als private oder protected deklariert. Die Methoden zum Lesen der Eigenschaften beginnen mit Get (bzw. deutsch Hole), die Methoden zum Schreiben der Eigenschaft mit Set (bzw. Setze). Der Parameter der Methode zum Schreiben des Wertes heißt Value.

Eigenschaften[Bearbeiten]

Eigenschaften, die auf private Felder zugreifen, werden wie das Feld benannt, nur ohne führendes F. Verwenden Sie für den Namen bitte nur Substantive, keine Verben. Eigenschaften mit Index sollten dabei in der Mehrzahl stehen, sonst Einzahl:

property Farbe: TColor read FFarbe write FFarbe;
property Adressen[1..10]: TAdresse read HoleAdresse write SetzeAdresse;

Eigenschaften, die im Objektinspektor von Delphi angezeigt werden sollen, deklarieren Sie als published, sonst als public.


Quelle: frei nach „Delphi 4 Developer's Guide Coding Standards Document“


  Inhaltsverzeichnis