Noch gibt es Hürden auf der "Prachtstraße zum SW-Entwurf"

16.08.1991

Die Antwort auf die Frage, was objektorientiert meint, ist ein wenig umständlich: Das Wort findet heutzutage in erstaunlich vielen Zusammenhängen Verwendung. Es gibt deshalb auch zahllose Gelegenheiten, mit scheinbar präzise formulierten Sätzen geradewegs aneinander vorbeizureden. Die Basiskonstellation ist simpel: A verwendet "objektorientiert" (OO) in bezug auf Programmierung, B kennzeichnet damit die Analyse, und C charakterisiert so eine Benutzeroberfläche.

Zweierlei scheint Allgemeingut zu sein: Zum einen ist objektorientiert ein Gütesiegel; man findet kaum noch Software, die nicht OO ist. Dieser Marketing-Aspekt soll hier nicht weiter behandelt werden. Zum anderen scheint jedem klar zu sein, daß OO viel mehr ist als eine Bezeichnung, die einige Merkmale zusammenfaßt. Es handelt sich um eine Philosophie, so hört man, oder jedenfalls um ein Paradigma.

Ich möchte im folgenden einen Überblick über die Verwendungsweisen von Objektorientierung geben, um einige geistige Hinweisschilder im Dickicht der klugen Gespräche aufzustellen, die sich mit dieser "Prachtstraße zu Software-Entwurf und -Realisierung" befassen, so Bertrand Meyer, ein Franzose, der mit dem Namen der von ihm entworfenen OO-Sprache nicht wenig anspruchsvoll an einen namhaften Hardware-Architekten erinnert: Eiffel.

Den harten Kern der Objektorientierung bilden nach wie vor die Programmiersprachen. Hier hat OO eine einigermaßen allgemeingültige Bedeutung, und hier ist auch der Ausgangspunkt für die Verbreitung der OO-Terminologie in alle möglichen Abteilungen der Anwendungsentwicklung - von der Gestaltung der Benutzeroberfläche über Analyse und Design bis zu den Datenbanken - zu finden.

Was OO als Konzept allenfalls bedeuten kann

Ich werde im folgenden zunächst auf objektorientierte Programmierung und Datenbanken eingehen. Daraufhin will ich aufzeigen, was OO als abstraktes Konzept allenfalls be deuten kann (Sprache, Paradigma). Auf dieser Basis beschreibe ich, wie Objektorientierung in den der Programmierung vorgelagerten Phasen der Anwendungsentwicklung sinnvoll eingesetzt werden kann, und zwar in einem Großsystemumfeld, wie es für die kommerzielle Informationsverarbeitung typisch ist. Hier gibt es noch wenig Einigkeit, insbesondere was das Design betrifft. Die Darstellung ist also recht subjektiv.

Da schon viel Vernünftiges über OOP geschrieben wurde, kann ich mich hier relativ knapp fassen. Es geht im Grunde darum, daß eine Programmiersprache die fundamentalen OO-Konzepte unterstützt. Leider ist es vom Konstrukteur der Sprache abhängig, was er für fundamental hält. Relevant sind jedenfalls folgende Grundlagen:

- Encapsulation

Ein Objekt besteht aus Daten und Methoden (zu ihrer Bearbeitung). Diese bilden eine Einheit, weil ausschließlich durch die festgelegten Methoden auf die Daten zugegriffen werden kann. Methoden heißen diese Prozeduren dank Smalltalk. Man kann sich bildlich die Datenstruktur gleichsam von den zugehörigen Methoden eingekapselt vorstellen - daher stammt auch die Bezeichnung. So wäre beispielsweise ein Bildschirmfenster ein Objekt, dessen Daten aus den verschiedenen Koordinaten, Farbdefinitionen etc. bestehen. Ein Fenster kann man vergrößern, verkleinern und natürlich auch schließen, also müssen entsprechende Methoden programmiert werden. Diese bilden dann zusammen mit den Daten das Objekt.

Die Objekte kommunizieren über Nachrichten (Messages) miteinander. Eine Nachricht enthält die Angabe der gewünschten Methode und eventuelle Parameter. Sie hat ganz allgemein das folgende Format: (O; M; P1,...Pn), wobei O das angesprochene Objekt (Receiver), M die Methode (Selector) und die Pi die notwendigen Parameter repräsentieren. Die Parameter sind von der Methode abhängig. Im Fenster-Beispiel benötigt "Schließen" keine Parameter, wohingegen man bei "Verkleinern" den Verkürzungsfaktor mitgeben muß, damit die neuen Koordinaten berechnet werden können.

- Abstraction

Objekte werden durch Merkmalstypen abstrakt in einer Klasse definiert. Sie selbst bilden - mit konkreten Daten - Exemplare (Instances) ihrer Klasse. Was ich beim Programmieren wirklich festlege, ist nicht das einzelne Objekt, sondern seine Klasse. Diese allerdings kann selbst wieder Objekt einer Metaklasse sein.

Bei der Definition der Klasse geht es um alle Attribute, die den Klassenexemplaren gemeinsam zukommen. Ein Beispiel: Jedes Fenster hat einen Rahmen, Vergrößerungs- und Verkleinerungs-Buttons, eine Titelzeile etc. Nicht Gegenstand der Klassendefinition sind die konkreten Werte, die einem einzelnen Fenster zukommen, also beispielsweise der Text, der in der Titelzeile steht, oder die Farbe des Rahmens. Bei unserem Fenster werden also nicht alle Koordinaten hart codiert - das wäre ja auch ein absurder Rückschritt gegenüber den konventionellen Sprachen - , sondern über Variable definiert, deren Datentyp in manchen Sprachen nicht einmal fixiert zu sein braucht (Dynamic Typing). Ein konkretes Objekt entsteht dann durch eine sogenannte "Instantiation", bei der den Variablen konkrete Werte zugeordnet werden.

- Inheritance

Klassen können eine Hierarchie (vom Abstrakten zum Konkreten) bilden. Die Subklassen erben Datentypen und Methoden ihrer Supraklasse. Bei Multiple Inheritance sind für eine Klasse mehrere Oberklassen möglich.

Hier merkt man, wie nützlich der Ansatz ist: Wiederverwendbarkeit ist sozusagen konzeptionell eingebaut. Ich muß nicht - wie sonst - nach der Codierung eines Fensters den allgemeinverwendbaren Teil davon an die nächste Stelle kopieren, wo ich ein Fenster öffnen will, sondern ich setze FENSTER als Supraklasse bei der Definition der anderen Fenster ein. Brauche ich ein Exemplar, das Eingabefelder enthält, definiere ich es als Subklasse FENSTER_E und muß nur die zusätzlichen Variablen und Methoden codieren. Benötige ich ein Fenster mit einer Auswahl, so definiere ich eine andere Subklasse FENSTER_A und muß lediglich die Buttonreihe für die Auswahl (inklusive Methoden natürlich) neu programmieren.

Falls Multiple Inheritance zugelassen ist - das ist nicht in jeder Sprache der Fall - , könnte ich nun eine Fensterklasse FENSTER_AE, in der die Eingaben gemäß einer Auswahl bearbeitet werden, allein dadurch festlegen, daß ich sie als Subklasse von FENSTER_A und FENSTER_E definiere. Eine unter Umständen notwendige Anpassung der Methoden könnte durch Überschreiben erfolgen. Es leuchtet ein, daß man mit der Tiefe solcher Vererbungshierarchien aufpassen sollte, um nicht Probleme beim Änderungsdienst zu bekommen

- Polymorphismus

Polymorphismus bedeutet daß ein und dieselbe Methode (zum Beispiel Anzeigen) auf verschiedene Datentypen wirkt (zum Beispiel Text, Grafik, Image). Anders ausgedrückt: Wird eine Nachricht, die zum Beispiel die Methode "Print" aufruft, an unterschiedliche Objekte wie Texte oder Diagramme gesendet, so wirkt sie gleichermaßen. Erreicht wird dieser Effekt dadurch, daß man "Print" pro Klasse unterschiedlich implementiert. Technisch gesehen ist Dynamic Binding unterstellt das heißt, die Befehle werden erst zur Laufzeit mit den ausführbaren Instruktionen verbunden.

- Information Hiding

So wird die Technik bezeichnet, möglichst viele Details der Implementierung zu verstecken: Von anderen Objekten aus kann immer nur auf einen Teil der zum Objekt gehörenden Daten und Methoden zugegriffen werden. Dies unterstützen manche Sprachen dadurch, daß man bei der Definition von Variablen und Methoden die Attribute "public" oder "private" vergeben kann. Sämtliche Festlegungen, die "private" sind, können vom Programmierer geändert werden, ohne daß sich Konsequenzen für die Wartung der anderen Klassen ergeben. Die öffentlichen Variablen und Methoden, deren Änderung Anpassungen an anderen Klassen notwendig macht, heißen Protokoll.

Grundsätzlich kann man zwischen reinen OO-Sprachen wie Smalltalk oder Eiffel und hybriden Sprachen wie C + + unterscheiden. Hierbei haben erstere, die speziell für objektorientierte Programmierung entwickelt wurden, den Vorteil, daß alle ihre Möglichkeiten konsequent auf OOP abgestimmt sind. So ist es für den Neueinsteiger leichter, Rückfälle in die alte Methodik zu vermeiden. Dies ist ein Risiko bei C+ + oder Object Pascal. Umgekehrt besitzen solche auf bekannten Sprachen aufbauenden OO-Erweiterungen den Vorzug, daß der Programmierer an ihre Syntax gewöhnt ist.

Für die Entscheidungsfindung in der Praxis ist nicht nur die Geschlossenheit des Systems und die Eleganz der Lösung wichtig, sondern auch

- die Kompatibilität (welche Plattformen werden unterstützt?),

- die Geschwindigkeit (handelt es sich um einen Compiler oder einen Interpreter?) sowie

- die Größe der Klassenbibliothek.

Speziell der letzte Punkt ist von besonderer Bedeutung denn das Ideal "Programmieren nach dem Baukastenprinzip" unterstellt, daß der Hersteller der Sprache möglichst viele vordefinierte Klassen mitliefert. Trotzdem muß man für die eigenen Belange Spezifisches konstruieren. Im großen Rahmen wird dann die Bibliotheksverwaltung problematisch: Wie kann sichergestellt werden, daß dasselbe Modul nicht unter fünf verschiedenen Namen programmiert wird? Wie kann man - bei einer Basis von mehr als 1500 gelieferten Klassen - schnell und präzise das richtige Objekt finden? Wie läßt sich die Verantwortlichkeit für die Bibliotheken (pro Projekt?) regeln?

Die Wahl einer Sprache kann nur unter Berücksichtigung des konkreten Umfeldes erfolgen. Meines Wissens gibt es für MVS oder andere Großsystem-Betriebssoftware derzeit noch nicht einmal einen OO-Compiler. In solchen Umgebungen kommt OOP also gegenwärtig nur für Front-end-Prozesse auf PCs im Rahmen von Verbundverarbeitung mit Host-Systemen (zum Beispiel als Datenbankserver) in Frage. In diesem Zusammenhang ist beispielsweise die Entwicklungsumgebung Enfin/2 recht interessant - allerdings handelt es sich hier nur um einen Interpreter. Enfin/2 ist ein - Smalltalk-ähnliches - komplettes objektorientiertes Programmier-Environment mit Fenstertechnik, das unter Windows 3.0 oder OS/2 läuft und die Kommunikation mit dem Host über LU6.2 (APPC) unterstützt.

OO-DB (Datenbanken):

Die Ansätze zu objektorientierten Datenbanken stellen in gewisser Weise eine Ergänzung zur OO-Programmierung dar. Die Objekte existieren als Instanzen von Klassen zunächst lediglich zur Laufzeit des Programms. Sollen sie dauerhaft, wiederverwendbar und auch für andere benutzbar gemacht werden, dann reicht es nicht aus, sie in Dateien abzuspeichern. Falls beispielsweise mehrere Personen mit diesen Objekten arbeiten wollen, sind Kontrollmechanismen notwendig für

- gleichzeitigen Zugriff (Concurrency Control),

- Integrität (die Abhängigkeiten müssen berücksichtigt werden) und

- Sicherheit (Recovery, Zugriffsschutz).

Man braucht also ein Datenbank Management System, das Objekte, also Daten und zugelassene Prozeduren, gemeinsam abspeichert. Damit der Nutzen dieses neuen Konzepts deutlich wird, muß man allerdings davon ausgehen, daß die verarbeiten Datentypen vielfältig, unregelmäßig und komplex sind. Geht es um Daten, die sich unmittelbar in Satz- oder Tabellenform darstellen lassen, so ist das relationale Modell ausreichend. Für diese simplen Datenstrukturen können durchaus die erlaubten SQL-Befehle, Typprüfungen und Trigger für referentielle Integrität als Quasi-Methoden interpretiert werden. Die schlichte Tatsache, daß wir es im kommerziellen Bereich ohnehin noch lange Zeit mit relationalen DBMS zu tun haben werden, stellt sich so in etwas günstigerem Licht dar (vgl. Winblad u.a.: OO-Software; Addison-Wesley, Reading 1990).

Das heißt allerdings nicht, daß man relationale Datenbanksysteme nicht in einem objektorientierten Sinne verbessern könnte, etwa indem man das Konzept der referentiellen Integritätsprüfung verallgemeinert. So könnten beispielsweise Prüfroutinen, Trigger und Prozeduren, die für bestimmte Views der Datenbasis gelten, zusammen mit ihnen abgespeichert werden. Statt in den Applikationen, die mit den im View definierten Daten arbeiten, sind sie einheitlich im DBMS abgelegt. Je mehr solcher Quasi-Methoden man mit flexibel konstruierbaren Datentypen speichern kann, um so größer sind Datensicherheit, Wiederverwendbarkeit des Codes und Vereinfachung der Anwendungskonstruktion. Diesen Weg gehen zum Beispiel Sybase und Ingres.

Anders sieht es aus, wenn man an eine Büroumgebung denkt. Hier treten neben den "klassischen" Datentypen Texte und - in Zukunft vermehrt - Bilder, Sprache etc. auf. Diese lassen sich in relationalen DBMS bislang nur ungenügend verwalten. Eine Anwendung, die auf die verschiedenen Datentypen zugreift, müßte die zugrundeliegenden verschiedenen Speicherungskonzepte selbst verwalten. Das Interesse, diesen Aufwand zu vermeiden, ist ein praktischer Ausgangspunkt für ein OO-DBMS. Es böte eine gleichmäßige Schnittstelle für alle Datentypen und vereinfachte damit die Anwendungsentwicklung und -wartung erheblich. Beispielsweise wurde für Büroinformationssysteme OZ + entworfen (vgl. Kim (ed.): Object Oriented Concepts, Databases and Applications; Addison-Wesley, Reading 1989)

Ein anderer Ansatzpunkt ist das CASE-Umfeld, in dem ebenfalls komplexe Datentypen auftreten, die nur spezielle Bearbeitungsmethoden zulassen. Die verschiedenen Produkte von Analyse- und Designtools, Generatoren und Wartungsinstrumenten sollten sich in allen ihren Versionen in einem einheitlichen Information Resource Dictionary System (IRDS) verwalten lassen. Der Repository Manager/MVS etwa hat eine OO-DB-Schnittstelle für CASE-Tools, die auf der Speicherung der Daten in DB2 basiert.

Ein Hauptanwendungsgebiet von OO-DB-Konzepten dürfte im technischen Bereich (CAD/ CAM) liegen, denn beim Arbeiten mit Grafik und in der Produktion fallen sehr verschiedenartige Datentypen an, die ausschließlich auf ganz spezielle Weise bearbeitet werden sollen, so daß "Encapsulation" als sinnvolles Prinzip einleuchtet.

Prinzipiell gibt es zwei Ansätze, ein OO-DBMS zu realisieren Entweder werden die Objekte direkt gespeichert (reiner Ansatz) oder sie werden in Informationen umgesetzt, die sich in einer zugrundeliegenden relationalen Datenbank speichern lassen. Beim Zugriff werden sie dann wieder zusammengesetzt und als vollständige Objekte übergeben. Solche hybriden Modelle bieten vor allem Produzenten von RDBMS an. Sie haben, durch den Umsetz- und Rekompositionsprozeß bedingt, einen beträchtlichen Überbau mit entsprechenden Auswirkungen auf das Antwortzeitverhalten. Für den technischen Bereich sind sie deshalb untauglich.

Innerhalb eines Konzepts, nach dem die Objekte unmittelbar und unzerlegt gespeichert werden, läßt sich noch einmal zwischen einem "reinen" und einem evolutionär an SQL anknüpfenden Ansatz unterscheiden. Letzterer hat den Vorteil, bestehende RDBMS besser integrieren zu können. In dieser Richtung forscht etwa IBM. Einen Ansatz, der kompromißlos eine neue Technologie verwendet, stellt demgegenüber "Orion" dar (vgl. oben Kim 1989). Diese Datenbank ist auf CAD/CAM- und Expertensystem-Anforderungen ausgerichtet.

Es bleibt aber festzuhalten, daß die Entwicklung noch so sehr in den Anfängen steckt daß ein Konsens noch nicht einmal darüber erzielt wurde, was ein "reines" Konzept sein soll (vgl. Rajiv Gupta, Ellis Horowitz (ed.): Objectoriented Databases With Applications etc.; Prentice Hall 1991) und wie sich Dinge wie "Inheritance" sinnvoll implementieren lassen.