Objektorientierte Programmiersprachen am Beispiel Eiffel - Software ...
Objektorientierte Programmiersprachen am Beispiel Eiffel - Software ...
Objektorientierte Programmiersprachen am Beispiel Eiffel - Software ...
Erfolgreiche ePaper selbst erstellen
Machen Sie aus Ihren PDF Publikationen ein blätterbares Flipbook mit unserer einzigartigen Google optimierten e-Paper Software.
<strong>Objektorientierte</strong><br />
<strong>Progr<strong>am</strong>miersprachen</strong><br />
<strong>am</strong> <strong>Beispiel</strong> <strong>Eiffel</strong><br />
Referat im Rahmen des Seminars<br />
„<strong>Progr<strong>am</strong>miersprachen</strong>“<br />
24. Mai 2004<br />
Jan Griesel<br />
Prof. Dr. Claudia Leopold, Dipl.-Inf. Michael Süß<br />
Fachgruppe <strong>Progr<strong>am</strong>miersprachen</strong>/ -methodik<br />
Fachbereich Elektrotechnik / Informatik<br />
Universität Kassel
<strong>Objektorientierte</strong> <strong>Progr<strong>am</strong>miersprachen</strong> <strong>am</strong> <strong>Beispiel</strong> <strong>Eiffel</strong> - 1 -<br />
Inhalt<br />
Inhalt ..............................................................................................1<br />
1. Einführung <strong>Eiffel</strong> .......................................................................2<br />
2. <strong>Objektorientierte</strong> Progr<strong>am</strong>mierung..............................................3<br />
2.1 Einführung ............................................................................3<br />
2.2 Klassen und Objekte ..............................................................3<br />
2.3 Typen und Verweise ...............................................................4<br />
2.4 Generalisierung, Vererbung.....................................................5<br />
2.5 Datenkapselung.....................................................................5<br />
2.6 Redefinition...........................................................................7<br />
2.7 Polymorphismus, dyn<strong>am</strong>isches Binden......................................8<br />
2.8 Abstrakte Klassen ..................................................................9<br />
2.9 Par<strong>am</strong>etrisierbare Klassen.......................................................9<br />
2.10 Multiple Vererbung ............................................................ 10<br />
2.11 Wiederholtes Erben ........................................................... 10<br />
2.12 Zusicherung, Design-by-Contract ........................................ 11<br />
3.<br />
4.<br />
5.<br />
6.<br />
Weitere Besonderheiten........................................................... 12<br />
<strong>Eiffel</strong><br />
Einsatzgebiete........................................................................ 12<br />
Fazit ..................................................................................... 12<br />
Literatur ................................................................................ 13
<strong>Objektorientierte</strong> <strong>Progr<strong>am</strong>miersprachen</strong> <strong>am</strong> <strong>Beispiel</strong> <strong>Eiffel</strong> - 2 -<br />
1. Einführung <strong>Eiffel</strong><br />
<strong>Eiffel</strong> ist eine reine objektorientierte Progr<strong>am</strong>miersprache, welche seit<br />
1985 von dem französischen Informatiker Bertrand Meyer und seiner<br />
Firma Interactive <strong>Software</strong> Engeneering Inc. (Goleta, Kalifornien) als<br />
Alternative zu C++ entworfen wurde. Seinen N<strong>am</strong>en verdankt <strong>Eiffel</strong> dem<br />
in der zweiten Hälfte des 19. Jahrhunderts bekannt gewordenen Ingenieur<br />
Gustave <strong>Eiffel</strong>, Erbauer des <strong>Eiffel</strong>turms (erbaut 1887-1889) in Paris. Der<br />
N<strong>am</strong>e <strong>Eiffel</strong> stellt den Anspruch in den Vordergrund, eine Sprache zu<br />
geschaffen, mit der <strong>Software</strong>entwicklung gemäß den Standards des<br />
Ingenieurwesens ermöglicht wird.<br />
Bei <strong>Eiffel</strong> handelt es sich im Unterschied zu C++ um einen vollständig<br />
neuen Entwurf, der lediglich in Anlehnung an ältere Sprachen (Ada 1 und<br />
der ALGOL-Sprachf<strong>am</strong>ilie 2 ) aufgebaut wurde.<br />
Ziel der Entwicklung von <strong>Eiffel</strong> ist es, eine Sprache zu erschaffen, mit der<br />
es möglich ist umfangreiche <strong>Software</strong>projekte aus zuverlässigen, wieder<br />
verwendbaren und leicht wartbaren Modulen zu konstruieren. Um dies zu<br />
erreichen, wurden riskante Möglichkeiten, wie manuelle<br />
Speicherverwaltung, globale Variablen, GOTOs, etc. komplett<br />
ausgeschlossen.<br />
Besonderheiten von <strong>Eiffel</strong> sind u.a. Zusicherung (Desing-by-Contract) und<br />
Multiple Vererbung.<br />
Die Sprachdefinition von <strong>Eiffel</strong> ist Public-Domain und steht unter der<br />
Kontrolle von Nonprofit International Consortium for <strong>Eiffel</strong> (NICE) 3 ,<br />
welches sich das Recht vorbehält, jedes Entwicklerwerkzeug bezüglich der<br />
Konformität zum Standard zu validieren.<br />
Es existieren wenige kommerzielle <strong>Eiffel</strong>-Entwicklungsumgebungen und<br />
mit Smart<strong>Eiffel</strong> 4 zumindest ein OpenSource-Compiler. Die Sprache konnte<br />
bisher nicht an den Verbreitungsgrad von Java oder C++ heranreichen.<br />
<strong>Eiffel</strong> besitzt keine größere <strong>Software</strong>- oder IT-Firma, von welches es<br />
unterstützt wird, wie z.B. Java durch Sun.<br />
<strong>Eiffel</strong><br />
1<br />
Ada ist eine strukturierte Progr<strong>am</strong>miersprache mit statischer Typenbindung. Sie<br />
wurde in den 1970er Jahren von Jean Ichbiah entworfen.<br />
2<br />
ALGOL wurde von 1958-1963 entwickelt und diente zur Lösung<br />
wissenschaftlich-numerischer Probleme.<br />
3 NICE http://eiffel-nice.org<br />
4 <strong>Eiffel</strong> Compiler unter GNU http://smarteiffel.loria.fr
<strong>Objektorientierte</strong> <strong>Progr<strong>am</strong>miersprachen</strong> <strong>am</strong> <strong>Beispiel</strong> <strong>Eiffel</strong> - 3 -<br />
2. <strong>Objektorientierte</strong> Progr<strong>am</strong>mierung<br />
Dieser Themenbereich ist in mehrere Unterpunkte gegliedert, welche in<br />
sich wiederum in der folgenden Art untergliedert wurden. Zuerst erfolgt<br />
eine kurze allgemeine Definition zu dem Themenkomplex, darauf wird die<br />
Umsetzung in der Progr<strong>am</strong>miersprache <strong>Eiffel</strong> erläutert und schließlich<br />
werden die Unterschiede zur Umsetzung in der Progr<strong>am</strong>miersprache Java<br />
aufgelistet.<br />
2.1 Einführung<br />
Die Idee der Objektorientierung ist fast 30 Jahre alt. In den 90er Jahren<br />
war die objektorientierte Progr<strong>am</strong>mierung (Abkürzung OOP) das führende<br />
Progr<strong>am</strong>mierparadigma. Viele der heute verwendeten<br />
<strong>Progr<strong>am</strong>miersprachen</strong> sind entweder von Grund auf objektorientiert (wie<br />
<strong>Eiffel</strong>, Java, SmallTalk) oder wurden im Laufe der Zeit mit<br />
objektorientierten Erweiterungen versehen (Basic, Pascal, ADA).<br />
2.2 Klassen und Objekte<br />
Bei der objektorientierten Progr<strong>am</strong>mierung werden Daten und die auf<br />
diese Daten anzuwendenden Operationen als Klassen zus<strong>am</strong>mengefasst.<br />
Ein Objekt ist ein Exemplar (auch Instanz genannt) einer Klasse, es<br />
enthält durch Attribute repräsentierte Informationen, deren Struktur in<br />
der Klasse definiert ist. Im Progr<strong>am</strong>mablauf kommunizieren die Objekte<br />
miteinander, indem ein Objekt die Attribute eines anderen Objektes auf<br />
bestimmte Eigenschaften hin abfragt oder es beauftragt, eine bestimmte<br />
Operation mit einem bestimmten Datenwert auszuführen.<br />
In <strong>Eiffel</strong> besteht ein Progr<strong>am</strong>m nur aus Klassen. Zur Laufzeit werden<br />
Exemplare der Klassen, die Objekte, erzeugt.<br />
class NAME<br />
<strong>Eiffel</strong><br />
end – class NAME<br />
creation<br />
...<br />
feature<br />
...
<strong>Objektorientierte</strong> <strong>Progr<strong>am</strong>miersprachen</strong> <strong>am</strong> <strong>Beispiel</strong> <strong>Eiffel</strong> - 4 -<br />
Die Eigenschaften von Objekten werden durch Attribute angegeben. Das<br />
Verhalten von Objekten wird durch Methoden definiert. Attribute und<br />
Methoden werden im Abschnitt features definiert.<br />
Der Bereich creation ist optional. In ihm werden Methoden, aus dem<br />
Bereich feature aufgelistet, welche zu Initialisierung eines Objektes<br />
wichtig sind.<br />
In <strong>Eiffel</strong> werden Klassen meist erstellt, um einen abstrakten Datentyp zu<br />
beschreiben. Ein abstrakter Datentyp stellt Schnittstellen zur Verfügung,<br />
welche bestimmte Aufgaben erfüllen. Es ist jedoch nicht bekannt, wie<br />
diese Aufgaben erfüllt werden. Detaillierter wird auf diesen Punkt im<br />
Bereich Datenkapselung 2.5 eingegangen.<br />
Ein Unterschied zu diesem Punkt zur ebenfalls objektorientierten<br />
Progr<strong>am</strong>miersprache Java ist der, dass Attribute und Methoden nicht, wie<br />
in <strong>Eiffel</strong>, zu features zus<strong>am</strong>mengefasst werden. Ein Java Progr<strong>am</strong>m<br />
benötigt eine Klasse, welche als Hauptprogr<strong>am</strong>m-Klassen fungiert, mit<br />
einer main-Methode. Bei <strong>Eiffel</strong> wird dies durch die (hier) root-Klasse<br />
genannte Klasse erledigt, diese enthält im Abschnitt creation eine<br />
bestimmt Prozedur.<br />
2.3 Typen und Verweise<br />
Ein Typ spezifiziert das Verhalten einer Menge von Objekten.<br />
In objektorientierten Sprachen muss grundsätzlich unterschieden werden<br />
zwischen dem statischen Typ (bzw. der statischen Klasse) eines Objektes,<br />
womit der Typ gemeint ist, den der Compiler herleiten kann, und dem<br />
dyn<strong>am</strong>ischen Typ (bzw. der dyn<strong>am</strong>ischen Klasse), welcher den Typ des<br />
Objektes zur Laufzeit eines Progr<strong>am</strong>ms tatsächlich besitzt.<br />
<strong>Eiffel</strong> ist eine statisch getypte Sprache. Dies bedeutet, dass jedes feature<br />
einer Klasse mit einem eindeutigen Datentyp deklariert werden muss.<br />
class REFERAT<br />
feature<br />
autor: PERSON;<br />
titel: STRING;<br />
seitenzahl: INTEGER;<br />
end – class REFERAT<br />
Die Attribute titel und seitenzahl werden mit den vordefinierten<br />
<strong>Eiffel</strong><br />
Datentypen STRING und INTEGER definiert. Das Attribut autor hat als<br />
Datentyp die Klasse Person. Diese Deklaration bedeutet, dass die zum<br />
Attribut autor gehörende Komponente eines Referatobjektes ein Verweis<br />
auf ein Objekt vom Typ PERSON ist.<br />
Es gibt in <strong>Eiffel</strong> nur zwei Arten von Datentypen: einfache Typen (INTEGER,<br />
BOOLEAN, CHARACTER, REAL und DOUBLE) und Klassentypen.
<strong>Objektorientierte</strong> <strong>Progr<strong>am</strong>miersprachen</strong> <strong>am</strong> <strong>Beispiel</strong> <strong>Eiffel</strong> - 5 -<br />
Klassentypen müssen durch Klassendeklarationen definiert werden und<br />
gehören nicht zum Basistypsystem von <strong>Eiffel</strong>.<br />
2.4 Generalisierung, Vererbung<br />
Bei der Generalisierung werden Eigenschaften hierarchisch gegliedert,<br />
wobei Eigenschaften mit allgemeinerer Bedeutung (allgemeineren)<br />
Oberklassen zugeordnet und speziellere Eigenschaften solchen Klassen<br />
zugeordnet werden, welche den Oberklassen untergeordnet sind. Die<br />
Eigenschaften der Oberklassen werden an die Unterklassen weitergegeben<br />
oder vererbt. Die Unterklasse verfügt somit über ihre spezifizierten<br />
Eigenschaften als auch den Eigenschaften ihrer Oberklasse(n).<br />
Eine Vererbung von einer Oberklasse an mehrere Unterklassen ist<br />
möglich, ein gleichzeitiges erben von mehreren Oberklassen fällt in den<br />
Bereich Multiple Vererbung 2.10.<br />
Die Grafik zeigt eine Klassenhierarchie, wobei die Klasse Oberklasse eine<br />
Generalisierung der Klasse Ober-Oberklasse darstellt und selbst von den<br />
Klassen Unterklasse 1 und Unterklasse 2 geerbt wird.<br />
Generalisierung wird in <strong>Eiffel</strong> so umgesetzt, dass zu Beginn der Definition<br />
einer Klasse in einer Erbklausel die jenige Klasse angegeben wird, von<br />
welcher Eigenschaften geerbt werden sollen. Die Eigenschaften (features)<br />
der Oberklasse müssen nicht erneut im feature-Bereich genannt werden,<br />
da sie automatisch verfügbar sind. Lediglich die Eigenschaften die neu<br />
hinzukommen müssen im feature-Bereich explizit benannt werden.<br />
<strong>Eiffel</strong><br />
In Java ist dieser Vorgang bis auf eine andere Form der Notation gleich.<br />
2.5 Datenkapselung<br />
Unter Kapselung versteht man selbstständige Progr<strong>am</strong>mmodule, die<br />
sowohl Daten (Attribute) als auch deren Verarbeitungsroutinen
<strong>Objektorientierte</strong> <strong>Progr<strong>am</strong>miersprachen</strong> <strong>am</strong> <strong>Beispiel</strong> <strong>Eiffel</strong> - 6 -<br />
(Methoden) enthalten. Die Datenstruktur eines gekapselten Objektes<br />
bleibt verborgen. Zugriff auf das Objekt kann nur über öffentlich sichtbare<br />
Attribute oder Methoden genommen werden.<br />
Datenkapselung ist besonders im Zus<strong>am</strong>menhang mit Generalisierung<br />
oder Vererbung besonders wichtig. Ziel ist es nur die Informationen zur<br />
Verfügung zu stellen, welche für die Funktion einer Unterklasse dringend<br />
nötig sind.<br />
<strong>Eiffel</strong> bietet hierbei besondere Möglichkeiten, die es in Java in dieser Art<br />
nicht gibt. So ist es in <strong>Eiffel</strong> möglich nur bestimmte geerbte Eigenschaften<br />
an eine weitere Unterklasse zu exportieren. Hierfür gibt es direkt unter der<br />
Erbklausel einen export-Bereich, in welchem jene Eigenschaften der<br />
Oberklasse einzeln benannt werden, welche zus<strong>am</strong>men mit den neuen<br />
Eigenschaften in der Unterklasse verfügbar sein sollen. Ist dieser Bereich<br />
nicht vorhanden, so sind alle Eigenschaften in der Unterklasse verfügbar.<br />
Diese Methode der Zugriffsbeschränkung auf Eigenschaften der<br />
Oberklasse durch Unterklassen wurde während der Entwicklung von <strong>Eiffel</strong><br />
noch weiter verfeinert. So ist es nun sogar möglich explizit zu den<br />
Eigenschaften, welche exportiert werden sollen, auch eine Unterklasse<br />
anzugeben, an welche die Eigenschaften vererbt werden sollen. Statt<br />
hierbei alle zu vererbenden Eigenschaften einzeln aufzuzählen, kann auch<br />
ein Schlüsselwort (all) angegeben werden, so dass alle Eigenschaften<br />
vererbt werden. Ist bei dieser Exportmethode eine Unterklasse nicht<br />
genannt, so werden keine Eigenschaften der Oberklasse an diese vererbt,<br />
außer den neuen Eigenschaften der vererbenden Klasse selbst. Ist eine<br />
Eigenschaft für eine Unterklasse freigegeben, so steht sie auch<br />
automatisch allen Unterklassen dieser Unterklasse zur Verfügung, sofern<br />
der Export nicht in einer anderen Unterklasse eingeschränkt wird.<br />
In Java wird eine Zugriffskontrolle realisiert, indem jedes Attribut und jede<br />
Methode mittels der Angaben public, private, protected und package bei<br />
der Initialisierung klassifiziert wird. Die einzelnen Angaben Regeln wir<br />
folgt:<br />
- public: Auf Komponenten mit diesem Zugriffsrecht kann man<br />
überall dort zugegriffen, wo man auf die Klasse zugreifen kann, in<br />
der sie definiert sind.<br />
- private: Auf private Komponenten kann man nur innerhalb der<br />
Klasse zugreifen, in der sie definiert sind.<br />
- protected: Auf Komponenten mit diesem Zugriffsrecht kann man<br />
innerhalb des Paketes (package), das die Klasse enthält, in der<br />
sie definiert sind, und in Unterklassen, zugreifen.<br />
- package: Auf Komponenten ohne ein Zugriffsrecht-Attribut kann<br />
man innerhalb des Paketes, das die Klasse enthält, in der sie<br />
definiert sind, zugreifen.<br />
<strong>Eiffel</strong><br />
und Methoden keine explizite Nennung von Erben geben. Stattdessen<br />
Wie man deutlich erkennen kann ist der Ansatz der Zugriffssteuerung in<br />
Java im Vergleich zu <strong>Eiffel</strong> eher indirekt. Es kann oder muss für Attribute
<strong>Objektorientierte</strong> <strong>Progr<strong>am</strong>miersprachen</strong> <strong>am</strong> <strong>Beispiel</strong> <strong>Eiffel</strong> - 7 -<br />
werden durch die Vergabe der Zugriffsrecht-Attribute Gruppen definiert,<br />
welche Zugriff auf eine bestimmte Eigenschaft haben.<br />
2.6 Redefinition<br />
Unter Redefinition versteht man die Veränderung der Implementierung<br />
geerbter Eigenschaften. So können geerbte Methoden überschrieben<br />
werden, sofern man die Berechtigung dazu hat.<br />
Um den Sinn dieser Möglichkeit besser zu verdeutlichen, dient dieses<br />
<strong>Beispiel</strong>. Nehmen wir an in einer Firmenfinanzsoftware existiert eine<br />
Klasse Mitarbeiter, welche u.a. das Gehalt eines Mitarbeiters zur<br />
Verfügung stellen kann. Durch die Schaffung eines neuen Arbeitsbereiches<br />
in der Firma kommt es zu Neueinstellungen besonderer Angestellter,<br />
welche nach Leistung vergütet werden sollen. Dazu wird eine neue Klasse<br />
Leistungsmitarbeiter erstellt, welche eine Unterklasse der Klasse<br />
Mitarbeiter ist. In dieser Unterklasse wird nun die Methode, welche das<br />
Gehalt der Mitarbeiter errechnet durch eine neu Methode, welche auf<br />
einem anderen Rechenschlüssel basiert, ersetzt.<br />
<strong>Eiffel</strong> ermöglicht es geerbte Eigenschaften neu zu definieren. Hierzu wird<br />
in dem redefine-Bereich angegeben, welche der geerbten Eigenschaften<br />
(features) verändert werden. Jedes dieser features muss nun erneut als<br />
feature der Klasse im eigenen feature-Bereich deklariert und später<br />
implementiert werden.<br />
class LEISTUNGSMITARTBEITER<br />
inherit MITARBEITER<br />
redefine<br />
gehalt<br />
export<br />
{ARBEITGEBER} n<strong>am</strong>e, vorn<strong>am</strong>e, adresse;<br />
{FINANZAMT} all<br />
end<br />
feature<br />
abteilung: STRING;<br />
raum, telefon: INTEGER;<br />
gehalt: REAL is -- Gehalt berechnen<br />
do Result := Gehalt nach Leistung<br />
end<br />
end -- class LEISTUNGSMITARTBEITER<br />
<strong>Eiffel</strong><br />
Die dargestellte Vererbung mit Redefinition zeigt eine Deklaration der<br />
Klasse aller Leistungsmitarbeiter, in der das feature gehalt neu definiert<br />
wurde. Ohne den redefine-Bereich wäre die erneute Deklaration von<br />
gehalt als Merkmal von Leistungsmitarbeiter ein Fehler, da gehalt<br />
bereits aus der Klasse Mitarbeiter übernommen wird.
<strong>Objektorientierte</strong> <strong>Progr<strong>am</strong>miersprachen</strong> <strong>am</strong> <strong>Beispiel</strong> <strong>Eiffel</strong> - 8 -<br />
Der redefine-Bereich teilt mit, welche features einer Oberklasse in einer<br />
Unterklasse neu definiert werden. Hierdurch wird gewährleistet, dass der<br />
selbe N<strong>am</strong>e sich auf verschiedene aktuelle features beziehen kann.<br />
Abhängig vom Typ des Objektes, auf das es angewandt wird, erhält man<br />
eine andere Implementierung.<br />
Es ist nicht möglich ein feature beliebig abzuändern. Von außen betrachtet<br />
muss ein feature im Wesentlichen unverändert, d.h. auf die gleiche Art<br />
aufrufbar und veränderbar, bleiben. Die Vereinbarungen der Oberklasse<br />
müssen weiterhin Gültigkeit haben.<br />
Zu den Vereinbarungen, die von der Oberklasse übernommen werden<br />
müssen, gehören insbesondere die Anzahl der Argumente und die Typen<br />
der features. Routinen müssen Routinen bleiben und Attribute Attribute.<br />
In Java ist eine Redefinierung durch eine Unterklasse ebenfalls möglich.<br />
Attribute und Methoden dürfen sogar umdefiniert und überladen (siehe<br />
Abschnitt 2.7) werden, sofern die Zugriffsrechte dies zulassen. Mit dem<br />
Attribut final kann man verhindern, dass eine Methode in Unterklassen<br />
verändert wird. Dies schließt aber nicht aus, dass sie in der Unterklasse<br />
noch benutzt werden kann. Auch Attribute können mit final deklariert<br />
werden. Ein derartiges Attribut erhält genau einmal einen Wert, und zwar<br />
durch die Initialisierung.<br />
2.7 Polymorphismus, dyn<strong>am</strong>isches Binden<br />
Polymorphismus (Vielgestaltheit) bezeichnet im Allgemeinen die Fähigkeit,<br />
verschiedene Formen anzunehmen. Bezogen auf die Objektorientierung<br />
bedeutet Polymorphie und dyn<strong>am</strong>isches Binden, dass in einer<br />
Klassenhierarchie gleichn<strong>am</strong>ige Operationen für verschiedene<br />
Unterklassen unterschiedlich implementiert sein können. Objekte können<br />
polymorph sein, d.h. die zum jeweiligen Kontext passende Operation zur<br />
Verfügung stellen. Wenn für ein einzelnes Objekt die spezifisch<br />
anwendbare Operation erst zu Laufzeit ausgewählt wird, spricht man von<br />
Operationen, welche dyn<strong>am</strong>isch zu den Objekten gebunden werden.<br />
<strong>Eiffel</strong> bietet Polymorphismus durch die Möglichkeit, Eigenschaften von<br />
Klassen teilweise oder auch ganz zu redefinieren. Durch dyn<strong>am</strong>isches<br />
Binden wird dann zur Laufzeit ermittelt, welche der redefinierten<br />
Versionen (d.h. welche konkrete Implementierung) tatsächlich ausgeführt<br />
werden soll. Eine Zuweisung der Form a := b ist in <strong>Eiffel</strong> zulässig, nicht<br />
nur wenn a und b vom selben Typ sind, sondern auch, wenn b Instanz<br />
einer Unterklasse der Klasse von a ist.<br />
<strong>Eiffel</strong><br />
gleichen N<strong>am</strong>en, können sich aber z.B. in der Art der Übergabewerte<br />
Java bietet ebenfalls Polymorphismus, hier jedoch durch überladen von<br />
Methoden. Das Überladen ist im Grunde eine Redefinierung einer geerbten<br />
Methode mit dem Unterschied, dass mehrere Versionen der redefinierten<br />
Methode in einer Klasse vorkommen können. Alle Versionen haben den
<strong>Objektorientierte</strong> <strong>Progr<strong>am</strong>miersprachen</strong> <strong>am</strong> <strong>Beispiel</strong> <strong>Eiffel</strong> - 9 -<br />
unterscheiden. Es bleibt dem Compiler überlassen, die richtige Version für<br />
eine bestimmte Gelegenheit auszuwählen.<br />
2.8 Abstrakte Klassen<br />
Die Methoden in einer abstrakten Klasse sind nur durch die Definition der<br />
Vor- und Nachbedingung definiert. Die Methoden wurden ohne eigentliche<br />
Operation implementiert. Diese wird in einer abgeleiteten Klasse<br />
implementiert, die Implementierung der eigentlichen Operation wurde also<br />
aufgeschoben. Von abstrakten Klassen werden keine Objekte erzeugt.<br />
In <strong>Eiffel</strong> gilt eine Methode als aufgeschoben (deferred), wenn an stelle der<br />
Anweisungsfolge das Schlüsselwort deferred enthalten ist.<br />
Eine Klasse gilt als deferred, wenn sie eine Methode enthält die<br />
aufgeschoben ist oder eine aufgeschobene Methode erbt und nicht<br />
redefiniert hat. Eine solche Klasse muss in ihrer Deklaration als deferred<br />
class gekennzeichnet sein.<br />
Auch in Java können abstrakte Klassen verwendet werden. Die<br />
Realisierung ist gleich der in <strong>Eiffel</strong>. Java verwendet bei der Deklaration von<br />
abstrakten Klassen und Methoden das Schlüsselwort abstract.<br />
2.9 Par<strong>am</strong>etrisierbare Klassen<br />
Eine par<strong>am</strong>etrisierbare Klasse (synonym zu generische Klasse) ist eine mit<br />
generischen formalen Par<strong>am</strong>etern versehene Schablone, mit der<br />
gewöhnliche (nicht-generische) Klassen erzeugt werden können. Die<br />
generischen Par<strong>am</strong>eter dienen als Stellvertreter für die aktuellen<br />
Par<strong>am</strong>eter, die Klassen oder einfache Datentypen repräsentieren.<br />
Par<strong>am</strong>etrisierte Klassen sind keine Typen, sondern Typschemata. Erst mit<br />
den aktuellen Par<strong>am</strong>etern werden sie zu Typen. Ohne aktuelle Par<strong>am</strong>eter<br />
kann man ihre Merkmale nicht ausführen und auch nicht austesten.<br />
In <strong>Eiffel</strong> werden generische Klassen erzeugt, indem bei der<br />
Klassendeklaration hinter den Klassenn<strong>am</strong>en in eckigen Kl<strong>am</strong>mern durch<br />
Kommata getrennt formale generische Par<strong>am</strong>eter angegeben werden.<br />
class GENERISCHEKLASSE[X]<br />
...<br />
<strong>Eiffel</strong><br />
testaufruf: GENERISCHEKLASSE[INTEGER]<br />
Innerhalb der Klasse kann ein formaler generischer Par<strong>am</strong>eter in allen<br />
Deklarationen wie ein normaler Datentyp eingesetzt werden, sei es als Typ<br />
von Attributen, Methoden, Par<strong>am</strong>etern in Routinen oder von lokalen<br />
Variablen. Nach außen ist der formale generische Par<strong>am</strong>eter unbekannt.
<strong>Objektorientierte</strong> <strong>Progr<strong>am</strong>miersprachen</strong> <strong>am</strong> <strong>Beispiel</strong> <strong>Eiffel</strong> - 10 -<br />
Ein <strong>Beispiel</strong> bei dem die Anwendung gerischer Klassen sinnvoll ist, wäre<br />
ein Listenvergleich. In der generischen Klasse würde dazu eine Methoden<br />
Implementiert werden, welche z.B. zwei Elemente verschiedener Listen<br />
auf Übereinstimmung vergleicht. Durch die Übergabe eines aktuellen<br />
Par<strong>am</strong>eters bei dem Erbvorgang, wird der Datentyp der Elemente<br />
übergeben, welche verglichen werden sollen.<br />
Par<strong>am</strong>etrisierbare Klassen lassen sich nur über Umwege in Java<br />
realisieren. Eine vollständige Implementierung ist in Planung.<br />
2.10 Multiple Vererbung<br />
Wenn eine Unterklasse mehrere direkte Oberklassen hat, spricht man von<br />
multipler Vererbung.<br />
Multiple Vererbung lässt sich in <strong>Eiffel</strong> realisieren. In der Vererbungsklausel<br />
werden dazu mehrere Oberklassen zus<strong>am</strong>men mit eventuellen<br />
Modifikationen geerbter features angegeben.<br />
Erbt eine Klasse direkt von mehreren Klassen, so hat sie direkt Zugriff auf<br />
alle features der Oberklassen. Dies kann in manchen Fällen zu<br />
N<strong>am</strong>enskonflikten führen. <strong>Eiffel</strong> umgeht dies, indem durch Erbung<br />
vorhandene features mit gleichem N<strong>am</strong>en umbenannt werden müssen.<br />
Laut Meinung der Java Entwickler führe Multiple Vererbung nur zu<br />
„unnötigen“ Problemen. Daher können Unterklassen immer nur eine<br />
Oberklasse haben. Java hat also nur einfacher Vererbung.<br />
2.11 Wiederholtes Erben<br />
Durch die Möglichkeit der multiplen Vererbung ist eine mehrfache Erbung<br />
der gleichen Klasse<br />
<strong>Eiffel</strong><br />
möglich.
<strong>Objektorientierte</strong> <strong>Progr<strong>am</strong>miersprachen</strong> <strong>am</strong> <strong>Beispiel</strong> <strong>Eiffel</strong> - 11 -<br />
Bei wiederholtem<br />
Erben von gleichen<br />
Oberklassen ergibt<br />
sich das Problem,<br />
dass die features der<br />
mehrfach geerbten<br />
Klasse ebenfalls<br />
mehrfach vorhanden<br />
sind. Im letzten<br />
Abschnitt wurde<br />
erklärt, dass hierbei<br />
ein N<strong>am</strong>enskonflikt<br />
auftritt, welcher durch Umbenennung doppelter features mit gleichem<br />
N<strong>am</strong>en gelöst wird. Dieses Vorgehen macht bei einer wiederholten Erbung<br />
nur dann Sinn, wenn die features nicht gleich sind, also wenn sie von<br />
einer Oberklasse, welche die features wiederum geerbt hat, redefiniert<br />
oder umbenannt wurden. Ist dies nicht der Fall und sind die features<br />
vollkommen identisch, so werden sie als ein feature betrachtet und<br />
vereinigt.<br />
2.12 Zusicherung, Design-by-Contract<br />
Eine wichtige Möglichkeit, die Gefahr von Abweichungen zwischen<br />
<strong>Software</strong>-Spezifikationen und ihren Implementierungen zu vermindern, ist<br />
die Einführung von Spezifikationselementen in die Implementierung. Dazu<br />
werden Klassen, Methoden oder Attributen Ausdrücke über den Zweck<br />
dieses Elements zugeordnet. Ein solcher Ausdruck, welcher mögliche<br />
Zustände eines solchen Elements angibt wird Zusicherung (Design-by-<br />
Contract oder Progr<strong>am</strong>ming-by-Contract) genannt.<br />
In <strong>Eiffel</strong> existieren zur Implementierung solcher Zusicherungen eigene<br />
Prädikate (and, or, and then, or else, not, xor, implies), welche<br />
ausschließlich für diese Zusicherungen eingeführt wurden.<br />
Zusicherungen stellen in <strong>Eiffel</strong> boolsche-Ausdrücke dar.<br />
n>0 and not x=Void<br />
Dieser boolsche-Ausdruck wird dann erfüllt, wenn n größer 0 und x nicht<br />
leer ist.<br />
Es ist möglich die Zusicherungen während der Laufzeit überwachen zu<br />
lassen. Kommt es durch nicht erfüllte Zusicherungen zu einem Fehler,<br />
kann die Routine entweder selbst innerhalb eines rescue-Bereichs<br />
versuchen diesen<br />
<strong>Eiffel</strong><br />
Fehler zu beheben oder dieser Fehler wird an die<br />
aufgerufene Routine zurückgeben, um dort eine Fehlerbehandlung zu<br />
ermöglichen.
<strong>Objektorientierte</strong> <strong>Progr<strong>am</strong>miersprachen</strong> <strong>am</strong> <strong>Beispiel</strong> <strong>Eiffel</strong> - 12 -<br />
3. Weitere Besonderheiten<br />
<strong>Eiffel</strong> Quelltext wird gewöhnlich in Maschinencode (Binär) der<br />
Zielmaschine kompiliert. Es besteht aber auch die Möglichkeit der<br />
Umwandlung von <strong>Eiffel</strong>-Souce in C-Code. Zudem gibt es die Ansätze<br />
diesen in Bytecode für Java Virtual Machine zu übersetzen.<br />
Zur Entstehungszeit von <strong>Eiffel</strong> war es üblich die Speicherverwaltung für<br />
eine Anwendung manuell zu Implementieren. Ähnlich wie bei Smalltalk<br />
stellt <strong>Eiffel</strong> den benötigten Speicher automatisch zu Verfügung. Die<br />
Freigabe von nicht mehr benötigtem Speicherplatz wird mittels des<br />
garbage-collector, ebenfalls ein automatisierten Vorgang, realisiert.<br />
4. Einsatzgebiete<br />
Für <strong>Eiffel</strong> werden als Anwendungsgebiete, für welche es sich besonders<br />
anbieten soll genannt:<br />
- sicherheitskritische Anwendungen<br />
- Entwurf- und Spezifikationssprachen<br />
- Ausbildung in objektorientierter Progr<strong>am</strong>mierung<br />
(Die Angaben sind Aussagen der <strong>Eiffel</strong> Entwickler selbst und können an<br />
dieser Stelle nicht bestätigt oder verworfen werden.)<br />
5. Fazit<br />
Während meiner Arbeit an diesem Referat und dem dadurch gewonnenem<br />
Eindruck bezüglich der Möglichkeiten von <strong>Eiffel</strong>, bin ich zu der<br />
Überzeugung gelangt, dass <strong>Eiffel</strong> die Kriterien erfüllt, auf Grund welchen<br />
<strong>Eiffel</strong> erschaffen wurde. <strong>Eiffel</strong> ist vollkommen objektorientiert und dank<br />
seiner ausgefeilten Datenkapselungsmöglichkeiten (spezifischer feature-<br />
Export) ist ein hohes Maß an Sicherheit gewährleistet. Auch sind<br />
Eigenschaften moderner Sprachen, wie automatische Speicherverwaltung<br />
oder die Möglichkeit der Zusicherung in <strong>Eiffel</strong> bereits implementiert.<br />
Ich persönlich halte die Möglichkeit der multiplen Vererbung für eine<br />
unnötige Quelle von<br />
<strong>Eiffel</strong><br />
Fehlern. Die bei sehr großen Projekten eine sehr gute<br />
Planung voraussetzt, um solche zu vermeiden. In Java, welches multiple<br />
Vererbung nicht unterstützt, wird mithilfe von Schnittstellen erreicht, dass<br />
man Eigenschaften von mehreren Klassen erben kann. Ich halte diesen<br />
Ansatz für sinnvoller im Vergleich zur multiplen Vererbung.
<strong>Objektorientierte</strong> <strong>Progr<strong>am</strong>miersprachen</strong> <strong>am</strong> <strong>Beispiel</strong> <strong>Eiffel</strong> - 13 -<br />
6. Literatur<br />
Meyer, Bertrand: EIFFEL The language<br />
Prentice Hall International (UK) Ltd; 1992; I. Reprint<br />
ISBN: 0-13-247925-7<br />
Switzer, Robert: EIFFEL An Introduction<br />
Prentice Hall International (UK) Ltd; 1993; II. Series<br />
ISBN: 0-13-105909-2<br />
Oestereich, Bernd: <strong>Objektorientierte</strong> <strong>Software</strong>entwicklung<br />
R. Oldenbourg Verlag München Wien; 1998; 4. Auflage<br />
ISBN: 3-486-24787-5<br />
Gumm, Sommer: Einführung in die Informatik<br />
R. Oldenbourg Verlag München Wien; 2002; 5. Auflage<br />
ISBN: 3-486-25635-1<br />
Schildt, Herbert: Java 2 Ent-Packt<br />
MITP-Verlag GmbH, Bonn; 2001; 1. Auflage<br />
ISBN: 3-8266-0736-8<br />
<strong>Eiffel</strong>