Grundlagen der Informatik I “Programmierung”
Grundlagen der Informatik I “Programmierung” Grundlagen der Informatik I “Programmierung”
Das bedeutet also, daß die Erbenklassen nicht nur die Rechte, sondern auch die Pflichten ihrer Ahnenklassen besitzen: die neue Klasse muß die Kontrakte der ererbten Routinen und ihre Klasseninvarianten einhalten. Dies wird in Eiffel durch die folgenden Regeln sichergestellt. Entwurfsprinzip 3.8.15 (Regel der Elterninvarianten) Die Invarianten aller Eltern einer Klasse gelten für die Klasse selbst. Dies bedeutet, daß die Elterninvarianten automatisch den Invarianten der Erbenklasse hinzugefügt werden (im Sinne von and bzw. ;), ohne daß sie explizit genannt werden müssen. Entwurfsprinzip 3.8.16 (Regel der Zusicherungsredefinition) Ist r eine Routine der Klasse K und s eine Redefinition von r in einem Nachkommen von K, so müssen die Vorbedingungen von s schwächer sein als die von r und die Nachbedingungen stärker. Dies bedeutet, daß die redefinierte Version alle korrekten Eingaben der ursprünglichen Form akzeptieren und alle Nachbedingungen einhalten muß. Man darf also die Anforderungen an redefinierte Versionen verschärfen, aber niemals abschwächen. “Stärker” und “schwächer” gilt im logischen Sinne: aus dem Stärkeren muß das Schwächere durch Implikation logisch folgern. In diesem Sinne ist x>=5 stärker als x>=0, x>=0 and then y=0 und x>=0 stärker als x>=0 or else y
3.8.11 Kaufen oder Erben? Wenn Sie bei einer Klassendeklaration features einer anderen Klasse K benötigen, dann werden Sie vor der Frage stehen, welche Beziehungsart gewählt werden soll: soll K vererben oder Lieferant sein? Die meisten Programmierer, die noch nicht mit der objektorientierten Denkweise vertraut sind, werden im allgemeinen die Vererbung vorziehen, da man hier auf die qualifizierten Aufrufe verzichten kann. Dies bedeutet aber einen Mißbrauch der Vererbung, da hierdurch die durch die das Klassenkonzept geförderte Strukturierung von Softwaresystemen in unabhängige Komponenten wieder verlorengeht. Wer Vererbung nur der leichteren Schreibweise wegen bevorzugt, läuft Gefahr, in Eiffel nach wie vor einen Pascal-Stil zu verwenden. Sinnvoller ist es, sich Gedanken darüber zu machen, welche konzeptionelle Beziehung zwischen den Objekten der realen Welt besteht, die durch die Klassen beschrieben werden. Vererbung drückt aus, daß die Objekte der Erbenklasse auch Objekte der Elternklasse sind, also Attribute der Elternklasse besitzen. Die Kunden- Lieferant Beziehung besagt, daß ein Kundenobjekt das Lieferantenobjekt als Bestandteil hat (und daß möglicherweise mehrere Kundenobjekte dasselbe Lieferantenobjekt haben). So kann zum Beispiel die Klasse BUCH niemals sinnvoll ein Erbe der Klasse PERSON sein, da Bücher nun einmal keine Personen sind. Bei Studenten, Entleihern und Arbeitnehmern sieht das ganz anders aus. Natürlich gibt es Gründe, von dieser Vorgehensweise abzuweichen. Bei der Implementierung der Klasse FIXED LIST (Abbildung 3.38 auf Seite 111) haben wir die Klasse ARRAY geerbt, obwohl Felder eindeutig keine Listen sind. Hier stand die Effizienz und Einfachheit der Schreibweise im Vordergrund. Auch mag die Flexibilität der Redefinition ein Kriterium für Vererbung anstelle des Kaufens sein. Die größere Flexibilität der Vererbung erkauft man sich jedoch durch eine stärkere Bindung an die Elternklasse. Kunden und Lieferanten kommunizieren über sauber definierte Schnittstellen und Verträge. Der Kunde wird von Änderungen der Implementierungen bei den Dienstleistungen nicht beeinflußt. Zwischen Eltern und Nachkommen gibt es keine derartigen Sicherheiten. Eine globale Entscheidung für oder wider die Vererbung gibt es also nicht. Sie sollte im Einzelfall durch eine Bewertung dieser Kriterien getroffen werden. 3.9 Arbeiten mit Eiffel In den bisherigen Unterkapiteln haben wir alle wesentlichen Konzepte für die Strukturierung von Daten angesprochen und an vielen Beispielen illustriert. Damit haben wir alle Komponenten beisammen, die wir für einen systematischen Entwurf der Architektur von Softwaresystemen benötigen. Sie sind in nun der Lage, Klassen zu entwerfen, die Beziehungen der Klassen untereinander durch von Vererbung und Benutzung festzulegen und die notwendigen Leistungen einer Klasse in der Form von Kontrakten genau zu spezifizieren. Auf Programmierkonstrukte für eine systematische Implementierung der einzelnen Leistungen einer Klasse (also Schleifen, Prozeduren, Ausdrücke) werden wir erst im nächsten Kapitel eingehen. Sie sind aber bereits prinzipiell in der Lage, die Dienstleistungen bereits existierender Klassen in ihren eigenen zu benutzen und sich somit das große Spektrum vordefinierter Softwarestücke aus der Eiffel-Bibliothek zunutze zu machen. Bisher haben wir aber erst wenig dazu gesagt, wie man aus dieser losen Ansammlung von Klassen ein ausführbares Eiffel-Softwarepaket erzeugt. Der Grund hierfür ist, daß es einer der Grundgedanken der objektorientierten Programmierung ist, die konkrete Implementierung und die Bestimmung eines “Hauptprogramms” so lange wie möglich zu verschieben und den eigentlichen Entwurf – die Strukturierung von Daten und Dienstleistungen – in den Vordergrund zu stellen. Anders als in der “konventionellen” Programmierung wird ein also Softwaresystem nicht um eine zentrale Hauptfunktion herum entworfen, sondern als Ansammlung unabhängig agierender Einzelbetriebe, die in einer Bibliothek (library) gesammelt werden. Auf diese Art wird die Entwicklung wiederverwendbarer Softwarebausteine betont, die als Implementierungen von Klassen gebaut werden.
- Seite 84 und 85: Entsprechend ihrer beabsichtigten B
- Seite 86 und 87: Klassen sind rein statische Beschre
- Seite 88 und 89: leeren Verweis (d.h. von machen Per
- Seite 90 und 91: haben wie z.B. “(jahr:INTEGER)”
- Seite 92 und 93: und diese erzeugten Objekte mit Ver
- Seite 94 und 95: Bei der Erzeugung von Objekten mitt
- Seite 96 und 97: über den Namen eines Attributs Wer
- Seite 98 und 99: • Die Veränderung und Auswertung
- Seite 100 und 101: 3.5 Copy- und Referenz-Semantik In
- Seite 102 und 103: 3.5.2 expanded: Klassen mit Copy-Se
- Seite 104 und 105: class LIST[X] creation new feature
- Seite 106 und 107: Dieses Problem wird durch das Konze
- Seite 108 und 109: 3.7.1 Zusicherungen Eiffel logische
- Seite 110 und 111: class ARRAY[X] creation make featur
- Seite 112 und 113: class ARRAY[X] creation make featur
- Seite 114 und 115: formulieren und zu überwachen. Eig
- Seite 116 und 117: 3.8.2 Export geerbter Features Norm
- Seite 118 und 119: Ist also p ein Personenobjekt und a
- Seite 120 und 121: Definition 3.8.5 (Konformität) Ein
- Seite 122 und 123: Um die Beschreibung des Typsystems
- Seite 124 und 125: Nachkommenklassen aber folgt entity
- Seite 126 und 127: deferred class LIST[X] feature leng
- Seite 128 und 129: class STUDENT feature universität:
- Seite 130 und 131: Das Problem ist nun, daß beide Elt
- Seite 132 und 133: Prinzipiell wäre es sogar möglich
- Seite 136 und 137: Die eigentliche Montage eines Syste
- Seite 138 und 139: Verständlichkeit der Module: Die L
- Seite 140 und 141: dynamische Semantik: Die dynamische
- Seite 142 und 143: Constant ::= Manifest constant | Id
- Seite 145 und 146: Kapitel 4 Systematische Entwicklung
- Seite 147 und 148: 4.1.2 Grundideen des objektorientie
- Seite 149 und 150: jedoch dringend zu empfehlen, jegli
- Seite 151 und 152: • Ausleihe - Bücher werden nach
- Seite 153 und 154: Der Anwender ist kein echter Klient
- Seite 155 und 156: Es sei an dieser Stelle angemerkt,
- Seite 157 und 158: einen Rechner überprüft werden ka
- Seite 159 und 160: Definition 4.2.3 (Korrektheit von R
- Seite 161 und 162: Programmkonstruktion keine Rolle, d
- Seite 163 und 164: Eine Wertzuweisung entity := Ausdru
- Seite 165 und 166: 4.3.2.1 Die Rolle formaler Paramete
- Seite 167 und 168: Für eine korrekt implementierte Pr
- Seite 169 und 170: { pre} Anweisung1 { p} , { p} Anwei
- Seite 171 und 172: die alle dieselbe Variable x betref
- Seite 173 und 174: 4.3.4.4 Verifikation Die Verifikati
- Seite 175 und 176: Dieser Beweis ist in der folgenden
- Seite 177 und 178: Im allgemeinen ist es sehr schwieri
- Seite 179 und 180: from Init invariant Inv variant Var
- Seite 181 und 182: Programm Zusicherungen Prämissen n
- Seite 183 und 184: entdeckten Fehler stillschweigend h
Das bedeutet also, daß die Erbenklassen nicht nur die Rechte, son<strong>der</strong>n auch die Pflichten ihrer Ahnenklassen<br />
besitzen: die neue Klasse muß die Kontrakte <strong>der</strong> ererbten Routinen und ihre Klasseninvarianten einhalten.<br />
Dies wird in Eiffel durch die folgenden Regeln sichergestellt.<br />
Entwurfsprinzip 3.8.15 (Regel <strong>der</strong> Elterninvarianten)<br />
Die Invarianten aller Eltern einer Klasse gelten für die Klasse selbst.<br />
Dies bedeutet, daß die Elterninvarianten automatisch den Invarianten <strong>der</strong> Erbenklasse hinzugefügt werden<br />
(im Sinne von and bzw. ;), ohne daß sie explizit genannt werden müssen.<br />
Entwurfsprinzip 3.8.16 (Regel <strong>der</strong> Zusicherungsredefinition)<br />
Ist r eine Routine <strong>der</strong> Klasse K und s eine Redefinition von r in einem Nachkommen von K, so müssen<br />
die Vorbedingungen von s schwächer sein als die von r und die Nachbedingungen stärker.<br />
Dies bedeutet, daß die redefinierte Version alle korrekten Eingaben <strong>der</strong> ursprünglichen Form akzeptieren und<br />
alle Nachbedingungen einhalten muß. Man darf also die Anfor<strong>der</strong>ungen an redefinierte Versionen verschärfen,<br />
aber niemals abschwächen. “Stärker” und “schwächer” gilt im logischen Sinne: aus dem Stärkeren muß das<br />
Schwächere durch Implikation logisch folgern. In diesem Sinne ist x>=5 stärker als x>=0, x>=0 and then y=0 und x>=0 stärker als x>=0 or else y