left up right


3. Objektorientierte Datenbanken:

3.1. Objektorientierte Analyse, Design und Programmierung:


Bei dieser Arbeitsweise wird versucht die deskriptiven Möglichkeiten der natürlichen Sprache weitgehendst zu erhalten und zu verwenden. Am Anfang steht eine objektorientierte Analyse der natürlichsprachigen Problem- und Lösungsbeschreibung. Dabei gibt es mehrere methodische Ansätze, wobei eine Möglichkeit die bereits bekannte Entity-Relation-Analyse, angereichert um einige weiter Analyseaspekte wie z.B. Vererbungsrelationen, darstellt.  Im ersten Analysegang wird dabei  die natürlichsprachige Problem- und Lösungsbeschreibung nach Substantiven, Adjektiven und Verben durchsucht, wobei die Substantive den Objekten entsprechen, die Adjektive können meist als Datenelemente der Objekte umgesetzt werden und die Verben werden zu Methoden (zur genauen Begriffsbestimmung siehe unten). Erst nachdem diese Grundbausteine identifiziert sind setzen komplexere Analysemethoden ein, die die genauen Abhängigkeiten und Relationen zwischen den einzelnen Elementen bestimmen lassen.
Ziel ist es, das Niveau der Abstraktion bei der Beschreibung des Problems in der Datenbank - bzw. in der Klasse (siehe unten), also im objektorientierten Programm - möglichst nahe der natürlichen Sprache zu halten. Es soll somit nur ein absolutes Minimum an Abstraktion eingeführt werden, um dem Programmierer zu ermöglichen eine Beschreibung des Problems im Programm umzusetzen, die möglichst nah an der natürlichsprachigen Problembeschreibung liegt. Andererseits soll der Abstraktionsgrad hinsichtlich der physischen Repräsentation der Daten im Computer möglichst groß sein. Der Programmierer, bzw. Anwender soll sich keine Gedanken machen müssen wie die Daten im Endeffekt abgespeichert werden. Ihn soll einzig und allein ein möglichst aussagekräftiges Datenmodell interessieren.
Beim objektorientierten Design wird versucht eine optimierte Abbildungen der Wirklichkeit zu erreichen: optimiert in dem Sinne, dass sprachliche Ungenauigkeiten oder Sinn- bzw. Bedeutungslosigkeiten durch die Analyse eliminiert wurden. Da aber keine zusätzliche Sprache eingeführt wird in die die natürliche Sprache abgebildet werden muss, kann eine nahezu verlustfreie Übertragung der Aussagen der natürlichen Sprache in ein objektorientiertes Programm erreicht werden (dies ist eine stark idealisierte Sichtweise, und stösst im wirklichen Leben rasch an ihre Grenzen).

Anmerkung: An dieser Stelle muss zwischen Anwendungsprogrammierer und "Klassenprogrammierer" unterschieden werden. Der Anwendungsprogrammierer kann natürlich nur dadurch auf eine semantisch sehr reiche Sprache zurückgreifen, da ein "Klassenprogrammierer" die objektorienterte Sprache bzw. Datenbank um die für die Problembeschreibung/Lösung notwendigen Klassen (siehe unten) zuvor angereichert hat. Der Klassenprogrammierer erzeugt mit den Klassenbibliotheken eine semantische Erweiterung der eigentlichen Programmiersprache, sodass diese neue Programmiersprache (Programmiersprache + Klassenbibliotheken) eine semantische Reichhaltigkeit anbieten, die der Semantik der natürlichen Sprache, bezogen auf einen eng begrenzten Problemkontext, sehr nahe kommt.
Diese Klassen können aber auch für andere Problembeschreibungen dann wiederverwendet, oder adaptiert werden, sodass nach Erstellung ausreichend komplexer Klassenbibliotheken eine Bearbeitung eines Problems ohne weitere Veränderungen durch den Klassenprogrammierer, also nur durch den Anwendungsprogrammierer, durchgeführt werden können. Klassenprogrammierer müssen einen weit grösseren Abstraktionsgrad eingehen und im ungünstigsten Fall bis auf die Maschinenebene zurückgehen. Prinzipien des objektorienten Arbeitens (siehe unten) gewährleisten aber, dass diese Implementierungsdetails keine wesentliche Auswirkung auf den Anwendungsprogrammierer und seine Analyse haben.
Im Folgenden sollen einige Grundbegriffe der objektorientierten Analyse bzw. Design erklärt werden. Diese sind:

  1. Klasse (Daten + Methoden)
  2. Objekt
  3. Information Hiding
  4. Vererbung (einfach, mehrfach)
  5. Polymorphismus
ad 1.) Unter "Klasse" versteht man einen abstrakten Datentyp. Diese Datentypdefiniton enthält alle zum diesem Typ gehörigen Datenelmente und -Methoden. Eine Klasse stellt also einen Bauplan für einen bestimmten Objekttyp dar. Datenelmente können in diesem Zusammenhang beliebige andere abstrakte Datentypen sein - also auch andere Klassen - und unter Methoden versteht man Funktionen mit denen dieser Datentyp manipuliert werden kann. Bei konsequentem objektorientierten Design stellen die Methoden einer Klasse die einzige Möglichkeit zum Manipulieren der in der Klasse enthaltenen abstrakten Datenelemente dar. Ist also in einer Klasse "Mensch" ein Datenelement mit dem Namen "Gewicht" enthalten, das in einem Integer abgespeichert wird, dann kann man nicht einfach diesem "Integer Gewicht" einen Wert zuweisen, sondern man muss eine Methode, also z.B. Gewicht_eintragen (...)  verwenden um den Wert zu setzten, bzw. eine andere Methode, z.B. Gewicht_abfragen(...) um den Wert zu erfahren, usw.. Man spricht in diesem Zusammenhang von sogenannten "Messages", mittels denen man mit Objekten  kommuniziert. Eine Klasse beschreibt somit nicht nur wie etwas ist, sondern auch was ich damit machen kann. In der herkömmlichen Programmierung wurde immer eine Trennung zwischen Daten und Funktionen die diese Daten manipulieren gemacht. Im objektorientierten Denken fliessen diese Konzepte wieder zusammen.

ad 2.) Ein "Objekt" entsteht durch Instantiierung einer Klasse. Es wird also mit Hilfe des Bauplans ein reales Objekt erzeugt. Durch einen eindeutigen Namen und durch bestimmte Datenwerte erhält dieses Objekt eine eindeutige Identität. Bei reinen objektorientierten Sprachen sind alle Datentypen Klassen und somit gibt es nur Objekte als Daten. Und die einzige Möglichkeit diese Daten zu manipulieren ist, indem man Messages zu Objekte schickt bzw. von diesen empfängt. Es gibt somit auch keine Funktionsaufrufe mehr, wo in einer Funktion bestimmte Datenwerte manipuliert werden. Will ein Objekt eine bestimmte Information von einem anderen Objekt, dann sendet dieses erste Objekt eine Message an das zweite Objekt in dem es die gewünschten Informationen anfordert, und das zweite Objekt sendet wiederum eine Message zurück mit den gewünschten Informationen, falls diese geliefert werden können, oder sonst einer entsprechenden Fehlermeldung.

ad 3.) Diese Art Daten zu Manipulieren hat einen tieferen Grund, das "Information Hiding". Darunter versteht man, dass der Benutzer von Klassen keine Ahnung von der konkreten Implementierung einer Klasse haben muss. Er muss also nicht wissen welche abstrakten Datentypen in einer Klasse vorgesehen sind, oder wie eine bestimmte Methode auf solche Datenelemente zugreift. Für den Benutzer einer Klasse, also jenen der Objekte anlegt un mit diesen manipuliert ist es nur wichtig welche Messages die Objekte verstehen, also wie man mit den Objekten kommunizieren kann. Der Vorteil eines solchen Designs ist, dass man Implementierungen von Objekten beliebig verändern kann, solange nur die Messages, die das Objekt versteht sich nicht ändern. Man kann also  in obigem Beispiel die Implementierung des Datenelements "Gewicht" von Integer auf Float (also von ganzer Zahl auf rationale Zahl) umstellen, solange das Verhalten der Methoden "Gewicht_eintragen" und "Gewicht_abfragen" nicht ändern. Dies hat den Vorteil, dass man Designprobleme oder -Fehler sehr einfach beheben kann, und auch das Verhalten von Objekten einfach an neue Anforderungen anpassen und erweitern kann.

ad 4.) Die "Vererbung" stellt einen weiteren wichtigen Aspekt des objektorientierten Ansatzes dar. Dabei geht es darum Klassen in sogenannte "ist-ein" Relationen zu bringen. So ist z.B. ein Mann ein Mensch, ein Mensch ist ein Lebewesen, usw. Man erzeugt so eine Hierarchie von Klassen, die von sehr konkreten zu immer abstrakteren Objekten geht. Die abstraktere Klasse stellt hierbei immer den Elternteil ("parent") der konkreteren Klasse dar, dem sogenannten Kind ("child"). Wichtig ist dabei, dass ein Kind alle Eigenschaften der Elternklasse vererbt bekommt. Dass bedeutet, dass alle Datenelemente und Methoden von der Elternklasse an das Kind weitergegeben werden. Für die Erstellung einer Kindklasse bedeutet das, dass man sich nicht mehr um die Aspekte der Klasse kümmern muss, die bereits durch die Elternklasse abgedeckt werden. Ausserdem kann sich der Anwenderprogrammierer darauf verlassen, dass in einer Klassenhierarchie alle konkreteren Klassen (also jeweils die Kinder) mit all den Methoden der Elternklassen manipuliert werden können. Das bedeutet, dass in einem bestehenden Programm ein Objekt einer allgemeineren Ausprägung durch eine konkreter Instanz ersetzt werden kann, ohne etwas am Programm ändern zu müssen. Der Vollständigkeit halber soll erwähnt werden, dass ein Kind auch von mehreren Elternklassen erben kann.
 

ad 5.) Unter "Polymorphismus" versteht man einerseits, dass ein Objekt auf gleiche Messages, je nach Kontext sich unterschiedlich verhält, und andererseits, dass man einem Objekt unter dem gleichen Messagenamen unterschiedliche Messages senden kann. Im ersteren Fall kann man also bei der Vererbung eine Methode, die vererbt wurde überschreiben und ihr eine neue Bedeutung, eine an den spezifischeren Charakter des neuen Objekts angepasste, verleihen. So kann in obigem Beispiel eine Methode Name (...) für den Klassentyp Lebewesen den Typ des Lebewesen, also z.B. "Pferd", "Vogel",..., liefern. Verwendet man die gleiche Methode beim Klassentyp Mensch so liefert diese den Vornamen und Nachnamen des Menschen, also z.B. "Ludwig Wittgenstein". Wird nun ein Objekt des Typs Mensch im Kontext eines Lebewesens verwendet, so wird aber nicht die Methode Name(...) des Menschen aktiviert sondern die des Lebewesen. Als Antwort würde man also z.B. "Mensch" erhalten.
Im anderen Fall kann ein und die selbe Klasse mehrere Methoden gleichen Namens besitzen - dazu ist keinerlei Vererbung notwendig -, die je nach unterschiedlichen Parametern, also unterschiedlichen Messages, unterschiedlich reagieren. Es könnte in obigem Beispiel eine Methode Gewicht_erhöhen ( "2x" ) und eine Methode Gewicht_erhöhen ( 17.5 ) geben. Erstere würde eine Verdopplung des bestehenden Gewichts bewirken, die zweite Methode würde z.B. 17.5 kg zum bestehenden Gewicht hinzuaddieren.

Einen Überblick über die wichtigsten Strukturen des objektorientierten Ansatzes finden sich in Abbildung 4.1.

 

Abb. 3.1: Grafische Darstellung der wichtigsten Strukturen der objektorientierten Analyse (aus COAD & YOURDON. 1994b).
 

Weitere Informationen zum Themenbereich Objektorientierte Analyse, Design und Programmierung finden sich in COAD & YOURDON 1994a, 1994b, COAD & NICOLA 1994, SCHÄFFER 1995 und in BLUM 1992.
Nach dieser kurzen Einführung in das objektorientierte Konzept soll nun die Anwendung dieser Gedanken auf Datenbanken besprochen werden.
 
 

3.2. Objekt-Relationale Datenbanken:

Objekt-Relationale Datenbanken stellen eigentlich nur eine leichte Erweiterung des relationalen Datenmodells dar. Da aber dieses in kommerziellen Datenbanksystemen meist nur sehr eingeschränkt umgesetzt ist, erscheint die Einführung objektorientierter Ansätze als grosse Verbesserung. Eigentlich wird nur bei der Definition der abstrakten Datentypen eine Erweiterung um objektorientierte Konzept - wie der Vererbung, des Polymorphismus, des Information Hidings,..., sowie der gemeinsamen Sichtweise von Daten und Methoden - vorgenommen. Da bereits im relationalen Modell abstrakte Datentypen vorhanden sind, bei denen zwischen physischer Repräsentation und abstraktem Modell unterschieden wird, sind diese Erweiterungen nur ein logischer Schritt. Man erspart sich mit diesen Konzepten unnötige Arbeit beim definieren ähnlicher Datentypen und bringt mit der Klassenhierarchie zusätzlich Struktur in das Datenmodell. Auch die Bindung der Methoden an die Klasse vereinfacht die Verwendung eines Datentyps, da man nicht in anderen Teilen der Datenbank nach Funktionen ("Stored Procedures") suchen muss um einen Datentyp zu manipulieren. Prinzipiell ist aber diese Sichtweise ohne grosse Probleme im relationalen Datenmodell integrierbar und stellt somit nur eine besonders leistungsfähige Implementation einer relationalen Datenbank dar, bei der zusätzliche Aspekte des Analyseprozesses auf das relationale Modell abgebildet werden.
 
 

3.3. Objekt-Datenbanken:

Anders sieht es bei "echten" Objekt-Datenbanken aus. Dabei werden nur Objekte als Objekte - und nicht als Teile einer Relation - in der Datenbank abgelegt und alle Manipulationen der Objekte erfolgen über deren inhärente Methoden. Das bedeutet, dass das DBMS ein objektorientiertes Programm ist, welches die in der Datenbank abgelegten Objekte in sich als Objekte wiederfindet und mit diesen Objekten über Messages kommuniziert. D.h. dass nahezu in natürlicher Sprache die Datenbank manipuliert werden kann, da diese Messages der natürlichen Sprache - bei optimalem Klassendesign - den Messages entsprechen, die von den Objekten in der Datenbank verarbeitet werden können. Prinzipiell stellt sich hier die Frage, ob ein Programm auch als Datenbank angesehen werden kann. Da aber ein Programm als sehr spezielles DBMS gesehen werden kann ist diese Frage mit ja zu beantworten (die gleiche Frage wird uns auch noch bei den Logik-Datenbanken beschäftigen).
Die Performanz der Datenbank hängt somit einerseits vom Design der Objekte ab, und andererseits von der Qualität des objektorientierten Programms. Es muss aber erwähnt werden, dass Objekt-Datenbanken, besonders bei einer größeren Anzahl von gespeicherten Objekten nie an die Geschwindigkeit einer relationalen Datenbank herankommt. Die große Nähe zur natürlichen Sprache bewirkt eine geringe Rücksichtnahme auf Systemeigenheiten. Man könnte auch pointiert formulieren: Eine Nähe zur Welt bedingt eine Ferne vom Computer (u.u.?).
Um Leistungseinbußen zu minimieren werden oft die Objekte in einer einfachen (mehrdimensionalen) relationalen Struktur abgelegt. Damit erreicht man, dass man Objekte, nach wenigen wichtigen Kriterien (z.B. Alter, Größe, Gewicht, Position,...) klassifiziert, rasch in einer Struktur finden kann, um danach die aufwendigeren Detailinformationen mittels Messages von den Objekten zu erfragen. Da es aber hier mehr um theoretische Betrachtungen geht, soll den Performanzüberlegungen nicht zu viel Achtung beigemessen werden.
Der Unterschied zu relationalen Modellen liegt in erster Linie darin, dass eine Dateneinheit nicht mehr größtmögliche Einfachheit haben muss, sondern dass komplexe Dateneinheiten in ihrer Gesamtheit - gewissermaßen als unteilbar - betrachtet werden. Anders als im relationalen Modell wir beim Objekt-Modell eine Dateneinheit nicht über einen Namen bzw. eine fixe Position in einer logischen Struktur festgelegt, sondern das Datenobjekt wird durch sein Verhalten und die darin mitgeteilten Eigenschaften bestimmt. Der reduzierte Anspruch an die Struktur wird natürlich durch die Möglichkeit einer unvollständigen Beschreibung erkauft. Wenn ein Objekt gewisse Aspekte der Wirklichkeit nicht abgebildet hat, bzw. wenn diese Informationen bei der Dateneingabe nicht zur Verfügung standen, kann es vorkommen, dass ein Objekt auf eine Frage keine, oder nur eine Standard-(Default-)Antwort liefert. Auch kann bei komplizierten Vererbungshierarchien die Situation entstehen, dass nur eine geringe Anzahl von Methoden bei allen Objekten anzuwenden sind. Somit können aber nur diese wenigen Methoden (gewissermaßen der kleinste gemeinsame Nenner) für die Suche in der Gesamtheit der Objekt-Datenbank verwendet werden.
Auch die Konsistenz der Datenbank kann nicht mehr einfach gewährleistet werden. So ist in diesem Fall der Programmierer vor dem Abspeichern eines Objekts selbst dafür verantwortlich zu prüfen, ob diese neue Objekt die Konsistenz der Datenbank nicht kompromittiert. Allerdings gibt es keine formalen Kriterien nach denen dies überprüft werden kann. Es liegt im subjektiven Verständnis der Objekte welche Aspekte der Objekte eine Konsistenzprüfung verlangen oder ermöglichen. Das wird besonders schwierig, wenn mehrere Aspekte eines Objekts, bzw. unterschiedliche Aspekte mehrerer Objekte Inkonsistenzen hervorrufen können. Der zielführendste Weg ist es, eine Methode der Konsistenzprüfung in jede Klasse einzubauen und danach diese Methode an allen bereits vorhandenen Objekten auszuprobieren. Im Gegenzug muss dann aber auch die Konsistenzprüfmethode jedes bereits vorhandenen Objekts auf das neue Objekt angewendet werden. Dies zeigt eine wesentliche Änderung des Blickwinkels auf: bei relationalen Datenbanken gibt es einen alles überwachenden Hauptprozess der bestimmt was zulässig ist und was nicht; bei Objekt-Datenbanken ist jedes einzelne Objekt dafür verantwortlich.
Abschließend kann gesagt werden, dass Objekt-Datenbanken zwar ein realistischeres Abbild der Wirklichkeit darstellen, dass dies aber auf Kosten der logischen Struktur geht, welche notwendig ist um große Datenmengen effizient zu verwalten. Je flexibler das Datenmodell ist, desto weniger Struktur ist erlaubt, und desto weniger Klassifizierungen und Konsistenzüberprüfungen sind möglich. Die Möglichkeit zur Analyse und in weiter Folge das Verständnis der Daten reduziert sich und in weitere Folge geht bei größtmöglicher Detailgenauigkeit der Klassen geht der Sinn und die Aufgabe einer Datenbank verloren. Die Struktur liegt in erster Linie im hierarchischen Vererbungsmodell und somit ist die Qualität einer Objekt-Datenbank maßgeblich von der Qualität des Klassendesigns und er -Implementierung abhängig.
 



©Mag.Dr. Alfred Hofstadler : "Datenbanken und Wittgenstein: ontologische Vergleiche",Diplomarbeit an der Universität Wien, März 2001.
left up right