Benutzer:Centic/Komponentenbasierte Programmierung/Ausarbeitung

aus Wikipedia, der freien Enzyklopädie

Komponenten und die objektorientierte Programmierung

Unsere Motivation

Obwohl objektorientierte und komponentenbasierte Programmierung viele Gemeinsamkeiten haben, ergeben sich durch die verschiedenen Konzepte unterschiedliche Ansätze, die beim Einsatz von Objektorientierter Programmierung als Grundlage für Komponentenbasierte Programmierung beachtet werden müssen. Objektorientierung verwendet Klassen und Objekte als zentrale Design-Elemente. Komponentenbasierte Programmierung hingegen versucht, in Anlehnung an Hardware-Komponenten, austauschbare, zuverlässige Bausteine (Komponenten) zur Assemblierung von Softwaresystemen zur Verfügung zu stellen.

Wir versuchen in dieser Arbeit, Besonderheiten der Komponentenbasierten Programmierung darzustellen und in Relation zum Paradigma der Objektorientierung zu setzen. Wir untersuchen dabei nicht eine konkrete Sprache/Bibliothek, sondern das Paradigma der Objektorientierung auf Tauglichkeit zur Umsetzung des Komponentenkonzepts. Als besonders wichtig erscheinen uns hier Ansätze, die die verschiedenen Abstraktionslevel von CBD (engl. component based development) und OOP (engl. object oriented programming) betrachten, wie in Abbildung ~\ref{fig:CBSE} dargestellt wird.

Das objektorientierte Paradigma

OOP wurde in den 80er Jahren des vorigen Jahrhunderts entwickelt, um die immer größere Komplexität von Softwareprojekten in den Griff zu bekommen. Durch rasch wachsende Anforderungen an Anwendungen geriet die bis dahin vorherrschende prozedurale Programmierung immer mehr an ihre Grenzen. Das Konzept der Objektorientierung versprach hier Abhilfe durch die Aufteilung der Aufgabe in einzelne Einheiten, welche als Objekte bezeichnet werden.

Diese Objekte sind Objekten in der realen Welt nachempfunden. Dies wird erreicht, indem in Objekten Daten und die auf diese Daten definierten Operationen zusammengefasst werden. Die Objekte interagieren miteinander, indem sie Nachrichten austauschen und sich gemäß diesen Nachrichten verhalten. Ein Programm ist demnach eine Menge von relativ eigenständigen Objekten, die miteinander auf die beschriebene Weise interagieren [Poetsch01]

Denkweise und Begriffe der objektorientierten Programmierung zeigten sich zuerst in Simula, einer Sprache für Simulationszwecke, die als erste (damals noch nicht so genannte) objektorientierte Verfahren einführte. Heute hat sich objektorientierte Programmierung durch Programmiersprachen wie Smalltalk, C++ und Java stark verbreitet.

Grundkonzepte

Die Grundlagen der objektorientierten Programmierung lassen sich durch einige grundlegende Konzepte erläutern. [Poetsch01] beschreibt die folgenden Grundkonzepte der Objektorientierten Programmierung:

Objektkonzept
Softwaresysteme werden als eine Menge kooperierender Objekte modelliert. Konzeptionell sind Objekte eigenständige Ausführungseinheiten, die auf Nachrichten reagieren können. Objekte haben eigene Operationen und einen eigenen Zustand. Die Ausführung eines OO-Programms besteht im Nachrichtenaustausch zwischen Objekten, dem Ändern des eigenen Zustandes und dem Erzeugen/Zerstören von Objekten. Konsequenz daraus sind im Vergleich zum prozeduralen Programmieren, dass eine Zusammenfassung von Daten, Zustand und Operationen in kleine Einheiten (Objekte) mit sauberer Schnittstelle nach außen erfolgt und dass das Ausführungsmodell inhärent für die parallele Ausführung geeignet ist.
Klassifikation
Objekte lassen sich anhand der öffentlichen Schnittstelle klassifizieren. Dies stellt die Grundlage für Abstraktion und Spezialisierung dar. \textbf{Abstraktion} bedeutet dabei die Zusammenfassung gemeinsamer Eigenschaften von Objekten/Typen zu einem neuen Typ unter Verkleinerung der Schnittstelle. Als \textbf{Spezialisierung} bezeichnet man die Erweitern von Objekten und Typen sowie ihrer Implementierung.

Sprachliche Realisierung

Die Grundkonzepte werden durch folgende Konzepte erweitert, um diese in eine Programmiersprache zu überführen.

Klassenkonzept (engl. Classes)
Eine Klasse ist eine Beschreibung der Eigenschaften, die die Objekte dieser Klasse haben sollen. Klassen werden in Verbindung mit Typisierungs- und Modularisierungskonzepten zur Deklaration von Objekteigenschaften verwendet. Saubere Schnittstellenbildung führt zur Kapselung.
Vererbungskonzept (engl. Inheritance)
Die Vererbung erlaubt das Übertragen von Eigenschaften existierender Klassen/Objekte auf neue Objekte, die entweder die Funktionalität der ursprünglichen Klasse erweitern oder modifizieren. Dies führt zu Anpassbarkeit, Erweiterbarkeit und reduziert die Programmgröße, da bestehende Funktionalität nicht kopiert werden muss, sondern mitverwendet werden kann.
Dynamische Methodenauswahl (engl. Polymorphism) und Subtyping
Dynamische Methodenauswahl meint, dass zum Zeitpunkt der Implementierung nicht feststeht, welche Klasse die Implementierung der Methode zur Verfügung stellt. Je nach Vererbungshierarchie ermittelt die Laufzeitumgebung die aufzurufende Methode. Dies wird auch als Polymorphismus bezeichnet. Subtyping beschreibt, dass durch Vererbung eine Typhierarchie entsteht und somit eine abgeleitete Klasse (=Subtyp) alle Eigenschaften des Supertyps erbt. Subtyping ermöglicht Polymorphie in typisierten Sprachen.
Kapselung (engl. Encapsulation)
Dies erlaubt den Objekten, Details über die zur Verfügung gestellte Funktionalität zu verbergen und stellt sicher, dass Benutzer des Objektes den internen Zustand nicht unvorhergesehen verändern können. Nur die Implementierung des Objekts kann den internen Zustand lesen und verändern. Öffentlich zugängliche Eigenschaften und Nachrichten von Objekten werden als Schnittstellen bezeichnet.

Die zuvor genannten Konzepte werden in verschiedenen objektorientierten Sprachen in unterschiedlicher Weise und Gewichtung umgesetzt. So gibt es objektorientierte Sprachen ganz ohne Typkonzept oder Sprachen, die keine Klassen kennen sondern zum Erzeugen eines neuen Objektes ein bestehendes kopieren und dann nach Bedarf modifizieren. Weiter soll an dieser Stelle aber nicht darauf eingegangen werden.

Vorteile der Objektorientierten Programmierung

Objektorientierte Programmiersprachen wurden von Beginn an als Ablösung der vorherrschenden prozeduralen Programmierung entworfen. Die Vorteile manifestieren sich hauptsächlich durch die folgenden Eigenschaften (nach [Page00] und [Poetsch01]):

  • Objektorientierung unterstützt die Wiederverwendung von Software. Klassen können einfacher wiederverwendet werden, als die wenig zusammenhängenden einzelnen Methoden in früheren Ansätzen, da sie einen inneren funktionalen Zusammenhang, sowie eine definierte Schnittstelle nach außen haben.
  • Objektorientierte Programme sind in der Regel besser erweiterbar als z.B. prozedurale. Dies hat zwei Ursachen: Durch Nutzung von Vererbung können die Eigenschaften von bereits bestehenden Programmen genutzt werden, ohne die wiederverwendeten Programmteile zu ändern. Die Programme werden nur um den neuen Teil ergänzt. Außerdem sind durch Nutzung des Geheimnisprinzips (strenge Kapselung und Schnittstellenbildung) die Wirkungen von Änderungen gut erkennbar. Änderungen, die die Schnittstelle nicht betreffen, können als lokal betrachtet werden und erzeugen geringeren Prüfaufwand.
  • Das objektorientierte Grundkonzept bietet gute Ansätze für parallele Programmierung. Objekte in Programmen reagieren auf Nachrichten von anderen Objekten und reagieren selbst wieder durch Zustandsänderungen und/oder Nachrichten. Vom Modell her spricht nichts dagegen, dass mehrere Nachrichten gleichzeitig unterwegs sind und somit mehrere Ausführungsfäden gleichzeitig abgearbeitet werden.
  • Durch die logische Zusammenfassung von Daten und Funktion in Objekte und die gute Eignung für parallele Programmierung bietet die Objektorientierung gute Voraussetzungen zur Lösung verteilter Probleme. Objekte eines Programms müssen sich nicht zwingend auf einem einzelnen Rechner befinden. In Architekturen wie z.B. CORBA werden diese Eigenschaften genutzt und die Entwicklung verteilter Programme durch eine entsprechende Infrastruktur unterstützt.

Das Konzept der Komponentenbasierten Programmierung

Die komponentenbasierte Softwareentwicklung (engl. CBD: component based development, auch CBSE: component based software engineering und CBSD: component based software development) beschäftigt sich mit der Entwicklung von Systemen auf Basis von wiederbenutzbaren Artefakten –- den Komponenten –- und der Entwicklung von Komponenten [Crnkovic02].

Warum ein neues Programmierparadigma?

Programmierer sind mit dem ständigen Wachstum der Komplexität von Software konfrontiert. Diese Komplexität führte in den späten 60er Jahren zu einer Krise in der Softwarebranche, die heute noch andauert.

Einer der erfolgversprechenden Wege aus dieser Krise scheint vielen Entwicklern der Versuch, die durch eine Software zu lösenden Probleme in Teilprobleme zu zerlegen und letztlich diese Teilprobleme für sich getrennt zu betrachten.

Diese Gedankengänge führten zunächst zur Modularisierung von Programmen, später zur Objektorientierung und letztlich zur komponentenbasierten Softwareentwicklung.

CBD ist damit kein vollständig neues Paradigma, sondern greift weitgehend auf bestehende, bereits bewährte Konzepte zurück, um diese in einem konsistenten Modell zusammenzufassen. Es beschäftigt sich zum einen mit der Entwicklung und Wartung von Softwarekomponenten (kurz Komponenten), zum anderen mit der Konstruktion von Softwaresystemen aus Softwarekomponenten.

Komponenten als Lösung für Teilprobleme

Für eine Betrachtung von Problemen als Summe von Teilproblemen ist es notwendig, diese weitgehend voneinander zu entkoppeln. Das heißt, die Teilprobleme müssen so gewählt sein, dass ihre Abhängigkeiten untereinander so gering wie möglich sind. Die Schnittstelle zwischen den Teilproblemen muss also möglichst schmal sein.

Hier sieht [Griffel98] Analogien von Objektorientierung (insbesondere verteilter Objektorientierung) zum CBD: Eine starke Kapselung der Komponenten/Objekte mit enger Kommunikationsschnittstelle und der daraus resultierenden losen Kopplung innerhalb des Gesamtsystems. Dem zufolge müssen Komponenten also als Blackboxen entwickelt werden, die innere Funktionsweise der Komponente ist also von außen nicht sichtbar. Gleichzeitig muss die Schnittstelle, über die die Komponente ihre Dienstleistung anbietet, klar definiert und gut dokumentiert sein, um eine einfache Nutzbarkeit zu gewährleisten.

Da das Feld CBD aus anderen Gebieten hervorgegangen ist, sind viele der Begriffe historisch gewachsen und so sind eindeutige, in der Fachwelt anerkannte Definitionen schwer zu finden. Weitestgehend ist man sich aber darüber einig, dass folgende Eigenschaften eine Komponente ausmachen:

  • Komponenten sind nach außen streng gekapselt.
  • Kommunikation mit der Komponente geschieht über eine klar definierte Schnittstelle.
  • Komponenten sind eigenständig lauffähige Produkte. Sie unterliegen einer eigenen Versionierung und können als eigenständiges Produkt vertrieben werden.
  • Komponenten können aus anderen Komponenten zusammengesetzt werden.

[Szyperski02] legt zudem noch Wert darauf, dass eine Komponente keinen nach außen sichtbaren Zustand hat. Diese Forderung hat zur Folge, dass die Kopien einer Komponente voneinander nicht unterscheidbar sind. Demnach können zur Laufzeit die Kopien ausgetauscht werden (z.B. zu Redundanzzwecken oder zum Einspielen eines Updates).

Vorteile

Der Komponentenentwickler kann eine realitätsnahe Modellierung von Anwendungsbereichen vornehmen, Änderungen sind einfacher möglich und vorgefertigte, wiederverwendbare Komponenten lassen sich in neue Programme einbauen, was den Implementationsaufwand beträchtlich reduzieren kann. Viele Komponentensysteme bieten eine Reihe von In\-fra\-struk\-tur-Funktionalitäten an, welche nach der Übersetzung einer Komponente konfiguriert werden können und das Laufzeitverhalten beeinflussen. Implementierung und Wartung dieser Dienste liegen somit auf Seiten der Entwickler der Container und Applikationsserver. Weitere Belange wie die Verteilung von Komponenten, Lebensdauerverwaltung, Fernzugriff oder Persistenz können ebenfalls meist von der Laufzeitumgebung übernommen werden.

Nachteile

Trotz der höheren Abstraktion und der damit verbundenen Aufteilung der Aufgaben zeichnen sich auch einige Probleme in der komponentenbasierten Programmierung ab, siehe auch [Schmah03]. Zusammenfassend kristallisieren sich folgende Kritikpunkte an standardisierten Komponentenlösungen heraus, die jeweils zu einem gewissen Teil auf die einzelnen Technologien zutreffen:

  • Komplexe Programmiermodelle erschweren die Realisierung von Komponenten.
  • Die Implementierung der Geschäftslogik ist von der Komponententechnologie abhängig.
  • Implementierungsrestriktionen werden oftmals nicht durch den Compiler erzwungen, was mehr Disziplin der Entwickler erfordert.
  • Es besteht zur Zeit noch wenig Standardisierung unter den verschiedenen Komponentensystemen, eine Festlegung macht unter Umständen abhängig von der verwendeten Komponententechnologie und kann einen späteren Umstieg aufwändig gestalten.

Eignung der objektorientierten Programmierung für die komponentenbasierte Programmierung

Objektorientierte und komponentenbasierte Programmierung haben viele Gemeinsamkeiten, vor allem da für komponentenbasierte Programmierung Ansätze aus der Objektorientierung übernommen wurden und somit Teile als logische Weiterführung der Konzepte der Objektorientierung verstanden werden können.

Frank Griffel stellt in seinem Buch Componentware zum Beispiel fest, dass CBD als Skalierung der OOP betrachtet werden kann (vgl. [Griffel98], Kap. 2.2.2.). Er akzeptiert damit die objektorientierten Techniken als beste heute verfügbare Ausgangsbasis für eine komponentenbasierte Software und bringt diese Überlegungen mit der Formel

\begin{quotation} Komponenten = Objekte + "irgend etwas" \end{quotation}

\noindent auf den Punkt.

In diesem Kapitel diskutieren wird daher, welche Probleme auftreten können, wenn objektorientierte Techniken bei der Erstellung von Komponenten zum Einsatz kommen. Dazu untersuchen wir kurz einige exemplarisch ausgewählte Eigenschaften anhand der in [Page00] gelisteten Unterschieden und Gemeinsamkeiten.

Standards

Auch wenn in vielen Projekten Standards verwendet werden, um die Ergebnisse konsistent zu halten, macht Objektorientierung per-se keine Vorgaben, welche Operationen eine Klasse zur Verfügung stellen muss, um in das Gesamtsystem integriert werden zu können. Ein komponentenbasiertes System hingegen verlangt üblicherweise eine vorgegebene Anzahl von Operationen, durch die zum Beispiel Metadaten ermittelt werden können.

Zustand

Wenn Objekte aus Klassen instantiiert werden, so halten diese Informationen, die zu jeder Zeit den Zustand des Objektes darstellen. Methodenaufrufe können diesen Zustand verändern.

Obwohl vereinzelt vorgeschlagen wird, Komponenten so zu gestalten, dass sie keinen nach außen sichtbaren Zustand haben (vgl. [Szyperski02]), wird doch generell von Komponenten ausgegangen, die analog zu Objekten ihren Zustand speichern können.

Der Vorteil, Komponenten nach außen zustandslos zu gestalten, liegt in der besseren Wartbarkeit. Verschiedene Installationen einer Komponente auf unterschiedlichen Systemen sollen sich nicht voneinander unterscheiden, da dies den Wartungsaufwand deutlich erhöhen würde.

Daher wird in diesem Ansatz zwischen Komponente und dem Objekt, auf dem die Komponente arbeitet unterschieden. Beispielsweise kann ein Datenbankserver als Komponente betrachtet werden. Der Datenbankserver ist nach außen hin zustandslos. Der Zustand wird in den Datenbanken selbst gespeichert. nur diese sind persistent. Das heißt, verschiedene Installationen des Servers unterscheiden sich im Schnittstellenverhalten nicht, wenn sie als Parameter die gleiche Datenbank bekommen.

Ablaufumgebung

In der Objektorientierung wird üblicherweise keine generelle Umgebung für die Ausführung der Objekte definiert. Es wird also keine Vorgabe über die Ausführungsumgebung gemacht. Einige objektorientierte Programmiersprachen stellen allerdings bereits eine mehr oder weniger umfangreiche Umgebung zur Verfügung, etwa die Java Virtual Machine oder das .NET Framework.

Bei Komponenten hingegen muss oft zur Entwicklungszeit bereits die definierte Ausführungsumgebung (oft als Container bezeichnet) beachtet werden. Die Ausführungsumgebung kann allerdings dem Entwickler Arbeit abnehmen und häufig verwendete Funktionalität zur Verfügung stellen. Meist ist die Umgebung nötig, um die Komponente überhaupt einsetzen zu können.

Binärstandards

Da Komponenten üblicherweise in übersetzter Form als ausführbare Dateien verteilt werden, benötigen sie auch Definitionen, wie die Laufzeitumgebung aufgebaut sein muss. Dadurch müssen Standards für Komponenten auch Festlegungen für den ausführbaren Code enthalten. Die Erfüllung des Binärstandards ermöglicht Verbindungen zwischen Komponenten über ihre Schnittstellen ohne auf die ursprüngliche Implementierungssprache acht nehmen zu müssen. Dies erlaubt auch, Komponenten, die in unterschiedlichen Sprachen entwickelt wurden, zusammen einzusetzen, solange die binären Schnittstellen kompatibel sind.

Metadaten

Manche Komponentensysteme erfordern Metadaten als Teil der eingesetzten Komponenten und ermöglichen damit Prüfungen, welche Operationen und welche Verträge (engl. Contracts) eine Komponente zur Verfügung stellt. Eine Komponente wird dabei alle Schnittstellen bekannt geben, die sie zur Verfügung stellt. In der objektorientierten Programmierung sind solche Konzepte üblicherweise nicht vorhanden.

Schnittstelle

Sowohl in der Objektorientierung als auch in der Komponentenbasierten Softwareentwicklung hat die Schnittstelle wesentliche Rolle. Sie beschreibt durch Eigenschaften, Methoden und Ereignisse das Verhalten eines Objektes bzw. einer Komponente nach außen. So wird nur über diese Schnittstelle mit der Umwelt der Komponente/des Objekts kommuniziert.

Durch diese Gemeinsamkeit scheint die Erstellung von Komponenten durch objektorientierte Ansätze sehr gut unterstützt zu werden.

Die Objektschnittstelle hat aber aus Sicht von CBD einen entscheidenden Nachteil. Die Schnittstelle eines einzelnen Objekts ist in der Regel in einer konkreten Programmiersprache verfasst. Diese Sprachbarriere muss durch eine sprachübergreifende Technik, die vom objektorientierten Grundmodell nicht verlangt wird, überwunden werden.

Komponenten definieren ihre Schnittstelle daher oft in speziellen Schnittstellensprachen, die nicht Sprachabhängig sind. Dadurch können sie mit Komponenten kommunizieren, die in einer anderen Programmiersprache verfasst sind. Als Beispiel kann die IDL (Interface Definition Language) angeführt werden.

Diese Sprache wird oft auch für spezielle Schnittstellen in objektorientierten Programmen verwendet, nämlich dann, wenn es um Verteilte Programmierung geht. Die Nutzung von allgemeinen Schnittstellensprachen ist also keine Neuerung, die durch die Komponentenbasierte Softwareentwicklung eingeführt wurde, sondern wird schon länger dort gern genutzt, wo eine klar definierte, nach außen sichtbare Schnittstelle nötig ist.

Specification Matching

Eine Weiterführung des Gedankens, Software durch Komposition von Komponenten zu erstellen ist der Versuch, automatisch die passende Komponente für eine Aufgabe zu finden. Hierzu gibt es verschiedene Möglichkeiten. Einer dieser Ansätze ist das Specification Matching.

Voraussetzung für diese Technik ist, dass die Schnittstelle einer jeden Komponente formal beschrieben ist. Damit ist die syntaktische, aber auch die semantische Beschreibung der Schnittstelle gemeint, also sowohl ihre Syntax als auch ihre Spezifikation.

[Zaremski96] beschreibt verschiedene Lösungswege, die Schnittstellen von Komponenten miteinander zu vergleichen und festzustellen, ob eine Komponente durch eine andere ersetzt werden kann. Es geht dabei aber zunächst nicht um ein vollständig automatisiertes Suchen. Der Ansatz ist eher, dass die Sprache zunächst dem Entwickler helfen soll, aus einer Bibliothek von Komponenten geeignete Kandidaten für seine Zwecke zu finden. Entsprechend beschreiben die in diesem Papier untersuchten Techniken keine exakte Suche, sondern eher eine unscharfe Auswahl möglicher Treffer. Einige Fehlalarme werden hier eher akzeptiert, als dass zu viele gute Kandidaten aufgrund strenger Filterung wegfallen.

Letztlich kommen Zaremski und Wing zu dem Schluss, dass es neben den beiden Parametern Syntax und Spezifikation noch auf die Art der Interaktion der Komponente mit ihrer Umgebung (genutzte Protokolle) ankommt.

Uns erscheint solch ein Ansatz sehr aufwändig und nur lohnend, wenn eine Komponente tatsächlich für die Wiederverwendung erstellt wird. Nur dann lohnt sich der zusätzliche Aufwand der formalen Schnittstellenbeschreibung. Ebenso erscheint uns ein Specification Matching nur innerhalb eines konkreten Komponentenmodells sinnvoll, da nur so die Komplexität der Schnittstelle begrenzt werden kann.

Object Aliasing

Aliasing ist ein originäres Problem der Objektorientierung, bei dem Kapselung durchbrochen und die öffentliche Schnittstelle umgangen wird. Trotzdem soll dieses Problem in einem eigenen Kapitel betrachtet werden, da es sich um ein in der Objektorientierung bisher nicht zufriedenstellend gelöstes Problem handelt.

[Hogg92] definiert den Begriff Aliasing folgendermaßen: An object is aliased with respect to some context if two or more access-paths to it exist. Aliase entstehen z.B. dann, wenn nicht mit Objekten selbst sondern mit Referenzen auf Objekten gearbeitet wird.

Referenzen auf Objekte haben durchaus ihre Berechtigung (z.B. keine doppelte Haltung von Objekten im Speicher, call by reference ). Jedoch muss dem Entwickler objektorientierter Software bewusst sein, dass Aliasing zu Problemen führen kann.

Um mögliche Folgen des Aliasing zu verdeutlichen, gibt [Hogg92] ein Beispiel aus dem Gebiet der formalen Programmverifikation:

Mit Hilfe des Zuweisungsaxioms $\{P[E/x]\} x:=E \{P\}$ lässt sich zeigen, dass \linebreak$\{x = true\} y := false \{x = true\}$ gültig ist, da über $y$ in Vor- und Nachbedingung keine Aussage gemacht wird. Sind aber $x$ und $y$ Referenzen auf die gleiche Variable, stimmt diese Aussage nicht mehr. Zwar lässt sich auch hier ein Beweis formulieren, aber zum einen ist dieser komplizierter, zum anderen braucht man Aussagen zu allen Aliasen der betroffenen Variablen.

Problematisch wird das Aliasing, wenn Objekte selbst wiederum aus anderen Objekten zusammengesetzt sind. So ist es denkbar, dass ein Objekt (unbeabsichtigt) über seine Schnittstelle eine Referenz auf ein inneres, für seine Funktion wesentliches Objekt heraus gibt, und damit die Kapselung durchbricht [Noble98].

Eine externe Nutzung dieser Referenz kann Fehlfunktionen im herausgebenden Objekt verursachen, es zum Beispiel erlauben, Zugang zu den vertrauenswürdigen Teilen des Objekts zu erhalten. In [Noble98] wird ein derartiger Defekt in einer Implementierung in SUN's digitalen Signaturen für Java-Applets beschrieben, durch den sich jedes beliebige Applet als Trusted ausweisen konnte, weil statt einer Kopie ein Alias auf die interne Signaturliste zurückgegeben wurde. Diese war dann leicht entsprechend zu modifizieren.

Dieses Beispiel zeigt die Relevanz von Aliasing für die Entwicklung von objektorientierten Komponenten. Ist eine Komponente als Komposition von Objekten aufgebaut, ist es notwendig seine Schnittstelle gegen die Herausgabe von für die Funktionalität wesentlichen Referenzen zu schützen. Eine solche zusätzliche Kapselungsschicht könnte die Gefahr durch Aliasing entstehender Fehler erheblich senken.

Da Komponenten in der Regel ihre Objekte und Daten untereinander über die Infrastruktur austauschen, wäre es an dieser Stelle sogar denkbar, Object Aliasing zwischen Komponenten vollständig zu unterbinden und beim Datenaustausch nur Kopien zuzulassen. Damit wären die Komponenten selbst dafür verantwortlich, übergebene Daten in den eigenen Datenbestand zu übernehmen. Hier müssen die Vor- und Nachteile allerdings gegeneinander abgewogen werden.

Letztlich lösen Komponenten die Probleme, die mit dem Object Aliasing einhergehen nicht automatisch. Die zusätzliche Kapselung an der Komponentengrenze gibt dem Entwickler aber die Möglichkeit, eine Barriere gegen Aliase aufzubauen und so das Risiko einer Kompromittierung der Komponente zu reduzieren.

Wiederverwendung

[Griffel98] definiert Wiederverwendbarkeit von Software als das erneute Anwenden von bei der Entwicklung eines Softwaresystems entstandenen Artefakten und angesammelten Wissen bei der Entwicklung eines neuen Softwaresystems, um den Aufwand zur Erstellung und Pflege dieses neuen Systems zu reduzieren.

Beide Paradigmen haben die Zielsetzung, Wiederverwendung zu erleichtern und somit Zeit und Ressourcen zu sparen.

Durch die Kapselung und die daraus resultierende Lokalität von Änderungen sowie durch Vererbung unterstützt die Objektorientierung die Wiederverwendung von bereits implementierten Funktionalitäten. Diese Wiederverwendung findet sich bereits in der Analysephase wieder und setzt sich bis zur Implementation fort. So ist die Nutzung von Entwurfsmustern genauso eine Form der Wiederverwendung bewährter Lösungen wie das Erben und Modifizieren einer Klasse.

Allerdings werden objektorientierte Systeme bei steigender Komplexität schnell schwer beherrschbar. Dies vermindert die Möglichkeit zur Wiederverwendung, da dadurch die Kopplung der Systeme schnell ansteigt.

Bei der Erstellung und Pflege von Komponenten kann diese Eigenschaft der Objektorientierung gewinnbringend einfließen, wenn man bei der Erstellung die objektorientierte Techniken benutzt.

Bei CBD gibt es zudem noch die Form der Wiederverwendung von Komponenten als Ganzes. Komponenten als Fertiglösungen für Teilprobleme zu nutzen ist ein erklärtes Ziel der Komponentenbasierten Programmierung. Ebenso soll der Einbau fremder Komponenten ohne gravierende Schnittstellenprobleme möglich werden. Hier kann die Objektorientierung nur einen kleinen Beitrag leisten, da diese Form der Wiederverwendung auf einer höheren Abstraktionsebene geschieht (s.a. die Betrachtungen zur Schnittstelle).

Insgesamt ist bei Komponenten üblicherweise Wiederverwendbarkeit stärker betont. Objekte in OOP werden wiederverwendet, falls später Bedarf für ähnliche Funktionalität entsteht. Komponenten hingegen werden für die Wiederverwendung entworfen. Außerdem wird Wert darauf gelegt, fremde Komponenten einbauen und später durch alternative Implementierungen austauschen zu können.

Schlussfolgerungen

Objektorientierte und Komponentenbasierte Programmierung ergänzen sich besonders in großen Projekten ideal. Wo in rein objektorientiert entwickelten Systemen aufgrund der Komplexität der Beziehungen zwischen einzelnen Klassen schnell der Überblick verloren geht, sind Komponenten in der Lage, die enge Bindung zwischen den Bestandteilen eines Systems aufzulockern. Dass diese Komponenten selbst wieder aus Komponenten bestehen können, oder auch objektorientiert entwickelt sein können, erweitert noch die Möglichkeiten, Objektorientierung und Komponenten nebeneinander einzusetzen.

Der große Vorteil von komponenten-nutzenden Systemen ist, dass man die Komponenten als "Black Boxes" betrachten und ihre Implementation weiter vor dem Nutzer verbergen kann. Dadurch entsteht eine sehr starken Kapselung der Komponente nach außen und ihre öffentliche Schnittstelle gewinnt an Bedeutung.

Dies macht Komponenten wirtschaftlich interessant, da es dem Projektmanagement zusätzliche Möglichkeiten gibt, die Arbeit in einem Projekt zu strukturieren. Die Komponentenentwicklung kann an eine andere Person, eine andere Abteilung oder sogar an eine externe Firma ausgelagert werden. Als wirtschaftlich besonders interessante Lösung bietet sich die Wiederverwendung bereits existierender, zu einer geforderten Schnittstelle passender Komponenten an.

Diese Vorteile von Komponenten lassen sich im Ansatz auch in objektorientierten Systemen zeigen. So bieten zum Beispiel objektorientierte Frameworks bereits oft kommerziell vermarktete, vorgefertigte Lösungen für bestimmte Aufgaben. Der Entwickler eines Programms wird dann bei der Lösung seines Problems unterstützt. Er muss das Framework nur um die Anwendungslogik seines Problems konkretisieren.

Komponentenbasierte Entwicklung nimmt diesen Ansatz auf, bietet aber nicht eine allgemeine Basis zur Lösung von Teilproblemen sondern geht bei konkreten Problemstellungen in die Tiefe und löst diese vollständig.

Dies führt uns zu einer Feststellung, die bereits [Griffel98] getroffen hat:

\begin{quotation}Daher sollten die Konzepte der Objektorientierung und einer Komponentenorientierung nicht als nebeneinander stehende, sondern eher als aufeinander aufbauende Techniken betrachtet werden.\end{quotation}

In der Praxis birgt die Softwareentwicklung mit Komponenten wohl auch noch einige Schwächen, welche die Forschung noch die nächsten Jahre beschäftigen werden, wie etwa Wege, die richtige Komponente für die richtige Anwendung zu finden. Einen Ansatz zur Lösung haben wir mit dem Specification Matching vorgestellt. Ob sich dieser Ansatz praktisch bewährt, muss sich aber noch zeigen, da die Komponentenbeschreibung hierfür hohe Anforderungen an die Entwickler stellt.

Abschließend stellt sich uns als zentraler Punkt in beiden Paradigmen die Schnittstelle dar. Viele objektorientierte Programmiersprachen bieten bereits die Möglichkeit, Schnittstelle und Implementierung zu trennen. Für die komponentenbasierte Programmierung wurde diese Entwicklung fortgesetzt und eine Trennung der Schnittstelle von der Implementierung gefordert. Dies führt zu weiterer Modularisierung, Kapselung und weniger Koppelung. Dies lässt uns hoffen, in Zukunft durch die Kombination objektorientierter und komponentenbasierter Programmierung die Anforderungen der Kunden in Softwareprojekten schneller mit besserer und funktional ausgereifter Software bedienen zu können.

\newpage

Literatur

  • [Crnkovic02] Crnkovic, Ivica, Larsson, Stig, Stafford, Judith: Composing Systems From Components. Proceedings of the 9th IEEE Conference and Workshops on Engineering of Computer-Based Systems, Lund University, Lund, Sweden. IEEE. 2002.
  • [Griffel98] Griffel, Frank: Componentware: Konzepte und Techniken eines Softwareparadigmas. 1. Aufl., dpunk-Verlag, 1998, ISBN 3-932588-02-9
  • [Hogg92] Hogg, J., Lea, D., Wills, A., deChampeaux, D., Holt, R.: The Geneva convention on the treatment of object aliasing. Follow-up report on ECOOP'91 workshop W3: Object-oriented formal methods. OOPS Messanger, 3(2):11-16, April 1992. http://citeseer.ist.psu.edu/hogg92geneva.html
  • [Noble98] Noble, James, Vitek, Jan, Potter, John: Flexible Alias Protection. 1998. \linebreak http://citeseer.ist.psu.edu/47376.html
  • [Page00] Page-Jones, Meilir: Fundamentals of Object-Oriented Design in UML. Addison-Wesley, 2000, ISBN 0-201-69946-X
  • [Poetsch01] Poetsch-Heffter, A., Meyer, J., Müller, P.: Kurs 01618: Einführung in die objektorientierte Programmierung. Kursunterlagen der Fern-Universität Hagen, 2001
  • [Schmah03] Schmah, Steffen: ALICE, Implementierung semantischer Annotationen für Java. 2003. Diplomarbeit am Fachgebiet Softwaretechnik der Technischen Universität Darmstadt. \linebreak http://www.aop.informatik.tu-darmstadt.de/database/theses/thesis/Diplomarbeit.pdf?id=1
  • [Szyperski02] Szyperski, Clemens, Gruntz Dominik, Murer, Stephan: Component software : beyond object-oriented programming. 2nd ed., Addison-Wesley, 2002, ISBN 0-201-74572-0
  • [Zaremski96] Zaremski, Amy Moormann, Wing, Jeannette M.: Specification Matching of Software Components. 1996. http://citeseer.ist.psu.edu/355687.html