Grundlagen der Informatik I “Programmierung”

Grundlagen der Informatik I “Programmierung” Grundlagen der Informatik I “Programmierung”

22.08.2013 Aufrufe

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.

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

Hurra! Ihre Datei wurde hochgeladen und ist bereit für die Veröffentlichung.

Erfolgreich gespeichert!

Leider ist etwas schief gelaufen!