Grundlagen der Informatik I “Programmierung”
Grundlagen der Informatik I “Programmierung”
Grundlagen der Informatik I “Programmierung”
Sie wollen auch ein ePaper? Erhöhen Sie die Reichweite Ihrer Titel.
YUMPU macht aus Druck-PDFs automatisch weboptimierte ePaper, die Google liebt.
gewährleistet wird. Der Kunde kann sich darauf verlassen, daß die versprochene Leistung – bei Einhaltung<br />
<strong>der</strong> Vorbedingung – auch erfüllt wird.<br />
Im Falle <strong>der</strong> Funktion put bedeutet dies also, daß <strong>der</strong> Lieferant zusagt, das gegebene Element so einzusortieren,<br />
daß es mit item wie<strong>der</strong>gefunden werden kann.<br />
Die Vorteile dieses Vertrages sind gegenseitiger Natur: <strong>der</strong> Kunde bekommt bei jedem Aufruf gewisse Ergebnisse,<br />
<strong>der</strong> Implementierer weiß, daß er zu Beginn von gewissen Voraussetzungen ausgehen darf, die er nicht<br />
mehr prüfen muß. Hierdurch wird <strong>der</strong> Programmierstil erheblich vereinfacht, da die Verantwortlichkeiten auf<br />
Kunden und Lieferanten verteilt werden.<br />
Die Frage, wie genau man Verträge schließen kann, ist hauptsächlich eine Frage des Vertrauens zwischen<br />
Kunden und Lieferanten. Je mehr Vertrauen besteht, um so genauer kann man Verträge vereinbaren und um<br />
so einfacher wird die Implementierung. Das bedeutet aber auch, daß man sich darauf verlassen können muß,<br />
daß sie eingehalten werden. An<strong>der</strong>nfalls wird jegliche Kooperation unmöglich.<br />
Für Sie als zukünftige Softwareentwickler bedeutet dies, daß Sie sich bei <strong>der</strong> Erfüllung Ihrer Aufgaben keinerlei<br />
Ungenauigkeiten erlauben dürfen, son<strong>der</strong>n garantieren können müssen, daß Ihr Modul so arbeitet, wie Sie es<br />
versprochen haben. Aus diesem Grunde müssen Sie in <strong>der</strong> Lage sein, die Korrektheit zu beweisen, also zu<br />
verifizieren – natürlich unter <strong>der</strong> Annahme, daß die Leistungen, die Sie benutzen, ihrerseits korrekt sind. Auf<br />
dieses Thema, die Verifikation von Routinen, werden wir im nächsten Kapitel beson<strong>der</strong>s eingehen.<br />
Ist man sich über die möglichen Benutzer einer Klasse im unklaren, weil die Anwendungsgebiete sehr vielfältig<br />
sind – wie zum Beispiel bei generischen Klassen, dann lohnt es sich, diese durch ein zusätzliches Filtermodul zu<br />
umgeben, welches beim Aufruf einer Routine zunächst alle möglichen Fehler abfängt und die ungeschützte Version<br />
nur dann aufruft, wenn die Vorbedingungen erfüllt sind. Ein solches Modul bietet eine saubere Trennung<br />
zwischen <strong>der</strong> algorithmischen Lösung von Techniken zur Behandlung möglicher Fehleingaben. Ein Beispiel für<br />
ein Filtermodul gibt [Meyer, 1988, Abschnitt 7.3.4].<br />
3.7.3 Klasseninvarianten<br />
Vor und Nachbedingungen beschreiben die semantischen Eigenschaften einzelner Routinen. Darüber hinaus<br />
besteht jedoch auch die Notwendigkeit, globale Eigenschaften von Objekten zu beschreiben, die von allen<br />
Routinen eingehalten werden müßen, wie zum Beipiel die Tatsache, daß die Größe eines Feldes count nie<br />
negativ wird und die Abstand von lower und upper beschreibt. Dies war eine <strong>der</strong> Nachbedingungen <strong>der</strong><br />
Erzeugungsprozedur make in Abbildung 3.23, wurde aber in keiner an<strong>der</strong>en Routine erwähnt, obwohl es<br />
selbstverständlich sein sollte, daß diese Bedingung immer erhalten bleibt.<br />
Man könnte diese Bedingung nun in <strong>der</strong> Nachbedingung je<strong>der</strong> einzelnen Routine zusätzlich erwähnen, aber dies<br />
entspricht nicht dem Gedanken, daß sie immer gelten soll, also eine Invariante (unverän<strong>der</strong>liche Eigenschaft)<br />
<strong>der</strong> Klasse selbst ist. Daher bietet Eiffel die Möglichkeit an, Klasseninvarianten als solche zu formulieren.<br />
Dies geschieht durch Klauseln, die mit dem Schlüsselwort invariant eingeleitet werden, und am Ende <strong>der</strong><br />
Klassendeklaration genannt werden. Abbildung 3.25 zeigt die Deklaration von ARRAY mit Klasseninvarianten.<br />
Klasseninvarianten sind also Zusicherungen, die allgemeine semantische Bedingungen formulieren, welche – im<br />
Gegensatz zu den Vor- und Nachbedingungen einzelner Routinen – für jedes Klassenelement als ganzes gelten.<br />
Sie können neben den Beziehungen zwischen Attributen auch semantische Beziehungen zwischen Funktionen<br />
o<strong>der</strong> zwischen Funktionen und Attributen ausdrücken. Nur Prozeduren sind in Zusicherungen nicht erlaubt,<br />
da sie bei einer Überprüfung <strong>der</strong> Zusicherung Objekte verän<strong>der</strong>n würden.<br />
Klasseninvarianten müssen natürlich nur in stabilen Zuständen, also vor und nach dem Aufruf einer von<br />
außen verwendbaren Routine, nicht aber während ihrer Abarbeitung gelten. “Interne” Routinen, also solche,<br />
die nicht von außen aufgerufen werden können, sind daher von <strong>der</strong> Überprüfung ausgenommen, da sie nach<br />
außen ohne direkten Effekt sind.