Moderne Programmiersprachen sind gegenwärtig meist objektorientiert. Beispiele hierfür sind u. a. Smalltalk, Eiffel, Delphi und C++. Java kann hierbei als Ableitung aus C++ verstanden werden. Im Folgenden werden die Konzepte der objektorientierten Programmierung (OOP) vorgestellt. Booch definiert die OOP in [Booch94] folgendermaßen: „Objektorientierte Programmierung ist eine Implementierungsmethode, bei der Programme als kooperierende Ansammlungen von Objekten angeordnet sind. Jedes dieser Objekte stellt eine Instanz einer Klasse dar, und alle Klassen sind Elemente einer Klassenhierarchie, die durch Vererbungsbeziehungen gekennzeichnet ist." Eine Programmiersprache, die als objektorientiert klassifiziert werden soll, muss die in dieser Definition enthaltenen Bedingungen erfüllen. Betrachtet man als Beispiel für eine objektorientierte Programmiersprache Java, so stellt man fest, dass die Bedingungen erfüllt sind. Java verwendet Objekte als fundamentale Bausteine. Diese Objekte sind in Java Instanzen von Klassen. In Java können Klassen erweitert werden (Schlüsselwort extends), d. h. Subklassen erstellt werden, die von einer Superklasse erben. Diese Kennzeichen beschreiben allerdings im Wesentlichen die Eigenschaften der Programmiersprache, nicht die Konzepte der OOP, d. h. die Vorgehensweise bei der Erstellung eines Programms. Hierzu dient das Objektmodell, dessen Hauptelemente die folgenden sind [Booch94]: Objekt und Klasse Der Grundbegriff der Objektorientierung ist das Objekt. Ein Objekt ist ein abgeschlossenes Element eines Programms, das darauf ausgelegt ist, bestimmte Aufgaben zu erfüllen. Ein Objekt hat eine eindeutige Identität, die es von allen anderen Objekten unterscheidet, und ein bestimmtes Verhalten, das vom Zustand des Objekts abhängen kann. Objekte mit gleichem Verhalten werden in Klassen gruppiert. Eine Klasse beschreibt also statisch das Verhalten und die Struktur von Objekten. Klassen werden dazu verwendet, Objekte (Instanzen) zu erzeugen (diese zu instantiieren). Klassen werden in Java durch das Schlüsselwort class beschrieben. Attribute und Verhaltensweisen Im Allgemeinen besteht jede Klasse aus zwei Komponenten: Attributen und Verhaltensweisen, die durch Methoden definiert werden. Attribute, die durch Variablen definiert werden, legen die Erscheinung, den Zustand und andere Merkmale der Klasse fest. Das Verhalten einer Klasse wird durch Methoden definiert. Objekte kommunizieren miteinander, indem sie Nachrichten an andere Objekte senden. Empfängt ein Objekt eine Nachricht, so führt es daraufhin eine entsprechende Methode aus, die angibt, wie auf das Empfangen der Nachricht reagiert werden soll. Das Senden von Nachrichten kann mit dem Funktions- oder Prozeduraufruf in funktionalen bzw. prozeduralen Sprachen verglichen werden. Aggregation Wenn Objekte unter Verwendung anderer Objekte aufgebaut sind, nennt man dies Aggregation. Über Aggregation lässt sich also eine „Ist-Teil-von-Beziehung" zwischen Objekten beschreiben. Ein Beispiel hierfür wäre ein Auto, das (u. a.) vier Räder besitzt. Der durch die Aggregation beschriebene interne statische Aufbau von Objekten einer Klasse ist normalerweise nicht in der Schnittstelle einer Klasse sichtbar, sondern wird in der Implementierung dieser Klasse spezifiziert. Vererbung Vererbung ist ein Mechanismus, der es einer Klasse ermöglicht, ihre gesamten Eigenschaften von einer anderen Klasse zu erben. Vererbung wird in der OOP benutzt, um zwei Konzepte zu beschreiben, die häufig zusammen verwendet werden: die Spezialisierung von Klassenschnittstellen und den Import von Implementierungen. Spezialisierung dient dazu, ein System von Klassen nach einer Teilmengenbeziehung zu strukturieren. Eine Klasse A ist dann eine Spezialisierung einer anderen Klasse B, wenn alle Objekte von A die von B definierte Schnittstelle ebenfalls erfüllen, A also die Schnittstelle von B erweitert (extends). Zu beachten ist, dass eine Klasse mit erweiterter Schnittstelle jedoch eine Untermenge von Objekten beschreibt, da die erweiterte Beschreibung spezieller ist. Dies darf nicht verwechselt werden. Import beschreibt hingegen die Wiederverwendung existierender Implementierungen (oder Teile davon). Wenn eine Klasse A eine Klasse B erweitert, so kann sich dies also nicht nur auf deren Schnittstelle beziehen, sondern auch auf deren Implementierung, zu der weitere Funktionen hinzugefügt oder vorhandene an den neuen Kontext angepasst werden können. Diese beiden Konzepte werden in der Regel zusammen verwendet, da im Allgemeinen auch die Implementierung einer Klasse weiter verwendet werden soll, wenn diese spezialisiert wird. Genauso wird die Implementierung auch dann importiert, wenn ebenfalls eine Spezialisierung vorliegt. Da dies aber nicht in jedem Spezialfall garantiert werden kann, unterstützen moderne objektorientierte Programmiersprachen auch die Möglichkeit, beide Konzepte getrennt voneinander benutzen zu können. Bei der Programmierung von Benutzeroberflächen in Java wird z. B. die Klassenbibliothek Abstract Windowing Toolkit (AWT) importiert. Polymorphie Der Begriff Polymorphie (griech. Vielgestaltigkeit) besagt, dass eine Variable eines bestimmten Typs in die eines abgeleiteten Untertyps umgewandelt werden kann. Eine Variable vom (allgemeineren) Typ Fahrzeug könnte bspw. in den (spezielleren) Typ Auto umgewandelt werden, da sie dadurch lediglich um einige Eigenschaften erweitert (Konzept der Vererbung) wird. Objektorientierte Programmiersprachen unterstützen gewöhnlich das Konzept der Polymorphie. Bei Java erben bspw. alle Klassen automatisch von der Klasse Object. Ein Objekt vom Typ Object kann somit in jeden beliebigen Typ umgewandelt werden. Die Polymorphie stellt daher ein wichtiges Konzept zur Wiederverwendung und Erweiterbarkeit vorhandener Programme dar, was sowohl den Implementierungsaufwand als auch die Fehlerwahrscheinlichkeit der Programme verringert. Dynamisches Binden Die durch die Polymorphie eingeführten Möglichkeiten der Wiederverwendung und Erweiterbarkeit werden erst dann richtig ausgenutzt, wenn das Binden von den Methoden einer Klasse an die verschickten Nachrichten dynamisch zur Laufzeit erfolgt – im Unterschied zur statischen Bindung, die schon bei der Übersetzungszeit des Programms vorgenommen wird und die immer noch in vielen Programmiersprachen eingesetzt wird. Im Zusammenhang mit Komponenten, die eigenständige Programmteile sind, spricht man auch von Late Linking, da die Komponente nicht eingebunden, sondern nur benutzt wird. Dieses Konzept ist für ein erweiterbares System, worum es sich im Falle der Komponenten-Software handelt, eine Grundvoraussetzung. Eigenschaften des Objektmodells Aus den oben erwähnten Elementen des Objektmodells lassen sich folgende Eigenschaften ableiten, die ein Objektmodell aufweisen muss: Abstraktion Kapselung Modularität Hierarchie Nebenläufigkeit Verteilung und Persistenz. Abstraktion Abstraktion dient allgemein zur strukturierten Erfassung von komplexen Zusammenhängen. Im täglichen Leben macht man von Abstraktionen Gebrauch, indem komplizierte Sachverhalte auf das Wesentliche beschränkt werden. So kann ein Baum einfach durch Wurzeln, Stamm, Äste und Blätter beschrieben werden, wobei Details, wie z. B. die Zellstruktur der Blätter, vernachlässigt werden. Ob diese Abstraktion brauchbar ist, hängt jeweils vom Anwendungszweck ab. Der Begriff Abstraktion ist also subjektiv und zweckorientiert. Für den Programmierer bedeutet dies, selbst entscheiden zu müssen, ob ein Detail zur Objektmodellierung wichtig ist oder vernachlässigt werden kann. Kapselung Durch Kapselung erreicht man, Eigenschaften, die zur korrekten Funktionsweise eines Modells notwendig sind, von denen zu trennen, die zum Verstehen oder Verwenden des Modells unerlässlich sind. Um ein Objekt in einem Programm korrekt verwenden zu können, ist es nicht notwendig, eine genaue Kenntnis der inneren Vorgänge zu haben. Es genügt zu wissen, welche Eigenschaften das Objekt besitzt und welche Operationen darauf angewendet werden können. In Java erreicht man, ähnlich wie in anderen Programmiersprachen, eine Kapselung durch Vergabe sog. Modifier [OAV97]. Dazu gehören z.B. die Schlüsselwörter public, protected und private, durch die der Zugriff auf eine Eigenschaft oder Methode für Instanzen anderer Klassen kontrolliert werden kann. Dabei bedeutet public, dass der Zugriff allen Objekten erlaubt wird, protected, dass lediglich die Instanzen der Klasse selbst, die der Subklassen, sowie Klassen desselben Packages Zugriff haben und private, dass allein der Klasse selbst der Zugriff erlaubt ist. Allgemein kann man die Kapselung auch wie folgt [Booch94] beschreiben: „Die Kapselung dient dazu, die Schnittstelle einer Abstraktion und ihre Implementierung voneinander zu trennen." Modularität Eng mit der Kapselung verbunden ist der Begriff Modularität. Unter einem Modul versteht man die Zusammenfassung von Klassen, die einen logischen Bezug zueinander besitzen. In Java wird dies durch ein sog. Package realisiert. So stellt schon die Sprache verschiedene Packages bereit, z.B. das Package java.io.*, in dem häufig verwendete Ein- und Ausgabeaufgaben in vorgefertigten Klassen zur Verfügung stehen. Ähnlich wie bei der Kapselung muss festgelegt werden, welche Objekte von außen Zugriff auf Methoden und Attribute haben. Es muss folglich auch für Module eine Schnittstelle bereitgestellt werden, die Objekten anderer Module den kontrollierten Zugriff gestattet und gleichzeitig Teile, die nur für das Modul selbst wichtig sind, verbirgt. Hierarchie Auch das Konzept der Hierarchie ist lediglich eine Nachbildung der realen Welt. Objekte in der realen Welt sind häufig hierarchisch angeordnet. So ist z. B. ein Baum eine Pflanze und ein Auto ein Fahrzeug. Das Gegenstück hierzu in der OOP heißt Vererbung. Eigenschaften der Klasse Pflanze würden an die Klasse Baum, die eine Subklasse von Pflanze ist, vererbt werden. Diese Eigenart der Hierarchie nennt man auch „is a"-Hierarchie (ein Baum ist eine Pflanze). Verbundbeziehungen werden hingegen als sog. „part of"-Hierarchien bezeichnet. Ist bspw. die Wagenfarbe lediglich ein Attribut eines Autos, so ist der Motor sicherlich ein komplexer Bestandteil, der in einer eigenen Klasse beschrieben werden sollte. Nebenläufigkeit Nebenläufigkeit (Multithreading) bezeichnet die Eigenschaft einen Systems, mehrere Kontrollflüsse (Prozesse) gleichzeitig (oder quasi-gleichzeitig) ausführen zu können. In einem Objektmodell ist Nebenläufigkeit gut zu modellieren, indem verschiedenen Objekten parallele Kontrollflüsse zugeordnet werden. Diese Objekte nennt man in diesem Zusammenhang auch aktive Objekte. Verteilung Von Verteilung spricht man, wenn Objekte eines Systems auf verschiedene Rechner verteilt sind. Da Objekte in sich geschlossene Einheiten bilden (Modularität), eignen sie sich gut zur Verteilung. Weil die Kommunikation zwischen Objekten über einen Nachrichtenaustausch stattfindet, ist es leicht möglich, diese Nachrichten nicht nur innerhalb eines Rechners, sondern auch über ein Netzwerk zu verschicken. Verteilung ist in Java einer der wichtigsten Aspekte, der sowohl direkt mittels Java-RMI (Remote Method Invocation) realisierbar ist oder indirekt durch die Unterstützung von CORBA. Persistenz Unter Persistenz versteht man die Eigenschaft eines Objekts, einen Zustand zeitlich und/oder räumlich beizubehalten. Dies beinhaltet einerseits ein zeitliches Überdauern des Erzeugers des Objekts, indem das Objekt bspw. gespeichert und in einer anderen Anwendung weiterverwendet wird. Andererseits kann ein persistentes Objekt auf einen anderen Rechner verlagert werden, ohne dass sich seine Identität, sein Verhalten oder sein Zustand ändert. Persistenz spielt in Java besonders bei der Entwicklung von Java-Komponenten (JavaBeans) eine große Rolle.