Design by Contract in Java
Die Kontrakttypen und was sie bieten
Klasseninvariante
  - flat.inv = derived.inv && base.inv
- soll nur geprüft werden wenn keine self-message vorliegt
    - d.h. wenn die Methode aus einer anderen Methode der Klasse / des Objektes 
      heraus aufgerufen wurde
- wer verursacht eine self-message? Dasselbe Objekt, dieselbe Klasse, derselbe 
      Type (Klasse und alle Erben)
- prüfen der Klasseninvariante der direkten Super-Klasse
    - alternativ können alle Superklassen (bis hin zu java.lang.Object) durchsucht 
      werden
- ein super-call kann nicht generisch eingefügt werden
      - dazu muß geprüft werden, ob super-implementierung der Kontrakt-Methode 
        existiert
- bei Nutzung der Reflection muß der Methodenname sich von dem in der 
        Super-Klasse unterscheiden (sonst wird immer spät gebunden)
- vor und nach dem Methoden-Körper prüfen
- nach dem Konstruktor-Körper prüfen
- vor dem Destruktor-Körper prüfen
- eigentlich bei jedem Schreib-Zugriff auf ein Attribut
- bei inneren (und anonymen ?) Klassen muß die Invariante der outer-Klasse 
    geprüft werden
    - in welcher Reihenfolge?
      - flat.inv = (derived.inv && outer.inv) && base.inv
- flat.inv = (derived.inv && base.inv) && outer.inv
- prüft Attribute
- Unterscheidung in Klassen-Invariante für statische Attribute und Instanz-Invariante 
    für nicht-statische Attribute
    - flat.instance.inv = instance.inv && class.inv
Vorbedingung
  - flat.pre = (derived.pre || base.pre) && flat.inv
- soll bei self-message (s.o.) nicht geprüft werden
- Möglichkeit um Prüfen der geerbten Vorbedingung zu unterdrücken
    - standard ist, die geerbte Vorbedingung mitzuprüfen ("require else")
- geerbte Vorbedingung unterdrücken ("require")
- prüfen der Vorbedingung der Methode in der direkten Super-Klasse
    - da die direkte Super-Klasse die Methode evtl. nur erbt, müssen alle Super-Klassen 
      durchsucht werden
- s.o.
- wird vor dem Methoden-Körper geprüft
- nicht vor dem Konstruktor-Körper
    - es sollte die Möglichkeit bestehen, eine Vorbedingung anzugeben, die nur 
      die Parameter des Konstruktors prüft
- nicht vor dem Destruktor-Körper
    - Zulassen einer Vorbedingung für den Destruktor macht evtl. doch Sinn
- Problem: der Destruktor wird von der JVM implizit aufgerufen, wenn das 
      Objekt vielleicht schon ungültig ist. Deshalb sollte vielleicht auf das 
      Prüfen jeglicher Kontrakte (auch Klassen-Invariante) beim Destruktor verzichtet 
      werden
- prüft die Klassen-/Instanz-Attribute und die Parameter der Methode
- muß auch der Kontrakt einer "geerbten" statischen Klassen-Methode 
    mit derselben Signatur eingehalten werden?
Nachbedingung
  - flat.post = (derived.post && base.post) && flat.inv
- soll bei self-message (s.o.) nicht geprüft werden
- Möglichkeit um Prüfen der geerbten Nachbedingung zu unterdrücken
    - standard ist, die geerbte Nachbedingung mitzuprüfen ("ensure then")
- geerbte Nachbedingung unterdrücken ("ensure")
- prüfen der Nachbedingung der Methode in der direkten Super-Klasse
    - da die direkte Super-Klasse die Methode evtl. nur erbt, müssen alle Super-Klassen 
      durchsucht werden
- s.o.
- wird nach dem Methoden-Körper geprüft
- nicht nach dem Konstruktor-Körper
    - es sollte die Möglochkeit bestehen, die Klassen-/Instanz-Attribute nach 
      Ausführen des Konstruktors mit einer Nachbedingung zu prüfen, weil verschiedene 
      Konstruktoren auch verschiedene Semantik haben können, die über die Klasseninvariante 
      hinausgeht
- nicht nach dem Destruktor-Körper
- prüft die Klassen-/Instanz-Attribute, die Werte der Klassen-/Instanz-Attribute 
    vor Ausführen der Methode, den Rückgabewert
- die Werte der Attribute müssen vor Ausführen des Methoden-Körpers gesichert 
    werden ("deep-copy")
- muß auch der Kontrakt einer "geerbten" statischen Klassen-Methode 
    mit derselben Signatur eingehalten werden?
Struktureller Kontrakt
  - für Klassen
    - "muß die Methode xxx() redefinieren"
- für Methoden
    - "muß super-Aufruf vor dem Methoden-Körper machen"
- "muß super-Aufruf nach dem Methoden-Körper machen"
Schleifeninvariante
  - die Schleifen-Invariante gilt:
    - direkt vor Ausführung der Schleife
- am Anfang des Schleifen-Körpers
- am Ende des Schleifen-Körpers
- direkt nach Ausführung der Schleife
- bei der "for"-Schleife führt das zu dem Problem, daß die Schleifen-Variable 
      erst im Schleifen-Kopf initialisiert wird und schon vorher geprüft werden 
      soll
      - z.B. jede "for"-Schleife zuerst in "while"-Schleife 
        umwandeln?
Schleifenvariante
  - die Schleifen-Variante muß größer 0 sein
- der Wert der Schleifen-Variante muß am Schleifen-Ende kleiner sein als am 
    Schleifen-Anfang
    - oder in jedem Schleifen durchlauf
Check / Assertion
  - einfache Zusicherung im Code
Stichworte
  - die erzeugten Methoden für die Kontrakte sollen "protected" sein
- wie wird Sicherung der Attribute für "old-checks" gemacht werden?
- wie wird der Methoden-Rückgabewert für "result-checks" behandelt?
- die Bedingungen der Kontrakte sollten alle keine Seiteneffekte haben
- wenn eine Klasse "final" ist, weden ihre Methoden / Attribute 
    (?) geinlinet
- "try / finally" benutzen für die Prüfung der Nachbedingung
- wie werden Exceptions im Methoden-Körper behandelt?
- wie werden Exceptions beim Auswerden einer Kontrakt-Bedingung behandelt?
- wie werden generische Klassen / Methoden (siehe GJ) behandelt?
- wie werden abhängige Klassen erkannt / gefunden?
- was ist mit Klassen, die nicht als Source-Code vorliege?
- javadoc-Doclet anbieten
Wichtige syntaktische Strukturen in Java
Klasse
  - Interface
- abstrakte Klasse
- innere Klasse
    - statische innere Klasse
- nicht-statische innere Klasse
- anonyme Klasse
- Klasse ist final
- Name der Klasse
- package-Name
- importierte Klassen / packages
Attribute
  - statische Attribute
- nicht-statische Attribute
- old-Werte speichern
Methoden
  - Rückgabe-Typ
- Name
- Parameter (Typ-Name-Liste)
- Checked / unchecked exceptions
- ist es ein Konstruktor
- ist es ein Destruktor
- die "return"-Statements müssen gefunden werden
- statisch / nicht-statisch
- ist die Methode abstrakt
    - in abstrakter Klasse oder in Interface
- welche Sichtbarkeit hat die Methode
- ist die Methode final
Lokale Variablen
  - ist die Variable initalisiert?
    - das ist wichtig für die Kontrakte Check, Schleifen-Invariante und Schleifen-Variante
Schleifen
  - "for"-Schleife
- "while"-Schleife
- "do" ... "while"-Schleife
Lösung / Implementierung