4 Objektorientiertes Design (OOD)
Das reine objektorientierte Design ist der zweite Teil des Konzeptentwurfs,
wie er in den Phasen Architektur und Design auftritt. Es basiert jeweils
auf den Ergebnissen der objektorientierten Analyse. Die Qualität des
OOD hängt davon ab, wie präzise und vollständig die Ergebnisse
der OOA verfaßt sind.
4.1 Strategie: Modellieren
Das Ziel des objektorientierten Designs ist es, die relevanten Elemente
der OO-Analyse zu einem, das Problem und dessen Lösung beschreibenden,
Modell zusammenzusetzen. Das reine objektorientierte Design, ist demnach
der Vorgang, in dem die aus der Analyse gewonnenen OO-Elemente modelliert
werden zu einem komplexen Netz aus Klassen und Objekten, deren Beziehungen
untereinander alle für die Problemlösung relevanten Informationen
enthalten. In diesem Modell werden die Attribute und Operationen ihren
jeweiligen Klassen, die sie kapseln, zugewiesen (was auch schon während
der OOA erfolgt sein kann) und jedes Objekt wird um seinen Objekttyp, die
Klassenvorlage ergänzt (was direkt aus der Analyse hervor geht). Dann
werden die relevanten Klassen mit Beziehungen untereinander verknüpft,
wobei die Art der Beziehung jeweils angibt, wie die Klassen und damit auch
Objekte dieser Klassen zueinander stehen.
Solch
eine Beziehung könnte beispielsweise bestimmen, daß eine Klasse
von einer anderen erbt, oder daß eine Klasse ein funktionaler Teil
einer anderen ist, oder daß einfach nur eine Klasse Informationen
über eine andere besitzt (siehe Beziehungen).
Grundsätzlich gilt für alle OOD-Modelle: Jedes Designmodell
des zu realisierenden Programmsystems kann, je nach Art des Modells, einige
Aspekte besonders gut veranschaulichen, andere dagegen nur unzureichend
erklären. Um nun eine weitgehend zutreffende und nützliche modellhafte
Beschreibung des Sachverhalts zu erhalten, ist es demnach bei der Entwicklung
größerer Projekte (sogenanntem Very-Large-Scale-Development)
unbedingt ratsam, sich im OOD nicht auf ein scheinbar alles erläuterndes
Modell zu beschränken, sondern die Realität synchron von mehreren
Ansichten zu beleuchten und davon mehrere Modelle unterschiedlicher Art
zu erstellen, die alle die gleiche Realität beschreiben. Die Technik,
eine Realität durch mehrere separate Teilmodelle zu beschreiben, die
aber erst zusammengenommen eine sinnvolle, komplette Beschreibung liefern,
wird im folgenden als Multi-Komponenten-Modell (MKM) bezeichnet.
"Ein
Modell ist eine Abstraktion, die dazu dient, ein System zu verstehen, bevor
es gebaut wird. Weil ein Modell auf unwesentliche Details verzichtet ist
es leichter zu manipulieren als das Original" - Rumbaugh (OMT)
Das zu realisierende Programmsystem, welches ein beim OODesign erstelltes
Modell beschreiben soll, ist - streng genommen - selber wieder nur ein
Modell der Wirklichkeit. Auch die verwendete Programmiersprache ist nur
ein Modell zur Beschreibung von ablauffähigen Programmen. Die Designmodelle
sind daher nur eine weitere Abstraktionsstufe für die Beschreibungsmöglichkeiten,
die in der zugrundeliegenden Programmiersprache schon vorhanden wären.
Sie sind aber auch noch einfacher zu handhaben, weil sie auf noch mehr
vorerst irrelevante Details verzichten.
4.2 Schreibweisen (UML)
Um die Ergebnisse objektorientierten Designs notieren und untereinander
austauschen zu können, werden standardisierte Schreibweisen benötigt.
Es existierten bis vor kurzem drei voneinander unabhängig entstandene
Schreibweisen, die aus folgenden Methoden stammen: die Grady Booch-Methode,
die Object-Modelling-Technique (OMT)-Methode und die OSE. Die besten Ansätze
aus allen dreien wurden jüngst zu einer Unified Modelling Language
oder UML vereint.
4.2.1 Beziehungen zwischen Objekten
Für jede Methode der Modellbildung bei der objektorientierten Programmierung
essentiell, ist die Unterscheidung verschiedener Arten von Beziehungen
zwischen Klassen und Objekten. Die UML kennt als wesentliche, für
das Verständnis erforderliche OO-Elemente folgende Beziehungen zwischen
zwei (oder selten auch mehr) Klassen:
Beziehungen zwischen Klassen
Beziehung |
Darstellung |
-
Generalisierung:
-
Eine Basisklasse vererbt
alle ihre Felder (also Eigenschaften) an eine Subklasse. Mehrere direkte
Subklassen einer gemeinsamen Oberklasse unterscheiden sich durch eine Discriminator
genannte Menge Eigenschaften voneinander. Eine Generalisierung in der eine
Subklasse von mehreren Basisklassen erbt, kann auch nicht disjunkt
sein, dann sind Felder der Basisklasse polymorph.
-

-
Eine Generalisierung wäre etwa die Beziehung zwischen einer Klasse
"Tier" und einer Klasse "Katze", die beschreibt, daß eine Katze eine
Art Tier ist und die Tiereigenschaften erbt. Der Discriminator mehrer Tierderivate
wäre so beispielsweise die Vorkommensdomäne, wie Land oder Wasser.
|
 |
-
Komposition:
-
Eine Kontainerklasse kann eine andere Klasse dauerhaft als Komponente
enthalten bzw. zu einem essentiellen Teil aus ihr bestehen. Die Lebenszeit der Komponente
deckt sich vollstädig mit der ihres Kontainers.
Insbesondere hat die Kontainerseite der Relation die Kardinalität 1, weil jede
Komponente nur Teil genau eines Kontainers ist.
-

-
So würde also eine Klasse "Auto" aus den Komponenten "Fahrwerk" und "Motor" bestehen.
|
 |
-
Aggregation:
-
Wenn eine Klasse eine andere nur zeitweise beinhaltet oder zur Ausführung
Objekte anderer Klassen erzeugt, sagt man, eine Klasse ist aus ihren Referenten
aggregiert.
-

-
So würde also eine Klasse "Lieferung" einige Objekte "Artikel" enthalten.
|
 |
-
Delegation:
-
Wenn eine Klasse eine andere nur zeitweise beinhaltet oder zur Ausführung
Objekte anderer Klassen erzeugt, sagt man, eine Klasse delegiert Funktionalität
an ihre Referenten. Deshalb wird eine Delegation manchmal auch als
Aggregation by-reference bezeichnet. Delegation ist oft hinter anderen Assoziationen wie der
Aggregation versteckt.
-

-
Zum Beispiel könnte eine graphische Anzeigeklasse die Behandlung der Benutzereingabe
an eine speziell dafür vorgesehene Kontrollerklasse delegieren.
|
 |
-
Assoziation:
-
Eine allgemeine, unspezialisierte Assoziation bestimmt, daß zwei
Klassen durch irgendeine andere natürliche Eigenschaft, die bei der
Analyse auftrat, miteinander verbunden sind.
-

-
Zum Beispiel kann eine Assoziation einen Vogel als "Vater" mit einem anderen
Vogel als "Kind" verbinden.
|
 |
-
Dependency:
-
Dies ist eine Beziehung die, ganz unspezifisch, keine detaillierte Auskunft
über die Art der Verbindung zwischen zwei Klassen (häufiger zwischen
Modulen) macht. Diese Beziehung wird quasi nur auf der höchsten Designebene
während der Systemarchitektur verwendet.
-

-
In einer modernen Architekturspezifikation wird vermutlich immer stehen,
daß ein Modul "FrontEnd", was für die Ausgabe zuständig
ist, eine Dependencybeziehung zum Modul "Fensterverwaltung" unterhält.
|
 |
Alle Beziehungen können durch sogenannte Rollen
an beiden Enden näher erläutert sein, und sie können durch
einschränkende Mengenangaben (Constraints) quantifiziert sein,
die bestimmen, in welchen Verhältnissen die Beziehungen auftreten
können. In seltenen Fällen kann auch durch einen unidirektionalen
Pfeil die normale Bidirektionalität einer Beziehung aufgehoben werden,
so, daß nur noch einer der Beziehungspartner von der Existenz des
anderen weiß (siehe Verkapselung).
In so einem Fall spricht man auch davon, daß die bidirektionale Navigierbarkeit
einer Beziehung aufgehoben ist. |
 |
Beispiel
für solche weiteren Spezifierungen einer Beziehung ist eine spezielle
Beziehung zwischen Vogeleltern und Vogelkindern, deren Elternrolle "isParentOf"
und Kinderrolle "hasParent" ist. Diese Beziehung wäre
eine Assoziation und ist dadurch gekennzeichnet, daß sie in einer
2 zu 0..* Beziehung auftritt. Das heißt, daß genau zwei Vögel
Eltern für keinen bis beliebig viele Vogelkinder sind. Hier ist die
Navigierbarkeit üblicherweise vollständig bidirektional, weil
sowohl jeder der Eltern weiß, wer seine Kinder sind, als auch jedes
Kind seine ernährenden Eltern kennt.
4.2.2 Klassendiagramme
Die UML widmet sich dem Entwurf von MKM dadurch, daß sie mehrere
unterschiedliche Arten von Diagrammen spezifiziert. Jedes dieser Diagramme
standardisiert die visualisierte Notation einer Art Teilmodell. Man unterteilt
in Diagramme, die die statische Architektur eines Programms erläutern
und Diagramme, die das dynamische Verhalten während des Programmablaufs
veranschaulichen. Das wichtigste Diagramm im Zusammenhang mit OOPS ist
ein statisches, das Klassendiagramm.
Das Klassendiagramm veranschaulicht jede Klasse mit einem Rechteck,
in dem die wichtigsten Felder der Klasse notiert sind. Alle Klassen werden
so aufgezeichnet und untereinander mit den Darstellungen der im jeweiligen
Fall zutreffenden Beziehungen verbunden. Objekte einer Klasse werden durch
Rechtecke mit abgerundeten Ecken angedeutet.
4.3 Methode
Um das Ziel des OOD möglichst effizient zu erreichen, gibt es Ansätze
in der Grady Booch-, OMT- und OSE-Methode. Diese Methoden widmen sich jedoch
allesamt anderen Teilaspekten des Designs und sind spezifisch für
die ihnen zugrundeliegenden, alten Notationen. Auch vernachlässigen
diese Methoden Lösungsverfahren, die an einigen Stellen alternativ
eingesetzt werden könnten. Im neuen Standard, der UML gibt es bis
jetzt noch überhaupt keine Modellierungsmethode. Ein möglicher
Ansatz für eine neue Modellierungstechnik soll im folgenden eingeführt
werden. Einige Teilmethoden darin sind - mit entsprechender Anpassung -
aus der OMT8 übernommen.
Alle Elemente der OOA werden vorerst in das Designmodell übernommen.
Die Elemente werden in der OOD zusätzlich strukturiert und nach Kategorien
geordnet. Solche Designprozesse werden Schritt für Schritt für
alle Elemente (auch die während des Designs neu entstandenen) durchgeführt,
und können auf zwei unterschiedliche Arten ablaufen (siehe auch Softwareentwicklung):
-
bottom-up:
Aus vorhandenen Elementen werden allgemeinere Elemente gebildet. Elemente
mit gemeinsamer Struktur und Eigenschaften werden zusammengefaßt
zu hierarchisch höher angesiedelten, allgemeinen Basiselementen. Handelt
es sich bei den Elementen um Objekte oder deren Klassen, so werden auf
diese Weise neue Basisklassen erzeugt (siehe Generalisierung).
-
top-down:
Vorhandene Elemente werden zu problemspezifischeren spezialisiert. Im Falle
von Objekten und Klassen werden so neue Subklassen gebildet.
In beiden Fällen zeugt es von gutem Design, wenn die Untermodelle,
die durch solche Hierarchien entstehen, sich durch eine große innere
Kohäsion aber eine geringe äußere
Kopplung zu anderen Untermodellen auszeichnen.
Für Untermodelle gilt hier eine Analogie zur Modularität und
Verkapselung bei der OO-Entwicklung.
Die Designmethode besteht aus zwei Teilen, dem Systemdesign und dem
Objektdesign. Das Objektdesign folgt in - an die UML angepaßter -
erweiterter Fassung, das Systemdesign der Architektur ist weitgehend unabhängig
vom OOPS und folgt im Anhang unter Systemdesign.
4.3.1 Objektdesign
-
Die Algorithmen der wichtigen Operationen in den Klassen beschreiben, die
hochstufige Schnittstellen zu anderen Klassen haben.
-
Sich dadurch ergebende, neue Implementationsklassen ins Objektmodell mit
aufnehmen.
-
Ein Architekturstil wird festgelegt. Der Kontrollfluß soll je nach Anforderung den folgenden
Kommunikationsstilen gemäß implementiert werden:
-
sequentiell:
-
Das Programm läuft in strikter, logischer Reihenfolge ab, genauso,
wie wenn bei konventioneller Programmierung mit Prozeduren das Hauptprogramm
Schritt für Schritt ausgeführt wird.
-
ereignisorientiert:
-
Die Programmfunktionen werden quasi-parallel durch Ereignisse wie Befehle
des Benutzers durch äußere Einflüsse dynamisch von einem
Verwaltungssystem aufgerufen.
-
strombasiert:
-
Die Programmfunktionen liefern einen Strom von Daten, die den jeweils nächsten
Funktionen übertragen werden. Hierzu werden oft Iteratoren als Schnittstellen
verwendet.
-
parallel:
-
Auf einem Computer mit mehreren Prozessoren werden gleichzeitig
oder zumindest nebenläfig (d.h. in beliebiger Reihenfolge, auch gleichzeitig)
mehrere Funktionen des Programms ausgeführt.
Solche Programme erfordern
besondere Mechanismen um zu gewährleisten, daß die Ergebnisse
der parallelen Funktionalitäten (sogenannter Prozesse) rechtzeitig
synchronisiert werden, um eine sonst drohende Inkonsistenz der Daten zu
vermeiden.
-
Alle Operationen durch Algorithmen beschreiben. Dabei sollten Operationen
aufgeteilt werden in:
-
höherwertige, die Entscheidungen treffen, die den Kontrollfluß
beeinflussen.
-
niedrigerwertige, die der reinen Verarbeitung von Daten dienen.
-
Ähnliche Operationen zusammenfassen.
-
Gleiche Attribute unterschiedlicher Klassen in neuen Basisklassen zusammenfassen.
-
Die zugrundeliegenden Datenstrukturen für die Datenverwaltung beschreiben,
also auch festlegen, ob Daten in Listen, Arrays oder Bäumen gehalten
werden sollen.
-
Die Beziehungen näher beschreiben und durch Implementierungsattribute,
-operationen oder Implementierungsklassen realisieren. Dabei beachten,
welche Beziehungen häufig durchsucht oder häufig geändert
werden.