\chapter{Grundstrukturen f"ur Softwarebibliotheken} \label{Grundstrukturen}
Abh"angig davon, ob die Softwarekomponenten einer Bibliothek Module oder
Klassen sind, lassen sich zwei verschiedene Formen von Bibliotheken
unterscheiden, die modul- bzw. objektorientierten Bibliotheken. Dieses Kapitel
beschreibt sowohl die Eigenschaften als auch die sich daraus ergebenden Vor-
und Nachteile modul- und objektorientierter Bibliotheken. Ziel des Vergleichs
ist es, festzustellen, welche Form von Bibliotheken die in Kapitel
\ref{SoftBibs} genannten Qualit"atsmerkmale von Bibliotheken bei der Anwendung
auf Bibliotheken f"ur Massendatentypen besser erf"ullt.

\section{Modulorientierte Softwarebibliotheken} \label{ModProg}
Eine m"ogliche Grundstruktur f"ur Softwarebibliotheken ist die Aufteilung des
Systems in funktionale Untereinheiten, auch "`Module"' genannt \cite{Sch81}.
Den Proze"s der Gliederung und seine Ergebnisse bezeichnet man dabei als
"`Modularisierung"' \cite{May72,Den79,Sch81}. Die nachfolgenden Abschnitte
beschreiben zun"achst die Eigenschaften und Ziele der Zerlegung von Software in
Module und die sich aus dieser Vorgehensweise ergebenden Nachteile in Bezug auf
Softwarebibliotheken. Am Beispiel der Bibliothek f"ur Massendatentypen des
Tycoon-Systems werden die auftretenden Probleme exemplarisch verdeutlicht. 

\subsection{Eigenschaften und Ziele}
Modularisierung unterst"utzt die Verst"andlichkeit und Testbarkeit von
Systemen, die Wiederverwendung einzelner Module und die arbeitsteilige
Erstellung von Modulen durch verschiedene Programmierer \cite{Hen92}.
Als Richtlinien der modulorientierten Zerlegung von Software fa"st \cite{Coh72} folgende Punkte zusammen: 
\begin{itemize}
\item Jedes Modul bearbeitet eine logische Untermenge des gesamten Problems.
\item Module sind in sich abgeschlossen. Ihre Gr"o"se soll angemessen
sein\footnote{\cite{Coh72} gibt als Richtwert an, da"s ein Modul in der
Funktionalit"at 200 Cobol--Programmzeilen entsprechen soll.}.
\item Module sind Unterprogramme.
\item Module besitzen Ein-- und Ausgang.
\item Das Verhalten von Modulen entspricht dem Gedanken der "`Black--Box"', d.
h. ihr Verhalten h"angt nur von den Eingangswerten ab, nicht von einem zu
erinnernden internen Zustand der Module. 
\item Alle Ein-- und Ausgaben der Module sollten in Unterprogrammen geb"undelt
werden. 
\end{itemize}
Wesentliche Vorteile der Modularisierung sind die M"oglichkeit der getrennten
"Ubersetzung der Module und die Erstellung der Module mit weniger Wissen "uber
den Code in anderen Teilen des Gesamtsystems \cite{Par72}.
Die Aufteilung des Programms in kleine Module vereinfacht nicht nur die
Implementierung, sondern erh"oht auch die Testbarkeit des entstehenden Systems.
Module sind im Sinne der Testbarkeit abgeschlossene Funktionseinheiten, die
s"amtliche Au"senbeziehungen "uber ihre wohldefinierte Schnittstelle
abwickeln. Statt ein monolithisches System mit unz"ahligen verschiedenen
Zust"anden auf Korrektheit pr"ufen zu m"ussen, l"a"st sich der Test nun in zwei
Phase aufteilen \cite{Sto73,Coh72}: 
\begin{itemize}
\item Modultest: Im Rahmen des Modultests werden alle Module einzeln einem Test
unterzogen. Alle in ihrer Schnittstelle angebotenen Methoden sind auf
Korrektheit zu "uberpr"ufen. 
\item Gesamttest\footnote{\cite{Lig90} bezeichnet diesen Test als
"`Integrationstest"'.}: Nach erfolgreicher Durchf"uhrung des Modultests kann
das aus den einzelnen Modulen zusammengesetzte Gesamtsystem auf Korrektheit
getestet werden. Da die einzelnen Komponente des Systems bereits getestet sind,
sollten in dieser Phase nur noch Fehler auftreten, die ihren Ursprung im
Zusammenspiel der Module haben \cite{Sto73}. 
\end{itemize}

Die "Anderungsfreundlichkeit der Software steigt, wenn die Module nicht nur
Verarbeitungsschritte, sondern wesentliche Entwurfsentscheidungen
zusammenfassen\footnote{\cite{Coh72} kritisiert, da"s in der Praxis trotz der
M"oglichkeiten der modularen Programmierung lediglich die urspr"unglichen
monolithischen Systeme in einzelne Module aufgeteilt w"urden, ohne sich "uber
die zu dieser Aufteilung f"uhrenden Entscheidungen klar zu sein. Die Vorteile
der modularen Programmierung gehen bei einer solchen Vorgehensweise verloren,
da sich "andernde Benutzeranforderungen bei zu enger Koppelung der Module
"Anderungen in allen oder zumindest zahlreichen Modulen des Systems nach sich
ziehen k"onnten.} \cite{Sch81,Par72}. Abh"angigkeiten zwischen den
Modulen sind zu minimieren, um Module unabh"angig herstellen und verstehen zu
k"onnen. Ein derartiges Design steigert die Modifizierbarkeit des gesamten
Systems, da ver"anderte Anforderungen an das System nun in der Regel nicht
mehr zu globalen "Anderungen in zahlreichen Modulen f"uhren.

Als Systemarchitektur schl"agt \cite{Coh72} vor (Abbildung
\ref{Modularisierung}), das Gesamtsystem durch eine
Schichtenbildung aus aufeinander aufbauenden Modulen (im Bild A bis E) zu
realisieren, so da"s jede Schicht die Funktionalit"at der unter ihr
liegenden bei der Realisierung eigener Funktionalit"at nutzt 
\renewcommand{\epsfsize}[2]{0.75#1} 
\begin{figure}[hbt]
\begin{center} 
\leavevmode
\epsfxsize=14cm
\epsffile{../Bilder/thorsten/Postscript/Modularisierung.ps}
\end{center}
\caption{Entstehung des Gesamtsystems aus aufeinander aufbauenden Komponenten
(nach [Cohen 72])}
\label{Modularisierung} \end{figure}


Um die Unabh"angigkeit zwischen den Modulen zu gew"ahrleisten, schl"agt
\cite{Par71} das sog. Geheimnisprinzip ({\it information hiding}) vor. Der
Entwickler eines Moduls soll danach die Weitergabe von Informationen "uber das
Modul als bewu"ste Designentscheidung verstehen \cite{Sch81}. Die Benutzer von
Modulen neigen nach Ansicht von Parnas dazu, sich bei der Konstruktion eigener
Programme mit Hilfe der angebotenen Module auf alle ihnen "uber die
Funktionsweise der Module bekannten Informationen zu verlassen. Daher schl"agt
Parnas vor, nur so viele Informationen "uber die Module weiterzugeben, wie ein
Benutzer wirklich ben"otigt (auch in: \cite{Par72b}). Diese ver"offentlichten
Informationen stellen damit als dauerhafte Eigenschaften der Module
Schnittstelleninformationen dar. Ver"offentlichte Eigenschaften d"urfen vom
Anbieter anschlie"send nicht mehr ver"andert werden, da durch diese "Anderungen
die Programme derjenigen Benutzer ung"ultig werden k"onnten, die sich auf die
Dauerhaftigkeit verlassen haben. Die "ubrigen Eigenschaften
k"onnen jedoch auch zu einem sp"ateren Zeitpunkt noch ver"andert werden. 

Bei einer w"ortlichen Interpretation des vorgeschlagenen Geheimnisprinzips
entstehen Probleme bei der Softwareentwicklung. Ein Mitglied des Teams d"urfte
sich beispielsweise nicht den von einem anderen Mitglied geschriebenen
Quelltext eines Moduls ansehen, da ihm sonst auch alle Informationen "uber die
interne Realisierung des Moduls bekannt w"urden, die der Anbieter des Moduls
nicht zur Ver"offentlichung freigegeben hat. Dies bedeutet, da"s ein
Programmierer auch nicht mehr beurteilen kann, welche von einem Modul
angebotenen Prozeduren besonders effizient implementiert sind. Auch eine
sinnvolle Auswahl zwischen verschiedenen Modulen mit gleichem Verwendungszweck
ist bei dieser Interpretation des Geheimnisprinzips nicht mehr m"oglich
\cite{Sch81}. 
Eine explizite Spezifikation dauerhafter Eigenschaften, von denen die
Korrektheit anderer Komponenten abh"angen darf, vermeidet die bei einer
w"ortlichen Interpretation des Geheimnisprinzips auftretenden
Nachteile \cite{Sch81}.  

Als typische Entwurfsentscheidung, die in einem Modul zusammengefa"st werden
sollte, nennt \cite{Par72} eine Datenstruktur, ihre internen Verbindungen sowie
die lesenden und schreibenden Zugriffsfunktionen. \cite{Sch81} bezeichnet dies
als ein "`Datentyp-Modul"'. Durch Anwendung des Spezifikationsprinzips auf
Datentyp-Module gelangt man zur Entwurfsmethode der "`Datenabstraktion"' oder
der "`Abstrakten Datentypen"' \cite{Sch81}. Zugriffsfunktionen und ihr
Verhalten in Form der Modulschnittstellen werden spezifiziert, nicht
jedoch die interne Repr"asentation der Daten. Benutzerprogramme, die nur auf
Basis der Spezifikation der Module verifiziert wurden, k"onnen damit durch
"Anderungen der internen Repr"asentation der Daten nicht ung"ultig werden.

Mit Hilfe der modularen Programmiersprachen kann man also abstrakte Datentypen
realisieren. Eine Instanz eines solchen abstrakten Datentyps kann Daten
speichern und bietet Funktionalit"at auf den Daten an. Ein Zugriff auf die 
gespeicherten Daten ist nur unter Verwendung der Schnittstelle des abstrakten
Datentyps m"oglich. Aus diesem Grund kann man auch von einer horizontalen
Trennung sprechen. Ein abstrakter Datentyp entspricht damit in der praktischen
Programmkonstruktion einem Modularisierungskonzept \cite{Sch81}.
Die Eigenschaften von Modulen fassen \cite{Bal82,AS88} zusammen:
\begin{itemize}
\item Bereitstellung einer funktionalen Abstraktion oder eines abstrakten
Datentyps.
\item Kontextunabh"angigkeit bis auf eine definierte Schnittstelle, d. h. ein
Modul ist unabh"angig von seiner Umgebung entwickelbar, "ubersetzbar, pr"ufbar,
wartbar und verst"andlich. \cite{Goo74} merkt hierzu an, da"s die
Schnittstelle "ubersichtlich und m"oglichst einfach sein soll. Das Auftreten
komplexer Datenstrukturen in einer Schnittstelle deute auf eine mangelhafte
modulare Zerlegung hin.
\item Spezifizierung allein durch die Schnittstellenbeschreibung.
\item Realisierung des Geheimnisprinzips 
\item Realisierung des Lokalit"atsprinzips. Programmteile, die eine Funktion
betreffen, sind an einer Stelle konzentriert.
\end{itemize}
Aus der Diskussion um die Zerlegung gro"ser Programme in kleinere Module sind
auch eigene Programmiersprachen hervorgegangen, die das Konzept der
Modularisierung und der abstrakten Datentypen direkt unterst"utzen. Ihr wohl
prominentester Vertreter ist Modula-2 \cite{Wir88,CLR89}.  

Korrektheit, Robustheit, Wartbarkeit und damit Ver"anderbarkeit sind also die
wesentlichen Ziele bei der Entwicklung des modularen Programmierstils.
Kapselung von Daten und Aufteilung in einzelne Module helfen, diese Ziele zu
erreichen und bilden die Grundlage der von modulorientierten Bibliotheken
angestrebten Wiederverwendbarkeit. 

\subsection{Schw"achen modulorientierter Bibliotheken}
"Uberlegungen der Trennung, Aufteilung und Kapselung stehen beim modularen Stil
im Vordergrund. Dieser Abschnitt greift diesen Gedanken auf und beschreibt,
welche Formen der Trennung und Kapselung in modularer Programmierung
vorkommen und welche Wirkung diese Spracheigenschaften und Mechanismen auf die
Entwicklung und Gestaltung qualitativ hochwertiger modulorientierter
Softwarebibliotheken haben. Die Qualit"at von Bibliotheken wird dabei
insbesondere an den folgenden Qualit"atsmerkmalen gemessen:
\begin{itemize}
\item Wiederverwendbarkeit und Spezialisierung
\item Kombinierbarkeit
\item "Ubersichtlichkeit durch Vereinheitlichung von Protokollen
\item einfache Schnittstellen f"ur komplizierte Funktionalit"at sowie
Standardisierung 
\end{itemize}

\subsubsection{Einschr"ankung der Wiederverwendung und Spezialisierung}
\label{ModWieder}
Verglichen mit der objektorientierten Programmierung treten Wiederverwendung
und Spezialisierung bei modulorientierter Programmierung in anderer Form und
mit anderer Bedeutung auf. Modulorientierte Programmierung wird h"aufig
eingesetzt, um gro"se Softwaresysteme zu realisieren. Der Systementwurf erfolgt
dabei oft durch eine Zerlegung der Gesamtfunktionalit"at in einzelne Schritte
({\it top-down decomposition}) \cite{Bud89}. Dieses Vorgehen ist auch als
schrittweise Verfeinerung ({\it stepwise refinement}) bekannt \cite{Wir71}. 

Bei der Anwendung dieser Entwurfstechnik stellt das zu entwerfende Gesamtsystem
f"ur den Entwerfer zun"achst eine Funktion dar, die im Rahmen des
Entwurfsprozesses spezifiziert werden mu"s. Im Anschlu"s an die Spezifizierung
des Gesamtsystems teilt der Entwerfer die Funktionalit"at, die das Gesamtsystem
erbringen soll, in Hauptfunktionsgruppen auf. Diese Dekomposition wiederholt
sich mit den Hauptfunktionsgruppen, die zun"achst in Funktionsgruppen und
schlie"slich in Funktionen zerfallen, bis der Umfang der Funktionalit"at so
"uberschaubar ist, da"s die einzelne Funktion im Rahmen eines Moduls
implementiert werden kann. Abbildung \ref{TopDown1} zeigt einen solchen
Entwurfsproze"s.
\renewcommand{\epsfsize}[2]{0.85#1} 
\begin{figure}[hbt]
\begin{center} 
\leavevmode
\epsfxsize=14cm
\epsffile{../Bilder/thorsten/Postscript/TopDown.ps}
\end{center}
\caption{Erster Zerlegungsschritt (nach [Budgen 89])}
\label{TopDown1} \end{figure}

In diesem ersten Schritt der schrittweisen Zerlegung kommt es noch zu doppelter
Eintragung von gleicher Funktionalit"at. Die Abbildung zeigt, da"s
beispielsweise die Funktionalit"at, ein Zeichen oder eine Zeichenkette zu lesen
bzw. zu schreiben, mehrfach enthalten ist. Dies zeigt, da"s diese
Funktionalit"at an mehreren Stellen innerhalb des Systems von Nutzen ist. Ein
zweiter Schritt des Entwurfs reduziert doppelt auftretende Funktionalit"at auf
eine wiederverwendbare Funktionalit"at. Abbildung \ref{TopDown2} zeigt das
Ergebnis des zweiten Entwurfsschrittes.
\renewcommand{\epsfsize}[2]{0.85#1} 
\begin{figure}[hbt]
\begin{center} 
\leavevmode
\epsfxsize=14cm
\epsffile{../Bilder/thorsten/Postscript/TopDown2.ps}
\end{center}
\caption{Zweiter Zerlegungsschritt (nach [Budgen 89])}
\label{TopDown2} \end{figure}

In gro"sen Systemen setzt sich der beschriebene Algorithmus zur Aufteilung der
Funktionalit"at in handhabbare Einheiten fort, indem aus den einzelnen
Komponenten Schichten gebildet werden. Jede Schicht nutzt in einem solchen
Modell die Funktionalit"at der unter ihr liegenden Schicht und bietet
zus"atzliche Funktionalit"at an.  

Die bisher beschriebenen Aufteilungen betreffen nur die Funktionalit"at des
Systems, nicht die Daten, auf denen die Funktionalit"at arbeitet. Die gesamte
Funktionalit"at, deren Aufteilung in den beiden Abbildungen dargestellt wird,
arbeitet auf derselben Repr"asentation der Daten. Das Format dieser Daten wird
nicht ver"andert. 
In sehr gro"sen Systemen ist dies nicht immer der Fall. In
vielen F"allen ist die Ver"anderung der Repr"asentation von Daten sogar Teil
der gew"unschten Funktionalit"at. Ein Datenbanksystem ist ein Beispiel f"ur
eine solche Ver"anderung der Repr"asentation. Bei "Uber\-g"angen von einer
Systemschicht des Datenbanksystems in die n"achste werden die Daten in eine
andere Repr"asentation konvertiert. Auf diese Weise erfolgt eine Abbildung von
Relationen auf einfache Daten, die auf der Magnetplatte gespeichert sind. Der
Wechsel der Repr"asentation ist in diesen F"allen keine Ineffizienz, sondern
Teil der gew"unschten Funktionalit"at des Systems. 
Wiederverwendung zeigt sich also in modulorientierten Systemen in der Regel
dadurch, da"s Funktionalit"at in kleinere Einheiten zerlegt wird und die
Gesamtfunktionalit"at unter Verwendung der einzelnen Komponenten realisiert
ist.

Diese Form der Wiederverwendung korrespondiert mit Spezialisierung, da auf
einer funktionalen Ebene des Entwurfsvorganges die Hauptfunktionalit"at in eine
kleinere Granularit"at aufgespalten wird. Ziel dieses Vorgangs ist jedoch eine 
Menge von Funktionseinheiten, deren Funktion jeweils disjunkt ist.
Eine "Ubereinstimmung der Funktionalit"at, wie sie zwischen mehreren Klassen in
einem objektorientierten System durch die Ableitung von derselben Oberklasse
zu finden ist, gibt es in einem modulorientierten System in der Regel nicht.

Spezialisierung findet also bei modulorientierter Programmierung auf der Ebene
der Funktionalit"at im Rahmen einer disjunkten  Zerlegung w"ahrend des
Entwurfsvorgangs statt, w"ah\-rend sie sich in objektorientierten Bibliotheken
auf die Eigenschaften von Objekten bezieht. Modulorientierte Zerlegung f"uhrt
damit zu disjunkten Komponenten, objektorientierte Zerlegung zu "ahnlichen
Komponenten. 

\subsubsection{Mangelnde Unterst"utzung inkrementeller Erweiterung}
Es gibt zwei Alternativen, ein Modul inkrementell zu erweitern:
\begin{itemize}
\item "Anderungen direkt im urspr"unglichen Quelltext durchzuf"uhren:\newline
Nach der "Anderung existiert die alte Version des Quelltextes
nicht mehr. Alle Programme, welche die alte Version des Moduls benutzen,
m"ussen angepa"st und neu "ubersetzt werden. Diese Form der Erweiterung bietet
sich damit an, wenn etwa eine neue Prozedur in die Schnittstelle einzuf"ugen
ist. Die Ver"anderung bestehender Prozeduren gef"ahrdet jedoch die G"ultigkeit
von Klienten. 
\item "Anderungen auf der Kopie des Quelltextes: \newline
Anschlie"send existieren zwei Versionen des Moduls, die zum gr"o"sten Teil
identisch sind. Wenn sich zu einem sp"ateren Zeitpunkt Teile des identischen
Codes als fehlerhaft oder nicht optimal erweisen, ist die Fehlerkorrektur oder
Optimierung der Algorithmen in beiden Modulen parallel durchzuf"uhren. Eine
derartige "Uberarbeitung von gleichartigem Code ist teurer als die "Anderung
eines einzelnen Moduls und sorgt f"ur eine neue Fehlerquelle.  
\end{itemize}
Beide Methoden sind somit mit nicht unerheblichen Nachteilen behaftet.


\subsubsection{Einschr"ankungen der Kombinierbarkeit}
\label{ModulKombinierbarkeit} 
Abschnitt \ref{ModWieder} beschrieb die Aufteilung der Funktionalit"at des
Gesamtsystems als typisches Vorgehen modulorientierter Programmierung. Das
Gesamtsystem ist damit eine Kombination der Funktionalit"at der einzelnen
Komponenten. Diese Beobachtung legt die Vermutung nahe, modulorientierte
Sprachen w"urden die Kombination von Modulen unterst"utzen. Diese Vermutung ist
jedoch unzutreffend. Der Versuch, in einer modularen Sprache Funktionalit"at
aus verschiedenen Modulen zu kombinieren, st"o"st schnell auf Widerst"ande. Bei
der Entwicklung einer Bibliothek zur Verwaltung von Massendatentypen sind diese
Widerst"ande besonders ausgepr"agt.

Funktionalit"at ist in der Informatik in der Regel die Bereitstellung von
Aktionsm"oglichkeiten auf Daten. Die von einem Modul angebotene Funktionalit"at
mu"s bereits vollst"andig realisiert sein. Eine vollst"andige Realisierung
setzt aber voraus, da"s einem Modul bekannt ist, in welcher Repr"asentation die
Daten vorliegen, auf denen die Funktionalit"at des Moduls arbeiten
soll\footnote{Abschnitt \ref{ObjBib} zeigt, da"s objektorientierte
Bibliotheken Funktionalit"at auch ohne Festlegung auf eine Repr"asentation der
Daten anbieten k"onnen und dadurch die Kombinierbarkeit von Funktionalit"at
unterst"utzen.}.
Die Funktionalit"at verschiedener Module arbeitet also auf einem jeweiligen
Datentyp. Ausgehend vom Gedanken der Kapselung kann diese Funktionalit"at nur
"uber die Schnittstelle des jeweils zugeh"origen abstrakten Datentyps verwendet
werden. 

Abbildung \ref{Mauer} verdeutlicht dieses Problem. Die Abbildung zeigt zwei
Hierarchien von abstrakten Datentypen, die aus jeweils 3 Schichten bestehen.
Die Repr"asentation der Daten erfolgt in unterschiedlicher Weise in den jeweils
niedrigsten Schichten der beiden Hierarchien. Auf dieser Schicht baut jeweils
ein abstrakter Datentyp (A und B) auf. Die Funktionalit"at von A und B wird von
jeweils einem weiteren abstrakten Datentyp (C und D) erweitert, ohne die
Repr"asentation der Daten zu ver"andern. 
Eine Kombination der Funktionalit"at der beiden abstrakten Datentypen C und D
scheitert nun jedoch an deren Prinzip der Kapselung. Es ist also unm"oglich,
die Funktionalit"at von C und D effizient auf dieselben Daten anzuwenden. Eine
solche Kombination w"are nur m"oglich, indem die Daten des einen abstrakten
Datentyps in die Repr"asentation des anderen "ubertragen w"urden. Ein solches
Umkopieren ist jedoch in der Regel so ineffizient, da"s eine Kombination von
Funktionalit"at verschiedener abstrakter Datentypen unterbleibt. Der Versuch
scheitert an der in der Darstellung angedeuteten "`Mauer der Ineffizienz"'.
\renewcommand{\epsfsize}[2]{0.55#1} 
\begin{figure}[hbt]
\begin{center} 
\leavevmode
\epsfxsize=14cm
\epsffile{../Bilder/thorsten/Postscript/Bulklib-Fuer-Vortrag.b.ps}
\end{center}
\caption{Ineffizienz der Kombination von Funktionalit"at} \label{Mauer}
\end{figure}

Bei der Realisierung einer Bibliothek zur Verwaltung von Massendatentypen tritt
diese Einschr"ankung der Kombinierbarkeit besonders drastisch in
Erscheinung. Sowohl durch Zeiger verbundene Speicherungsstrukturen als auch die
Speicherung von Elementen in Feldern sind in jedem Fall Bestandteil einer
solchen Bibliothek. F"ur jede dieser Re\-pr"a\-sen\-ta\-tions\-for\-men mu"s in
der Bibliothek eine eigene vollst"andige und unabh"angige Hierarchie von
abstrakten Datentypen aufgebaut werden\footnote{\cite{Nor92} kommt in seiner
Dissertation zu "ahnlichen Ergebnissen:"`Consider the important problem of
combining, or "`integrating"', modules that must share data. The possibility of
sharing means that interacting modules must agree not only on the abstract
interfaces, but also on the underlying data representations."'}. 

\subsubsection{Fehlende Unterst"utzung der Standardisierung}
In der Bibliothek einer modulorientierten Sprache finden sich zahlreiche
Implementierungen von abstrakten Datentypen. Dabei f"allt auf, da"s ein gro"ser
Teil der Prozeduren und Funktionen in den Schnittstellen mehrerer abstrakter
Datentypen enthalten ist (z.B. Einf"ugen, L"oschen, usw.).

Wegen der getrennten Entwicklung der Modulhierarchien abh"angig von der
jeweiligen Repr"asentation der Daten ist es dem Entwickler allein "uberlassen,
eine Einheitlichkeit der Notationen "uber die Grenze einer einzigen
Schnittstelle hinweg zu erreichen. Dieses Problem versch"arft sich noch, wenn
die Bibliothek in Gruppenarbeit entsteht. Die Einheitlichkeit basiert dabei nur
auf Vereinbarungen zwischen den verschiedenen Entwicklern und auf selbst
gesetzten Normen und Regeln.

\subsubsection{Fehlende einfache Sicht auf komplexe Schnittstellen}
Ein weiteres Problem modulorientierter Softwarebibliotheken besteht darin,
da"s der Benutzer alle Operationen auf seinen Daten einer einzigen
Schnittstelle entnehmen mu"s. Wenn der Benutzer also in seinem Programm an
einer Stelle eine komplexe Operation verlangt, mu"s er einen abstrakten
Datentyp ausw"ahlen, dessen Schnittstelle komplex genug ist, diese Operation
anzubieten. Auch bei den sehr viel einfacheren Operationen f"ur das
Einf"ugen oder L"oschen von Elementen ist der Benutzer an die Verwendung der
komplizierten und durch die Zahl der Methoden m"oglicherweise
un"ubersichtlichen Schnittstelle gebunden. Modulorientierte Bibliotheken bieten
dem Benutzer also nicht die M"oglichkeit, die Funktionalit"at der komplexen
Operationen aus der Schnittstelle eines spezialisierten abstrakten Datentyps zu
entnehmen, aber f"ur einfache Standardanfragen einen einfachere Schnittstelle
zu benutzen. 
Sp"atere Teile der Arbeit zeigen, da"s objektorientierte Sprachen bei der
L"osung dieses Problems unterst"utzen.


\subsection{Die Massendatentypen-Bibliothek von Tycoon}
Die Bibliothek des Tycoon-Systems zur Verwaltung von Massendatentypen ist in
der modulorientierten Programmiersprache TL entwickelt worden. Dieser Abschnitt
zeigt beispielhaft anhand dieser Bibliothek, welche Auswirkungen die
Eigenschaften modulorientierter Sprachen auf die Struktur von
Softwarebibliotheken und den Programmierstil bei deren Erstellung haben.

\subsubsection{Struktur der Bibliothek}
Abbildung \ref{Bulklib} zeigt die Benutztbeziehungen innerhalb der
Bibliothek. Als benutzt gelten dabei die Module, die von einem Modul importiert
werden. Die Abbildung enth"alt nur jene Module, die im Tycoon-System den
Massendatentypen zugerechnet werden. Andere Importbeziehungen, z.B. Importe des
Moduls {\sf Iter}, sind nicht eingezeichnet. 
Es f"allt auf, da"s die Bibliothek in 5 nicht zusammenh"angende Teile
aufgeteilt ist: 
\begin{itemize}
\item Teil 1: Die Bibliothek implementiert eine Schlange ({\sf Queue}), ohne
einen anderen abstrakten Datentyp der Bibliothek zu verwenden. Dies ist um so
erstaunlicher, als die Bibliothek auch eine Liste ({\sf List}) enth"alt, die
bei der Realisierung der Schlange hilfreich sein k"onnte.  
\item Teil 2: Den zweiten Teil der Bibliothek bilden Assoziation ({\sf Assoc}),
W"orterbuch ({\sf Dictionary}) und Menge ({\sf Set}), die unter Verwendung der
Liste realisiert wurden. Die Liste "ubernimmt die Speicherung der Daten,
w"ahrend die anderen abstrakten Datentypen ihre Operationen durch Aufrufe der
Listenschnittstelle anbieten. 
\item Teil 3: Diesen Teil der Bibliothek bilden die abstrakten Datentypen,
deren Elemente in einem Feld ({\sf Array}) gespeichert sind. Eine Ausnahme
stellt lediglich {\sf Graph} dar, dessen Elemente in einer {\sf VarList}
gespeichert sind und der den Array-basierten {\sf Stack} als Hilfsstruktur
verwendet.
\item Der vierte Teil der Bibliothek besteht aus dem B-Baum ({\sf BTree}) und
seinen Komponenten. Im Gegensatz zu den ersten drei Teilen der Bibliothek
bildet in diesem Teil nur der B-Baum selbst einen abstrakten Datentyp, w"ahrend
die anderen Module durch eine Zerlegung der Funktionalit"at des B-Baumes
entstanden sind und nicht selbst"andig verwendet werden k"onnen. 
\item Im letzten Teil der Bibliothek befindet sich das mehrdimensionale
W"orterbuch ({\sf DDimDictionary}). Wie beim B-Baum wurde auch hier die
Gesamtfunktionalit"at in einzelne Module aufgeteilt. {\sf DDimDictionary} ist
die Schnittstelle dieses abstrakten Datentyps zur Mehrbereichssuche. Die Daten
des W"orterbuches werden in einer speziell zu diesem Zweck entworfenen Liste
{\sf DDimDicPartList} gespeichert, die auch einzeln als abstrakter Datentyp
verwendbar w"are. Die "ubrigen Module sind wie beim B-Baum nicht selbst"andig
verwendbar. 
\end{itemize}

\renewcommand{\epsfsize}[2]{0.77#1} 
\begin{figure}[hbt]
\begin{center} 
\leavevmode
\epsfxsize=14cm
\epsffile{../Bilder/thorsten/Postscript/Bulklib.ps}
\end{center}
\caption{Bibliothek f"ur Massendaten des Tycoon-Systems} \label{Bulklib}
\end{figure}

\subsubsection{Vorgehensweise bei der Implementierung von Bibliotheken in
Tycoon} 
Innerhalb der Bibliothek lassen sich drei Programmierstile in Bezug auf die
Realisierung der jeweiligen abstrakten Datentypen erkennen:
\begin{itemize}
\item[1. ] Ein abstrakter Datentyp, die Schlange ({\sf Queue}), ist ohne
Verwendung eines anderen abstrakten Datentyps entstanden. Diese v"ollige
Neuentwicklung der gesamten Funktionalit"at l"a"st eine
m"ogliche Wiederverwendung beispielsweise der Liste v"ollig au"ser acht. Die
Schlange wird auch selbst innerhalb der Bibliothek nicht verwendet. 
\item[2. ] Der gr"o"ste Teil der Bibliothek (Teil 2 und 3) besteht aus
Paaren von abstrakten Datentypen, bei denen einer die
Speicherung der Elemente "ubernimmt, w"ahrend ein zweiter eine andere
Schnittstelle f"ur den Zugriff auf diese Daten unter Verwendung der
Schnittstelle des ersten abstrakten Datentyps realisiert. Diese Vorgehensweise
entspricht der Darstellung in Abbildung \ref{Mauer}.
Allerdings zeigt sich in der Bibliothek des Tycoon-Systems, da"s die
Schichtung "uber dem Repr"asentationstyp zur Speicherung der Elemente in der
Regel auf einen weiteren abstrakten Datentyp beschr"ankt ist. Ausnahmen von
dieser Regel sind nur die abstrakten Datentypen, die unter Verwendung des
dynamischen Feldes ({\sf DynArray}), welches auf einem Feld basiert, realisiert
wurden.
\item[3. ] Wiederum eine andere Art der Realisierung zeigt sich beim B-Baum und
dem mehrdimensionalen W"orterbuch (Teil 4 und 5 in Abbildung 
\ref{Bulklib}). Die Vorgehensweise bei diesen beiden Teilen der Bibliothek
entspricht einer Kombination aus der Aufteilung in Komponenten und der
Speicherung der Daten in einem Repr"asentationstyp analog zu der unter Punkt 2
beschriebenen Vorgehensweise. 

Die Realisierung von abstrakten Datentypen dieser hohen
Komplexit"at erfolgt vermutlich in zwei Schritten. Zun"achst wird ein
geeigneter abstrakter Datentyp zur Speicherung der Elemente des
Ziel-Datentyps gew"ahlt (B-Baum) oder neu erstellt (mehrdimensionales
W"orterbuch). 
In einem weiteren Schritt erfolgt eine Aufteilung der umfangreichen und
komplexen Funktionalit"at des Ziel-Datentyps in mehrere einzelne Komponenten.
Nach der Realisierung der einzelnen Komponenten in jeweils einem Modul kann der
Ziel-Datentyp unter Wiederverwendung der Komponenten aus diesen
zusammengesetzt werden\footnote{In Bezug auf das mehrdimensionale
W"orterbuch, das von den Autoren dieser Arbeit realisiert wurde
\cite{LotRoem94}, handelt es sich bei diesem Absatz um einen Erfahrungsbericht,
beim B-Baum \cite{She94} um eine Vermutung.}. 

Typisch f"ur diese Vorgehensweise ist das Entstehen von zahlreichen nicht
selbst"andig verwendbaren Modulen. Da diese Module nicht als ungeeignet zum
selbst"andigen Einsatz gekennzeichnet sind, kann ein im Verzeichnis nach einem
passenden abstrakten Datentyp suchender Benutzer der Bibliothek durch diese
Dateien verwirrt werden. 
\end{itemize}

Die beschriebenen Beobachtungen in der Bibliothek f"ur Massendaten lassen auf
ein typisches Vorgehen der Softwareentwicklung in einer modulorientierten
Bibliothek schlie"sen. Ein Programmierer, der einen neuen abstrakten Datentyp
realisieren m"ochte, sucht zun"achst nach einem geeigneten und m"oglichst
bereits implementierten abstrakten Datentyp zur Datenrepr"asentation. Nach
einem Vergleich der zur Verf"ugung stehenden abstrakten Datentypen und ihrer
angebotenen Operationen erfolgt die Festlegung auf genau einen solchen
Datentyp. Die Daten des neuen abstrakten Datentyps werden im bereits
implementierten gespeichert. Der neue abstrakte Datentyp wird anschlie"send
durch Operationen auf dem alten realisiert. 

\subsection{Bewertung modulorientierter Bibliotheken}
Modulorientierte Programmierung scheint besonders geeignet zu sein, um
Schichtenarchitekturen zu entwerfen und realisieren, bei denen
an den "Uberg"angen von einer Schicht zur n"achsten ein Wechsel der
Repr"asentation der Daten erfolgt. Da dieser Wechsel gew"unscht ist, f"uhrt
die Kapselung der Daten nicht zu einer Ineffizienz des Systems. 

Doch trotz der erheblichen Vorteile gegen"uber einer monolithischen
Softwareentwicklung ist Modulorientierung wegen der damit verbundenen Nachteile
nicht f"ur jede Anwendungsform das geeignete Paradigma. Softwarebibliotheken
sollten u.a. "ubersichtlich und erweiterbar, ihre Funktionalit"at kombinierbar
sein. Die Eigenschaften modularer Sprachen stehen diesen Zielen entgegen
und verhindern ihre Realisierung in modulorientierten Bibliotheken durch den
vorherrschenden Gedanken der Trennung und Kapselung und die Einschr"ankung der
Wiederverwendung auf eine Benutztbeziehung. Es ist nicht m"oglich, auch
Designentscheidungen oder Eigenschaften erneut zu verwenden, wie etwa beim
Erben in objektorientierten Sprachen \cite{Kli86}. Zus"atzlich fehlt
modulorientierter Programmierung eine Unterst"utzung f"ur die Kombination von
Funktionalit"at. 

Inkrementelle Erweiterung ist problematisch und der Grad der Wiederverwendung
innerhalb der Bibliothek bleibt wegen der Aufteilung in disjunkte, stark
spezialisierte Komponenten gering, so da"s mehrfach "ahnlich
implementierte Funktionalit"at die Wartbarkeit reduziert. Fehlende Beziehungen
zwischen "ahnlichen abstrakten Datentypen bedeuten, da"s Funktionalit"at unter
verschiedenen Namen angeboten werden kann. Modulorientierten Bibliotheken fehlt
somit eine Unterst"utzung der Standardisierung.  Der Benutzer einer
modulorientierten Bibliothek wird bei der Auswahl des von ihm zu verwendenden
abstrakten Datentyps nicht von der Struktur der Bibliothek unterst"utzt. Die
abstrakten Datentypen der Bibliothek stehen nebeneinander und die Struktur der
Bibliothek gibt keine Hinweise auf zu erwartende Eigenschaften. Weiterhin fehlt
eine einfache Sicht auf komplizierte Schnittstellen und es sind nicht alle
Module selbst"andig nutzbar. Modulorientierte Bibliotheken erf"ullen somit
die in Kapitel \ref{SoftBibs} geforderten Anforderungen nicht vollst"andig. 

\section{Objektorientierte Softwarebibliotheken} \label{ObjBib}
Dieses Kapitel beschreibt die grundlegenden Verfahren und Ziele der
objektorientierten Programmierung. Ein besonderes Augenmerk wird auf Verfahren
liegen, die f"ur die Entwicklung von Beh"alterklassen verwendet werden. 

\subsection{Terminologie}
Mit dem Aufkommen des Begriffs "`objektorientiert"' entstand gleichzeitig eine
neue Terminologie. Die Notwendigkeit der Einf"uhrung dieser neuen Terminologie
ist nicht unumstritten\footnote{\cite{RW94}: "`Mit dem Ziel, ein neues
Paradigma f"ur das Programmieren im Gro"sen einzuf"uhren, folgte eine
Umbenennung vieler altbekannter Konzepte; so wurden aus Variablen Instanzen,
aus Prozeduren Methoden und aus Prozeduraufrufen das Senden von
Meldungen."'}. 
Dennoch scheint es heute nahezu unm"oglich, "uber das Thema Objektorientierung
zu schreiben, ohne auf die weithin verbreiteten Begriffe zur"uckzugreifen. Aus
diesem Grund erl"autern die  folgenden Abschnitten die in der
objektorientierten Programmierung gebr"auchlichen Begriffe. 

\subsubsection{Objekte, Eigenschaften und Methoden}
Ein Objekt ist eine nach au"sen abgeschlossene Einheit aus Daten und
Funktionalit"at. Die Daten des Objekts werden in lokalen, zum Objekt
geh"orenden Variablen gespeichert. Der Inhalt dieser Variablen bestimmt den
Zustand des Objekts. Die lokalen Variablen werden nach au"sen verborgen und
sind nur durch die Ausf"uhrung von Unterprogrammen ver"anderbar. Die auf die
Daten eines Objekts anwendbaren Unterprogramme werden Methoden genannt.

Ein Objekt f"uhrt eine seiner Methoden aus, wenn es von einem anderen Objekt
durch das Senden einer entsprechenden Nachricht hierzu aufgefordert wird.
Voraussetzung ist, da"s die in der Nachricht verlangte Methode zur
Schnittstelle des die Nachricht empfangenden Objekts geh"ort
\cite{Ott91}\footnote{"Ahnliche Darstellungen der Thematik finden sich auch in
\cite{WWW90,Col94,Kil93,Dec95,Coa94,Coa91,Bea94,Cook91,Boo94}.}. Eine 
vereinfachende Terminologie spricht davon, da"s eine Methode an ein Objekt
gesendet wird. Dies ist jedoch kein wesentlicher Unterschied, entscheidend
ist, da"s Objekte von anderen zu Aktivit"aten aufgefordert werden.
Objekte stehen damit in einer "`Benutztbeziehung"' zueinander, da sie Dienste
erbringen. 

Viele objektorientierte Programmiersprachen, z. B.Eiffel, C++ und die im Rahmen
dieser Arbeit benutzte Sprache TooL, bieten eine weitergehende Verfeinerung der
Kontrolle des Zugriffs auf Variablen und Methoden an, indem sie eine
Unterscheidung in private und "offentliche Methoden bzw. Variablen erlauben.
Private Methoden k"onnen dabei im Gegensatz zu den "offentlichen nicht von
anderen Objekten aufgerufen werden, sondern nur vom Objekt selbst. "Offentliche
Variablen k"onnen im Unterschied zu den bisher beschriebenen Variablen auch von
anderen Objekten ohne den Aufruf einer Methode des Objekts direkt ver"andert
werden.

Durch die Kapselung von Daten in privaten Variablen und den Zugriff "uber
"offentliche Methoden, der {\it Schnittstelle} des Objekts, erh"alt ein Objekt
die M"achtigkeit eines abstrakten Datentyps. Abbildung \ref{Objekt}
verdeutlicht die im Zusammenhang mit dem Objektbegriff auftretende
Terminologie.

Eine Unterst"utzung der Abstraktion bedeuten abstrakte Methoden ({\it deferred
method}). Eine Abstrakte Methode ist ein Methodenrumpf, der die Signatur der
Methode festlegt, aber noch keine Implementierung f"ur die Funktionalit"at der
Methode angibt.
\renewcommand{\epsfsize}[2]{1.0#1}
\begin{figure}[hbt]
\begin{center} 
\leavevmode
\epsfxsize=14cm
\epsffile{../Bilder/thorsten/Postscript/Objekt.ps}
\end{center}
\caption{Begriffskl"arung: Objekt (nach [Otto 91])}
\label{Objekt} 
\end{figure}

\subsubsection{Klassen}
Eine Klasse kann als Schablone zur Erzeugung von Objekten verstanden werden.
Eine Klasse erzeugt dabei gleichartige Objekte, d. h. die Objekte einer Klasse
besitzen dieselben Methoden und Variablen. Lediglich die in den
Variablen gespeicherten Eigenschaften unterscheiden sich von Objekt zu Objekt.
In Systemen, in denen Klassen ebenfalls Objekte sind, ben"otigen
Klassen klassenspezifische Eigenschaften und Methoden, um Objekte erzeugen zu
k"onnen. Die Klasse speichert die zu ihren Objekten geh"orenden Methoden. Auf 
alle Objekte einer Klasse sind deshalb dieselben Methoden anwendbar. Objekte
werden als Exemplar ihrer Klasse bezeichnet.

Klassen, die abstrakte Methoden enthalten oder erben und nicht implementieren
werden als abstrakte Klasse bezeichnet ({\it abstract class}). Von abstrakten
Klassen existieren keine Exemplare, sie dienen der Unterst"utzung der
Abstraktion. Die Ausdrucksm"achtigkeit der in den abstrakten
Klassen zu definierenden Bedingungen ist in den objektorientierten Sprachen
unterschiedlich. In allen objektorientierten Sprachen k"onnen in den abstrakten
Klassen abstrakte Methoden definiert werden. Durch die Definition einer Methode
werden alle Subklassen gezwungen, diese Methode zu implementieren, wenn die
Subklasse nicht selbst wieder abstrakt sein soll. Die Definition einer
abstrakten Methode in einer Klasse stellt also die Bedingung dar, da"s diese
Methode zur Schnittstelle aller unter der abstrakten Klasse h"angende
Subklassen geh"oren mu"s.

Einige objektorientierte Sprache, z.B. Eiffel, besitzen die M"oglichkeit, zu
den Methoden auch Vor- und Nachbedingungen zu definieren. Diese Bedingungen
werden wie die "ubrigen Eigenschaften einer Klasse auch vererbt. Durch die
Definition von Vor- oder Nachbedingung in den abstrakten Methoden einer
abstrakten Klasse kann also nicht nur festgelegt werden, da"s die entsprechende
Methode zur Schnittstelle aller Subklassen geh"oren mu"s, sondern der
Entwickler der Bibliothek kann auch die Semantik der in den Subklassen zu einem
sp"ateren Zeitpunkt zu implementierenden Methoden spezifizieren.

Abbildung \ref{Klasse} verdeutlicht den Klassenbegriff der objektorientierten
Programmierung. Die Abbildung zeigt zwei Exemplare der Klasse PKW. Beide
Exemplare speichern zu den in der Klasse mit Namen angegebenen Variablen die
jeweils zugeh"origen Werte. Auf beide Exemplare sind die bei der Klasse 
abgelegten Methoden ("`beschleunigen"', "`bremsen"' und "`polizeilich
ummelden"') anwendbar. 
\renewcommand{\epsfsize}[2]{1.0#1}
\begin{figure}[hbt]
\begin{center} 
\leavevmode
\epsfxsize=14cm
\epsffile{../Bilder/thorsten/Postscript/Klasse.ps}
\end{center}
\caption{Objekte derselben Klasse (nach [Otto 91])}
\label{Klasse} 
\end{figure}


\subsubsection{Vererbung und Klassenhierarchie}
Vererbung bezeichnet den Vorgang der Ableitung einer Klasse von einer bereits
bestehenden Klasse. Einige objektorientierte Programmiersprachen, z.B. Eiffel,
C++ und TooL, bieten Mehrfachvererbung an, die es erlaubt, eine Klasse von
mehreren bereits bestehenden Klassen abzuleiten. Wenn eine Klasse von einer
anderen erbt, bezeichnet man die beerbte Klasse als Oberklasse 
({\it super class}) der erbenden Klasse. Die erbende Klasse ist Subklasse ihrer
Oberklasse. Abbildung \ref{Hierarchie} zeigt ein Beispiel f"ur eine Hierarchie
von Klassen. 
\renewcommand{\epsfsize}[2]{1.0#1}
\begin{figure}[hbt]
\begin{center} 
\leavevmode
\epsfxsize=14cm
\epsffile{../Bilder/thorsten/Postscript/Hierarchie.ps}
\end{center}
\caption{Beispiel einer Klassenhierarchie (nach [Otto 91])}
\label{Hierarchie} 
\end{figure}

Erh"alt ein Objekt eine Nachricht, so wird zun"achst festgestellt, ob die
zu dieser Nachricht geh"orende Methode in der Klasse des Objekts selbst
definiert worden ist. Wenn dies der Fall ist, kann die Klasse des Objekts die
Methode selbst ausf"uhren. Ist dies nicht der Fall, so handelt es sich um
eine geerbte Methode\footnote{Wenn die Methode auch in den Oberklassen nicht
definiert ist, gibt es einen Laufzeitfehler. Der gr"o"ste Teil der "Ubersetzer
f"ur objektorientierte Sprachen erkennt solche Fehler jedoch bereits bei der
"Ubersetzung der Programme.}. Die entsprechende Methode der Oberklasse kann
jedoch auf den Variablen eines Objekts der Subklasse arbeiten. Da die
geerbten Methoden der Oberklassen auch f"ur Objekte der Subklasse anwendbar
sind, kann man sie als Teil der Schnittstelle der Objekte der Subklasse
ansehen. F"ur das Objekt und seinen Benutzer bedeutet es keinen Unterschied, ob
die Methode in der Klasse selbst definiert oder aus einer Oberklasse geerbt
wird. Vererbung ist damit ein Mechanismus zur Erweiterung von Klassen.
Exemplare der erbenden Klasse erhalten durch den Vorgang des Erbens alle
Eigenschaften der Oberklasse, wodurch die Anwendung aller Methoden der
Oberklasse auf die Variablen der Subklasse m"oglich ist. In einem
weiteren Schritt ist es m"oglich, die geerbten Methoden f"ur die Anwendung auf
Exemplare der erbenden Klasse zu ver"andern oder der Schnittstelle neue, auf
die Exemplare der Oberklasse nicht anwendbare Methoden hinzuzuf"ugen. 

Abbildung \ref{Vererbung} zeigt das Senden einer Nachricht an das Objekt einer
erbenden Klasse. Ein Exemplar (das Taxi mit dem Kennzeichen HH-BL-1007) der
Klasse Taxi empf"angt die Nachricht, die Geschwindigkeit um 20 km/h zu
reduzieren. Da die Methode "`bremse"' f"ur alle Personenkraftwagen aufrufbar
sein soll, wurde sie bereits in der Klasse PKW definiert. Auf das Exemplar der
Klasse Taxi wird somit eine geerbte Methode aus der Klasse PKW angewendet.  
\renewcommand{\epsfsize}[2]{1.0#1}
\begin{figure}[hbt]
\begin{center} 
\leavevmode
\epsfxsize=14cm
\epsffile{../Bilder/thorsten/Postscript/Vererbung.ps}
\end{center}
\caption{Vererbung (nach [Otto 91])}
\label{Vererbung} 
\end{figure}


\input{TypisierungUndPolymorphismus}

   \subsection{Vorteile des objektorientierten Ansatzes f"ur Bibliotheken}
Die Einf"uhrung des Paradigmas objektorientierter Programmierung und Analyse
sowie objektorientierten Designs bringt im Vergleich mit dem
modulorientierten Ansatz Vorteile f"ur die Erstellung qualitativ
hochwertiger Software, die in den folgenden Abschnitten im Hinblick auf die
Gestaltung und Entwicklung von Softwarebibliotheken f"ur Massendatentypen
untersucht werden. 

\subsubsection{Orientierung an den Daten statt an Funktionen}
Die Objektorientierte Programmierung versteht die Programmausf"uhrung als eine
Simulation des Verhaltens von realen oder imagin"aren Teilen der Welt.
Objektorientierte Programmierung bedeutet die Suche nach geeigneten
Abstraktionen f"ur die Objekte der Anwendungsumgebung. W"ahrend bei der
modulorientierten Programmierung eine funktionale Zerlegung und anschlie"sende
Schichtung vorherrscht, erfolgt die Abstraktion bei objektorientierter
Programmierung "uber den Daten \cite{Mey93}. Die Abstraktionen werden in
Klassen zusammengefa"st. Abbildung \ref{Zerlegung} zeigt die unterschiedlichen
Vorgehensweisen.
\renewcommand{\epsfsize}[2]{1.0#1}
\begin{figure}[hbt]
\begin{center} 
\leavevmode
\epsfxsize=14cm
\epsffile{../Bilder/thorsten/Postscript/Zerlegung.ps}
\end{center}
\caption{Konventionelle und objektorientierte Zerlegung eines Problems (nach
[Otto 91])} 
\label{Zerlegung} 
\end{figure}

Ein wesentlicher Vorteil dieses Ansatzes ist es, Sichtweisen aus der
Anwendungsumgebung in die Softwareerstellung "ubernehmen zu k"onnen. Das
objektorientierte Paradigma ist daher durchg"angig anwendbar auf Analyse,
Design und Implementierung und bietet damit eine einheitliche Sicht auf
die verschiedenen Phasen der Systementwicklung. Diese Vereinheitlichung l"a"st 
Programme verst"andlicher werden und erh"oht Wartbarkeit und Erweiterbarkeit.

Die Fokussierung des Paradigmas der Objektorientierung auf die
Abstraktion "uber den (Daten-) Objekten der realen Welt bewirkt eine leichtere
Anpa"sbarkeit der Software an Ver"anderungen der Anforderungen von Benutzern.
Die bei modulorientierter Programmierung gebildeten Abstraktionen "uber der
Funktionalit"at des Systems werden mit gro"ser Wahrscheinlichkeit bei
Ver"anderungen der Benutzeranforderungen ebenfalls zu ver"andern sein, da neue 
Anforderungen der Benutzer sich in der Regel auf eine Ver"anderung der
Funktionalit"at beziehen. Die an der Probleml"osung beteiligten Daten und mit
ihnen auch die Abstraktionen objektorientierter Programmierung bleiben jedoch
oft "uber l"angere Zeit unver"andert. Es ist daher in der objektorientierten
Programmierung leichter m"oglich, das System durch eine Erweiterung der
urspr"unglichen Funktionalit"at auf denselben Datenabstraktionen an neue
Anforderungen anzupassen.



      \subsubsection{Vorteile durch Vererbung} \label{WiederVererbung}
Neben die Benutztbeziehung tritt in objektorientierten Bibliotheken eine
Erbbeziehung, woraus eine Verbesserung der M"oglichkeiten zur Wiederverwendung
resultiert. Vererbung bringt Vorteile in Bezug auf die Kombinierbarkeit von
Funktionalit"at, die inkrementelle Erweiterung von Funktionalit"at und
Repr"asentation, die Wiederverwendung von Konzepten, sowie die Klassifizierung.
Diese Vorteile werden im folgenden n"aher erl"autert. 

\vspace{3mm}
\noindent {\bf Kombinierbarkeit von Funktionalit"at} \newline

\noindent Eine Kombination von Funktionalit"at kann effizient erfolgen, wenn
die Funktionalit"at noch nicht auf eine Repr"asentationsform der Daten
festgelegt ist. Eine derartige Entkoppelung erm"oglichen objektorientierte
Sprachen durch das Konzept der abstrakten Klasse, deren abstrakte Methoden
bereits f"ur andere Methoden benutzbar sind. "Ublich ist daher, die
Funktionalit"at, die von der sp"ater erfolgenden Wahl der Repr"asentationsform
abh"angig ist, als abstrakte Methode anzugeben, so da"s darauf aufbauend der
gr"o"ste Teil der Funktionalit"at bereits in der abstrakten Klasse
implementiert werden kann. Mehrfacherben erm"oglicht die Kombination von
Funktionalit"at mehrerer abstrakter Klassen, wobei eine anschlie"sende
Instantiierbarkeit der so entstehenden Klasse die Implementierung aller
abstrakten Methoden verlangt. Mit der Implementierung aller Methoden ist in der
Regel eine Festlegung auf eine Repr"asentationsform der Daten n"otig.

F"ur die Realisierung einer Bibliothek zur Verwaltung von
Massendaten bedeutet dies, da"s ein gro"ser Teil der Funktionalit"at losgel"ost
von der Frage der Repr"asentationsform der Daten in den weiter oben liegenden
abstrakten Klassen der Klassenhierarchie implementiert werden kann und
kombinierbar bleibt. Erst instantiierbare Klassen f"ur Endbenutzer der
Bibliothek m"ussen die Repr"asentationsform festgelegt und die verbleibenden
abstrakten Methoden realisieren. 

\vspace{3mm}
\noindent {\bf Inkrementelle Erweiterbarkeit} \newline

\noindent Um die Funktionalit"at einer Subklasse gegen"uber ihrer Oberklasse
auszuweiten, ist es ausreichend, ihrer Schnittstelle Methoden hinzuzuf"ugen.
Weiterhin kann in der Subklasse die Verhaltensweise geerbter Methoden
gegen"uber ihrer Verhaltensweise in der Oberklasse ver"andert werden. Auch die
inkrementelle Erweiterung der Repr"asentation gegen"uber der Oberklasse ist in
der Subklasse m"oglich. Hierbei ist es ausreichend, die Ver"anderungen
ausschlie"sliche in der Subklasse durchzuf"uhren. Da die urspr"ungliche 
Klasse unver"andert bestehen bleibt, ist auch die Funktionsf"ahigkeit von
anderen Klassen, welche die urspr"ungliche Klasse  ebenfalls beerben oder sie
benutzen, durch "Anderungen in der abgeleiteten Klasse nicht gef"ahrdet. Hinzu
kommt, da"s durch die Vererbung kein doppelter Code entsteht.


Die Verhaltensweise geerbter Methoden kann durch "Uberschreiben
ver"andert werden. Hierbei ist ist die M"oglichkeit des Aufrufs von Methoden
der Oberklasse hilfreich, die auch besteht, wenn die gleichnamige Methode in
der Subklasse ver"andert wurde. Da sich die Funktionalit"at beider Methoden oft nur in Nuancen
unterscheidet, ist die urspr"ungliche Methode in vielen F"allen bei der
Implementierung der neuen Methode von Nutzen. Dadurch erh"oht sich auch
innerhalb der Bibliothek der Grad der Wiederverwendung. Objektorientierung
vermeidet somit die in modulorientierten Bibliotheken auftretenden Probleme bei
der inkrementellen Erweiterung. 

\vspace{3mm}
\noindent {\bf Abstraktion und Wiederverwendung von Konzepten} \newline

\noindent Durch die Entkoppelung von Funktionalit"at und Repr"asentation der
Daten ist es in objektorientierten Bibliotheken m"oglich, in einer
Klassenhierarchie so etwas wie abstrakte Konzepte zu implementieren, ohne eine
konkrete Speicherungsform der Daten zu ber"ucksichtigen. Die Kombination
derartiger "`Konzeptklassen"' durch Mehrfachvererbung erzeugt instantiierbare
Klassen f"ur den Benutzer. Kombinierbarkeit und Wiederverwendung von Konzepten
stehen somit in einem engen Zusammenhang und erlauben Wiederverwendung auf
einem h"oheren Abstraktionsniveau, als es in modulorientierten Bibliotheken der
Fall ist \cite{KLL93}. 

\vspace{3mm}
\noindent {\bf Klassifizierung der Funktionalit"at} \newline

\noindent Vererbung erleichtert nicht nur dem Anbieter die Erstellung
"anderungsfreundlicher Bibliotheken, sondern bringt auch dem Benutzer wichtige
Vorteile. Von der Wurzel des Vererbungsgraphen aus betrachtet, nimmt die
Komplexit"at der Klassen mit jedem Vererbungsschritt zu. Diese Eigenschaft
hilft dem Benutzer bei der Auswahl der f"ur sein Problem zu verwendenden
Klasse. Dabei kann sich der Benutzer von den Anforderungen an die Klasse leiten
lassen.

Der Benutzer kann eine Klasse mit bestimmten Eigenschaften finden,
indem er dem Vererbungsgraphen von der Wurzel aus folgt und dabei in den Pfad
absteigt, dessen Klassen die gew"unschten Eigenschaften haben. Vererbung,
inkrementelle Verfeinerung und Spezialisierung der Eigenschaften der Klassen
unterst"utzen den Benutzer also bei der Auswahl und Suche nach
geeigneten Klassen als Leistungserbringer f"ur die L"osung seiner Aufgaben. 

\vspace{3mm}
\noindent {\bf Einfache Sicht auf komplexe Objekte} \label{EinfacheSicht}
\newline 

\noindent Eine objektorientierte Bibliothek bietet ihren Benutzern
Schnittstellen 
verschiedener Komplexit"at an. Mit zunehmender Entfernung einer Klasse von der
Wurzel des Vererbungsgraphen steigt der Grad der M"achtigkeit und
Spezialisierung der Schnittstelle der Klasse und damit auch ihre Komplexit"at.
Da die komplexeren Klassen durch Vererbung aus den allgemeineren hervorgehen,
k"onnen die Objekte der Subklasse wegen des Inklusionspolymorphismus
auch im Kontext der Oberklasse auftreten. Der Benutzer kann somit auf die
Objekte der spezielleren Klassen auch die Methoden der allgemeineren Klassen
anwenden. Im Gegensatz zu modulorientierten Bibliotheken ist daher bei einer
Vielzahl von Operationen ein Ausweichen auf eine einfachere Schnittstelle
m"oglich. 

\vspace{3mm}
\noindent {\bf Gemeinsame Sicht auf verschiedene Klassen}
\label{GemeinsameSicht}\newline 

\noindent Durch den mit der Vererbungsbeziehung der Klassen der Bibliothek
einhergehenden 
Inklusionspolymorphismus gewinnt der Benutzer jedoch nicht nur eine einfachere,
sondern auch eine gemeinsame Sicht auf Objekte verschiedener Klassen. Durch
dieses einheitliche, auf verschiedene Klassen anwendbare Protokoll vereinfacht
sich der Umgang mit Objekten verschiedener komplexer Klassen. Nur wenn eine
Methode n"otig ist, die in der  gemeinsamen Sicht noch nicht vorhanden ist,
mu"s die komplexe Sicht des jeweiligen Objekts selbst verwendet werden, in
allen anderen F"allen ist jedoch die Verwendung der Oberklassen-Schnittstelle
ausreichend.

      \subsubsection{Kapselung}
Auch in der objektorientierten Programmierung werden Daten gekapselt. Der
Zugriff auf die Daten eines Objekts ist nur "uber die Schnittstelle des Objekts
m"oglich. Eine Ausnahme von dieser Regel ist jedoch, da"s auch die Exemplare
einer erbenden Klasse auf die von der Oberklasse definierten Variablen
zugreifen 
d"urfen, ohne die Methoden einer Schnittstelle verwenden zu m"ussen.
Diese Einschr"ankung der Kapselung ist jedoch dann unsch"adlich, wenn die
geerbten Variablen der Oberklasse als durch die Vererbung auch zur
erbenden Klasse geh"orend betrachtet werden. Diese Betrachtungsweise scheint
sachgerecht, da die erbende Klasse von ihrer Oberklasse abgeleitet worden
ist. Zwar m"ussen Subklassen die in den Oberklassen bereits
definierten Variablen nicht neu auff"uhren oder definieren, doch diese
Variablen geh"oren durch die Vererbung auch zu den erbenden Klassen und sind
somit zu behandeln wie dort eingef"uhrte Variablen. Es scheint daher
angemessen, auch in der objektorientierten Programmierung von einer Kapselung
der Daten zu sprechen. Probleme, die sich aus der Durchbrechung der Kapselung
ergeben k"onnen, beschreibt der n"achste Abschnitt.

\subsection{Formen der Vererbung}\label{VererbungsFormen}
Bei der Entwicklung von Beh"alterklassen mu"s zwischen der Sicht der
Bibliotheksentwickler und der Sicht der Benutzer unterschieden
werden. Besonders bei der Verwendung der Vererbung k"onnen bei unvorsichtiger
Anwendung Nachteile f"ur Benutzer entstehen. 
In der Literatur \cite{DissIngrid} werden im wesentlichen zwei
Formen der Vererbung unterschieden. Dies sind {\it Implementierungsvererbung}
und {\it Konzeptvererbung}. \cite{Tr95} nennt {\it Typvererbung} als dritte
Form der Vererbung. 
Die folgenden Abschnitte erl"autern die verschiedenen Formen der Vererbung.
Dabei ist zu kl"aren, welche Motivation hinter der jeweiligen Form steht und
welche Auswirkungen sie auf die Qualit"at einer Bibliothek haben. 

\subsubsection{Implementierungsvererbung} \label{Implementierungsvererbung}
Die Konzepte des abstrakten Datentyps und der Vererbung sind teilweise
kontr"ar. Bei der Vererbung werden die beim abstrakten Datentyp verborgenen
Details f"ur den Erben sichtbar. Somit setzt Vererbung eine Verletzbarkeit des
Kapselungsprinzips voraus. 

Die Durchbrechung der Kapselung erm"oglicht der erbenden Klasse die
Redefinition geerbter Methoden und die Implementierung neuer Methoden unter
Verwendung geerbter Repr"asentationen. Die Verletzung der strengen Kapselung
birgt jedoch eine nicht zu untersch"atzende Gefahr in sich. Wenn in der
Oberklasse an der vererbten internen Repr"asentation Ver"anderungen
vorgenommen werden, m"ussen auch die Implementierungen der erbenden Klassen
erneut auf Korrektheit untersucht werden, da sie durch die Ver"anderung
ung"ultig geworden sein k"onnten \cite{DissIngrid}.

Erbende Klassen k"onnen jedoch nur dann ung"ultig werden, wenn sie geerbte 
interne Repr"asentationen nutzen. Wenn die erbende Klasse auf die internen
Repr"asentationen nur "uber ebenfalls geerbte Methoden der Oberklasse
zugreift, bleibt sie korrekt, falls die Semantik der Methoden nicht ver"andert
wird. Benutzende Wiederverwendung ist also von Ver"anderungen auf Seiten des
Diensterbringers weniger betroffen als erbende Wiederverwendung \cite{Sny86}.

Eine M"oglichkeit der Vermeidung direkten Zugriffs auf geerbte interne
Repr"asentationen liegt in der Einf"uhrung von Methoden in der Oberklasse,
deren Aufruf in der Subklasse den direkten Zugriff ersetzt. Da diese Methoden
f"ur Benutzer der Klasse unerheblich sind, brauchen diese Methoden auch nur den
erbenden Klassen zur Verf"ugung gestellt zu werden. Derartige private Methoden
werden vorgeschlagen \cite{Sny86,DissIngrid}, um die Idee des abstrakten
Datentyps auch in der objektorientierten Programmierung zu verwenden. In
\cite{Sny86} wird dabei sogar von einer objektorientierten Programmiersprache
verlangt, den Zugriff auf geerbte Variablen einer Klasse nur durch von
der Oberklasse zur Verf"ugung zu stellende Methoden zu erlauben.

In \cite{Tr95} werden die Probleme, die beim Einsatz von Vererbung mit dem Ziel
der Codewiederverwendung entstehen, am Beispiel einer Liste und einer
sortierten Liste beschrieben. Problematisch ist die Ableitung der sortierten
Liste mittels Implementierungsvererbung von der Liste. Zwar ist auch die
sortierte Liste eine Liste, so da"s es grunds"atzlich m"oglich ist, die
Eigenschaften der Liste zu erben und die Sortierung hinzuzuf"ugen, wobei
beispielsweise die Elemente einf"ugende Methode zu "uberschreiben w"are. Diese
Methode mu"s in der Subklasse {\sf SortierteListe} die Semantik dahingehend "andern,
da"s das neue Element an der der Sortierung entsprechenden Stelle in die Liste
eingef"ugt wird.

Es werden allerdings in einer allgemeinen Liste weitere Methoden zum Einf"ugen
von Elementen vorhanden sein. Dies k"onnte zum Beispiel eine Methode sein, die
ein Element als erstes Element in die Liste einf"ugt. Die Semantik einer
solchen Methode ist aber in der sortierten Liste nicht mehr zul"assig, da sie
in einem direkten Widerspruch zu deren Eigenschaft der "`Sortiertheit"' steht. 

Wenn die sortierte Liste dennoch von der allgemeinen Liste abgeleitet werden
soll, so w"aren die geerbten und nun nicht mehr zul"assigem Methoden so zu
"uberschreiben, da"s sie zur Laufzeit eine Fehlermeldung ausgeben. Es ist
offenkundig, da"s dieses Vorgehen einen Widerspruch zum Ziel der Entwicklung
sicherer Software darstellt. Die Zul"assigkeit von Methodenaufrufen darf nicht
erst zur Laufzeit "uberpr"uft werden. 

Eine Alternative w"are es, die nicht mehr in das Konzept der durch
Implementierungsvererbung gewonnenen Subklasse passenden geerbten Methoden aus
der Schnittstelle der Subklasse zu entfernen. Einige objektorientierte Sprachen
bieten zu diesem Zweck spezielle Mechanismen an, mit denen der Aufruf geerbter
Methoden unterbunden werden kann. Doch diese scheinbare Alternative
f"uhrt zu einem Verlust an "Ubersichtlichkeit. Es ist dann f"ur einen Benutzer
nicht mehr ohne weiteres feststellbar, welche Methoden in einer Klasse
"uberhaupt zur Verf"ugung stehen. 

Zwischen Klassen eine Vererbungsbeziehung mit dem Ziel der Wiederverwendung von
Code einzuf"uhren, liegt im Ermessen des Bibliotheksentwicklers. Die
Vererbungsbeziehung sollte besser verborgen bleiben, um eine leichtere
Revidierbarkeit der Entscheidung zu gew"ahrleisten \cite{DissIngrid}.

\subsubsection{Konzeptvererbung} \label{Konzeptvererbung}
Alternativ zur Implementierungsvererbung kann Vererbung jedoch auch als ein
Mechanismus zur Verfeinerung von Konzepten aufgefa"st werden, was als
Konzeptvererbung bezeichnet wird \cite{Sny86}. Da mit der
Konzeptspezialisierung eine Klassifikation von Eigenschaften der Klassen
einhergeht, die dem Benutzer die Verwendung der Bibliothek erleichtern soll,
ist die Sichtbarkeit der Konzeptvererbung in der Schnittstelle der beteiligten
Klasse erw"unscht.

Wenn in der Schnittstelle einer Klasse nicht nur Methoden, sondern auch
Variablen enthalten sind, werden nat"urlich auch diese vererbt. Deshalb
ist in einem solchen Fall keine klare Trennung zwischen 
Implementierungsvererbung und Konzeptvererbung mehr m"oglich. Beide Formen
der Vererbung treten dann gemischt auf \cite{DissIngrid}. 

Ist jeder Klasse ein Typ zugeordnet, so geht Konzeptvererbung mit 
einer Subtypbeziehung des Verhaltens der korrespondierenden Typen einher.
Auf diese Weise wird die Subtypisierung v"ollig unabh"angig von der
Wiederverwendung der Implementierung. Wegen des Kapselungsprinzips kann eine
durch Konzeptvererbung abgeleitete Klasse nach au"sen ein in Subtypbeziehung
zum Verhalten ihrer Oberklasse stehendes Verhalten anbieten, obwohl die
Implementierung von der Oberklasse v"ollig verschieden sein kann
\cite{DissIngrid}. 

In \cite{Sny86} findet sich als Beispiel die durch Konzeptvererbung
hergestellte Subtypbeziehung zwischen dem Verhalten einer Multimenge ({\sf
Bag}) und dem einer Menge ({\sf Set}), wobei die Implementierung beider Klassen
kaum "Ubereinstimmungen aufweist.

In \cite{Tr95} wird Konzeptvererbung am Beispiel der Liste und der
sortierten Liste erl"autert. Beiden Listen legen die in ihnen enthaltenen
Elemente geordnet ab. Bei der Liste ist die Ordnung extern, bei der sortierten
Liste intern , also durch den Algorithmus der einf"ugenden Methode bestimmt.
Nur bei der nicht sortierten Liste kann der Benutzer die Reihenfolge der
Elemente in der Liste durch die Reihenfolge des Einf"ugens der Elemente selbst
bestimmen. Eine die Eigenschaften klassifizierende Vererbungsbeziehung l"a"st
sich daher herstellen, indem von der Klasse mit geordneten Elementen je eine
Klasse mit intern bzw. extern geordneten Elementen als Vorg"anger f"ur die
Liste und die sortierte Liste abgeleitet wird. 

\subsubsection{Typvererbung}
In \cite{Tr95} wird noch eine dritte Form der Vererbung eingef"uhrt und als
Typvererbung bezeichnet. Bei dieser Form der Vererbung wird wegen der
Unvertr"aglichkeit einer Erbbeziehung zwischen Liste und sortierter Liste
auf eine Erbbeziehung verzichtet. Statt dessen wird eine gemeinsame Oberklasse
gebildet, welche die gemeinsamen Eigenschaften beider Listen enth"alt. Von
diesem Typ einer abstrakten Liste erben dann die Typen Liste und sortierte
Liste. Abbildung \ref{KlassifikationVonListen} aus \cite{Tr95} zeigt die
verschiedenen Formen der Vererbung angewendet auf Listen. 
\renewcommand{\epsfsize}[2]{1.0#1}
\begin{figure}[hbt]
\begin{center} 
\leavevmode
\epsfxsize=14cm
\epsffile{../Bilder/thorsten/Postscript/KlassifikationVonListen.ps}
\end{center}
\caption{Drei Formen der Vererbung} \label{KlassifikationVonListen}
\end{figure}

Als Fazit bleibt festzustellen, da"s aufgrund der in diesem Abschnitt
beschriebenen Nachteile Vererbung nicht mit dem alleinigen Ziel der
Implementierungs-Wiederverwendung benutzt werden sollte. 

\subsection{Ergebnis des Vergleichs der Grundstrukturen}
Durch Vererbung bieten objektorientierte Bibliotheken eine Verbesserung von
Wiederverwendung gegen"uber modulorientierten Bibliotheken bei gleichzeitiger
Betonung von Kombinierbarkeit und Erweiterbarkeit. Diese Eigenschaften f"uhren
sowohl f"ur den Anbieter als auch f"ur den Benutzer einer Bibliothek zu
Vorteilen. Hervorzuheben sind die einfache Sicht auf verschiedene komplexe
Objekte, Vereinheitlichung von Protokollen, Unterst"utzung inkrementeller
Erweiterungen sowie Unterst"utzung der Standardisierung von Benennungen.
Zus"atzlich bedeutet Objektorientierung die Orientierung an den gegen"uber der
Funktionalit"at eines Systems dauerhafteren Objekten der realen Welt in allen
Phasen der Systementwicklung.

Die Vorteile objektorientierter Bibliotheken legen nahe, f"ur die
Entwicklung einer Softwarebibliothek zur Verwaltung von Massendaten keine
modulorientierte, sondern eine objektorientierte Sprache zu verwenden. Aus
diesem Grund wurde im Rahmen dieser Diplomarbeit die bestehende
modulorientierte Bibliothek des Tycoon-Systems nicht "uberarbeitet oder
weiterentwickelt, sondern eine Bibliothek in der speziell zu diesem Zweck
entworfenen objektorientierten Programmiersprache TooL neu gestaltet und
implementiert. 




