Grundlagen der Informatik I “Programmierung”
Grundlagen der Informatik I “Programmierung”
Grundlagen der Informatik I “Programmierung”
Erfolgreiche ePaper selbst erstellen
Machen Sie aus Ihren PDF Publikationen ein blätterbares Flipbook mit unserer einzigartigen Google optimierten e-Paper Software.
jedoch dringend zu empfehlen, jegliche Seiteneffekte in Funktionen zu vermeiden, da dies schnell zu sehr<br />
unübersichtlichen Programmen führen kann und beson<strong>der</strong>s bei großen Softwaresystemen schnell zu unerwarteten<br />
Auswirkungen führen wird. 4 Will man gleichzeitig einen Wert berechnen und ein Objekt än<strong>der</strong>n, so<br />
sollte man diesen Effekt durch zwei getrennte Routinen – eine Funktion, die den Wert berechnet und eine<br />
Prozedur, die das Objekt än<strong>der</strong>t – auslösen. Es obliegt dann dem Kunden <strong>der</strong> Klasse zu entscheiden, ob er<br />
tatsächlich immer beide Operationen gemeinsam ausführen möchte.<br />
Beim Schreiben von Klassen, die Datenabstraktionen wie Fel<strong>der</strong>, Listen und Matrizen implementieren, ist es<br />
sinnvoll, Objekte nicht einfach als passive Sammlungen von Information anzusehen, son<strong>der</strong>n als “aktive Datenbehälter”<br />
mit einem internen Zustand. So wird z.B. bei Listen in <strong>der</strong> Eiffel-Bibliothek ein Cursor mitgeführt,<br />
<strong>der</strong> auf ein aktuell zu bearbeitendes Listenelement zeigt.<br />
Eine weitere Technik wird durch Vererbung möglich gemacht. Erlaubt ein bestimmter Begriff mehrere sinnvolle<br />
Implementierungen, die je nach Verwendungszweck verschieden effizient sind, dann ist es angebracht, die<br />
Schnittstelle für diesen Begriff als allgemeine Klasse zu deklarieren, und die verschiedenen Implementierungen<br />
in verschiedenen Erbenklassen, die allesamt nur die in <strong>der</strong> Ahnenklasse genannte features exportieren. Meist<br />
ist die allgemeine Klasse eine aufgeschobene Klasse – Beispiele findet man hierzu in <strong>der</strong> Eiffel-Bibliothek zuhauf<br />
– manchmal aber stellt sie auch eine Standardimplementierung <strong>der</strong> vielfältig benötigten Routinen bereit, die<br />
nur in manchen Spezialfällen verän<strong>der</strong>t wird.<br />
Umgekehrt kann man aber auch mehrere Schnittstellen für ein und denselben Begriff anbieten, was durch<br />
die Kombination von Vererbung und Re-Export geerbter features ermöglicht wird. Diese Technik ist sinnvoll,<br />
wenn verschiedenen Kunden verschiedene Sichten auf dasselbe Objekt geboten werden sollen, wie dies z.B. im<br />
Falle <strong>der</strong> Bankkonten (vgl. Seite 99) <strong>der</strong> Fall war.<br />
Eine tiefergehende Diskussion von Klassenschnittstellen findet man in [Meyer, 1988, Kapitel 9]. Hier werden<br />
die obengenannten Prinzipien anhand einiger Beispiele ausführlich erläutert.<br />
4.1.5 Vererbungstechniken<br />
Vererbung ist einer <strong>der</strong> entscheidenden Vorteile des objektorientierten Entwurfs und sollte daher gezielt,<br />
aber richtig eingesetzt werden. Wie bereits in Abschnitt 3.8.11 besprochen, bestimmt vor allem die logische<br />
Beziehung zwischen zwei Klassen, ob besser geerbt o<strong>der</strong> benutzt werden soll. Vererbung sollte genau dann<br />
genutzt werden, wenn Objekte einer Klasse Spezialfälle einer an<strong>der</strong>en Klasse sind. In allen an<strong>der</strong>en Fällen ist<br />
ein Benutzen sinnvoller. Gründe, von dieser Vorgehensweise abzuweichen, haben wir bereits besprochen.<br />
Im allgemeinen wird man eine neu zu definiernde Klasse als Spezialfall (also Erben) einer bereits existierenden<br />
Klasse beschreiben können. Zuweilen steht man aber vor <strong>der</strong> Situation, daß die existierenden Klassen<br />
nicht allgemein genug sind, und man eine Verallgemeinerung erzeugen muß (wie z.B. bei den geometrischen<br />
Objekten, die man erst erfunden hatte, nachdem es schon Punkte, Geraden, Dreiecke und Kreise gab). Bisher<br />
gibt es keine Programmiersprache, die hierzu einen generellen Mechanismus, also ein Gegenstück zur inherit-<br />
Klausel, anbietet. Verallgemeinerungen müssen von Hand durch Editieren des Spezialfalls generiert werden.<br />
Außerdem ist es bei Verallgemeinerungen ausnahmsweise nötig, Eingriffe in eine bereits existierende Klasse<br />
vorzunehmen: in <strong>der</strong> spezielleren Klasse muß eine entsprechende Erbklausel mit Redefinitionsvereinbarungen<br />
ergänzt werden. Diese Än<strong>der</strong>ungen sind jedoch geringfügig und haben keine Effekte auf weitere Klassen.<br />
Redefinition ist eine <strong>der</strong> wichtigsten Techniken bei Vererbung. Sie sollte immer dann eingesetzt werden, wenn<br />
für den Spezialfall <strong>der</strong> Erben eine effizientere Implementierung als die <strong>der</strong> Elternklasse gefunden werden kann.<br />
Ein beson<strong>der</strong>er Fall ist dabei die Redefinition von Funktionen als Attribute. Dies kostet zwar Speicherplatz,<br />
spart aber zuweilen sehr viel Rechenzeit. Der Einsatz dieses Mittels erfor<strong>der</strong>t aber ein sorgfältiges Abwägen.<br />
Bei Redefinition ist immer zu beachten, daß die Semantik <strong>der</strong> redefinierten Routine erhalten bleiben muß.<br />
In Abschnitt 3.8.10 haben wir Mechanismen kennengelernt, die sicherstellen, daß sowohl die Vor- und Nach-<br />
4 Eine legitime Ausnahme von dieser Richtlinie wird in [Meyer, 1988, Kapitel 7.7] besprochen.