Entwurf

Ziel dieser Phase ist es, die Architektur des Softwaresystems festzulegen. Diese komplexe Aufgabe kann man in folgende Schritte aufteilen:
  1. Zerlegung in Teilsysteme und Spezifikation der Wechselwirkungen zwischen den Teilsystemen
  2. weitere Zerlegung der Teilsysteme in Komponenten (Module), Spezifikation der Anforderungen an diese Komponenten durch Festlegung der Modulschnittstellen.
  3. Entwurf der Algorithmen, die die geforderte Funktionalität bereitstellen.

Entwurfstechniken

Wichtigstes Hilfsmittel zur Meisterung von Komplexität ist das Prinzip der Abstraktion. Anhand der Reihenfolge, in der man zu Abstraktionen gelangt, lassen sich die beiden folgenden Vorgehensweisen unterscheiden:
Topdown-Entwurf
Ausgangspunkt ist eine Analyse der Systemspezifikation. Realisierungsdetails werden zunächst nicht betrachtet. Man beginnt mit abstrakt beschriebenen Lösungsideeen, die nach und nach konkretisiert werden, aber nur soweit, wie dies für das momentane Verständnis des Systems notwendig ist. Die Grundidee dieser Vorgehensweise geht auf Dijkstra und Wirth zurück.
Bottomup-Entwurf
Hardware und darüberliegende Schichten (vom Betriebssystem bis zur vollständigen Applikation) bilden abstrakte Maschinen. Man geht also von den Gegebenheiten einer gegebenen, "konkreten Maschine" aus, die um benötigte Eigenschaften nach und nach ergänzt wird, bis schließlich die zur Bereitstellung der gewünschten Funktionalität notwendige Maschine verwirklicht ist.
Nicht nur die Reihenfolge, in der man zu den unverzichtbaren Abstraktionen gelangt, sondern auch die Kriterien, nach denen ein System in Teile zerlegt wird, haben entscheidenden Einfluß auf das Entwurfsergebnis. Folgende Entwurfsprinzipien lassen sich unterscheiden:
funktionsorientiert
Das System wird betrachtet als eine Black-Box, die in der Lage ist, eine (oder mehrere) Funktionen zu erbringen. Diese Funktionen, beschrieben in den funktionalen Anforderungen der Systemspezifikation, werden schrittweise in Teilaufgaben zerlegt, bis ihre Komplexität so gering ist, dass sie direkt realisiert werden können. Die für diese aufgabenorientierte Zerlegung vorgeschlagenen Methoden und Prinzipien gehen auf Wirth (stepwise refinement) und Yourdan/Constantine (structured design) zurück.
datenorientiert
die Struktur der zu verarbeitenden Daten bestimmt die Struktur des Softwaresystems. Beispiele finden sich im Compilerbau und häufig in der kommerziellen Datenverarbeitung. Die wichtigsten Methoden sind attributierte Grammatiken und, als Spezialfall davon, die von Jackson vorgeschlagenen Methoden und Prinzipien.
objektorientiert
Ein Softwaresystem wird angesehen als eine Sammlung von miteinander kommunizierenden Objekten. Jedes Objekt besitzt
  1. einen von außen nicht zugänglichen Zustand (meist realisiert durch Datenstrukturen, die nur dem Objekt zugänglich sind) und
  2. ausführbare Operationen, die allen "Kunden" des Objektes zur Verfügung stehen und mit denen möglicherweise dieser Zustand geändert oder beobachtet werden kann.
Die Objekte tauschen Nachrichten aus, die dem Empfängerobjekt mitteilen, welche seiner Operationen ausgeführt werden soll. Die Zerlegung orientiert sich dabei an der Zusammengehörigkeit von Daten und Funktionen. Entscheidend für die Reduktion von Komplexität ist die strikte Einhaltung des Geheimnisprinzips. Es besagt, dass einem "Kunden" eines Objektes nur soviel Wissen über ein Objekt zur Verfügung steht, wie er zur Verwendung der "öffentlichen" Operationen des Objektes benötigt.

Modularisierung

Die Zerlegung der Projektaufgabe in Teilaufgaben ist Grundvoraussetzung für Arbeitsteilung und Teamwork. Die Absprache der Teilaufgaben macht eine frühe Festlegung der Schnittstellen zwischen den Teilaufgaben notwendig. Gelingt dies in ausreichender Präzision und Stabilität, können die Teilaufgaben weitgehend unabhängig voneinander durch verschiedene Bearbeiter(gruppen) gelöst werden, und zwar unter Einhaltung der in der Schnittstellendefinition getroffenenen Vereinbarungen. Dies garantiert, dass die Lösungen der Teilaufgaben zu einer Lösung für das Gesamtsystem integriert werden können.

Richtlinien

Ein Modul Die zentrale Frage der Modularisierung lautet: Welche Operationen werden mit welchen Daten in einem Modul zusammengefaßt? Folgende Kriterien kann man berücksichtigen, um zu einer guten Modularisierung des Systems zu gelangen:
Geschlossenheit und Bindung (cohesion)
meint den inneren Zusammenhang, die Zusammengehörigkeit der Operationen und Daten in Bezug auf die in sich abgeschlossene Aufgabe des Moduls. Ziel ist eine hohe Bindung.
Kopplung (coupling)
eines Moduls drückt aus, wie stark es mit anderen Modulen verbunden und damit von ihnen abhängig ist. Ziel ist eine geringe Kopplung.
Minimale Schnittstelle
erkennt man z.B. an wenigen (am besten gar keinen) globalen Variablen, wenigen exportierten Prozeduren mit kurzen Parameterlisten und einer kurzen, leicht verständlichen Schnittstellenbeschreibung. Sie verringert die Gefahr einer hohen Modulkopplung.
Größe
eines Moduls ist leicht meßbar, sagt aber meist recht wenig über seine Komplexität. Eine sinnvolle Regel für eine anzustrebende Größe gibt es nicht.
Testbarkeit
meint den Test des Moduls als eigenständige Einheit (in der Phase Modultest). Dies wird entscheidend erleichtert durch geringe Kopplung und eine knappe Schnittstelle.
Interferenzfreiheit
drückt aus, daß ein Modul keine unerwünschte Nebenwirkung auf ein anderes hat. Nur wenn dies gewährleistet ist, kann man ein Modul durch ein anderes mit gleicher Schnittstellendefinition ersetzen und damit Änderbarkeit und Wartbarkeit eines Programmsystems steigern.
Importzahl
gibt an, wieviele weitere Module für die Implementierung des Moduls benutzt werden. Eine hohe Importzahl ist ein Indiz für eine hohe Kopplung.
Verwendungszahl
gibt an, wieviele andere Module dieses Modul verwenden. Eine hohe Verwendungszahl ist Indiz für Allgemeinheit und hohe Wiederverwendbarkeit.
Modulhierarchie
großer Programmsysteme enthält typischerweise vier übereinanderliegende Ebenen, wobei auf einer Ebene die Dienste von Modulen tieferer Ebenen verwendet werden:
  1. das Steuermodul an der Spitze der Modulhierarchie ist für Koordinierung, Initialisierungs- und Abschlußarbeiten zuständig. Es ist meist recht kurz.
  2. problemorientierte Module stellen die eigentlichen, anwendungsspezifischen Algorithmen zur Problemlösung bereit.
  3. Hilfsmodule stellen häufig benutzte Operationen allgemeiner Natur bereit. Beispiele sind Verwaltung von Tabellen, Listen, Bäumen, ...
  4. Module zur Kommunikation mit Hardware und mit Betriebssystem sind meist nicht problemspezifisch und stehen fast immer in Bibliotheken zur Verfügung.

Abstrakte Datenstrukturen und abstrakte Datentypen

Mit Modulen lassen sich Datenkapseln bilden. Sie verhindern unbeschränkte Zugriffe auf globale Daten, eine Fehlerquelle ersten Ranges. Statt jedermann auf komplexe Datenbestände zugreifen zu lassen, werden abstrakte Datenstrukturen (ADS) angelegt, die Zugriff auf gemeinsame Daten nur noch über einige, ausgezeichnete Prozeduren erlauben. Das Wissen über die komplexen Datenbestände besitzen nur noch diese Zugriffsroutinen, die dann auch verantwortlich für deren Konsistenz sind. Beim Entwurf einer ADS werden zunächst die benötigten Zugriffsroutinen identifiziert, um dann mit den Daten, die gekapselt werden sollen, in ein Modul zusammengefasst zu werden. Danach ist Zugriff auf die Datenstruktur nur noch über die Schnittstelle des Moduls, d.h. über die exportierten Zugriffsroutinen möglich.

Zur Erzeugung mehrerer, gleichartiger abstrakter Datenstrukturen dienen abstrakte Datentypen. Dort werden die Daten nicht mehr in ein Modul gekapselt, sondern den Zugriffsroutinen als Parameter übergeben, wie im folgenden Beispiel für einen abstrakten Datentyp Text in Modula-2 Notation:

     DEFINITION MODULE TextMod;
       TYPE Text;

       PROCEDURE NewText    (VAR t:Text);
       PROCEDURE DisposeText(VAR t:Text);
       PROCEDURE AppendChar (VAR t:Text; ch:CHAR);
       PROCEDURE GetChar    (VAR t:Text; index:CARDINAL; VAR ch:CHAR);
       PROCEDURE TextLength (VAR t:Text):CARDINAL;
       PROCEDURE InsertChar (VAR t:Text; before:CARDINAL; ch:CHAR);
       PROCEDURE DeleteChar (VAR t:Text; index:CARDINAL);

     END TextMod;
Als Besonderheit von Modula-2 sind die opaque types ("undurchsichtige Datentypen") ein entscheidendes Hilfsmittel, das Geheimnisprinzip für abstrakte Datentypen auch durchzusetzen: Im obigen Beispiel ist dem Verwender des Moduls nur der Name Text des abstrakten Datentyps bekannt, nicht aber die Datenstruktur von Text, die erst im IMPLEMENTATION MODULE festgelegt wird, und damit einem Verwender des Moduls prinzipiell unbekannt und, wichtiger, nicht zugänglich ist.

Entwurf von Benutzerschnittstellen

Diese Entwurfsaufgabe wird größtenteils schon während der Systemspezifikation angegegangen, weil Art und Weise der Programmbedienung schon im Pflichtenheft festgelegt werden muss, häufig durch Festschreibung eines Prototyps.

Folgende grundlegende Anforderungen an den Zielrechner werden im folgenden vorausgesetzt: grafischer Bildschirm, Maus, Fenstertechnik, Menüs.

Zustände. Entscheidenden Einfluss hat der Leitsatz "Avoid Modes", wobei "Mode" eine Situation meint, in der der Benutzer nur eine beschränkte Anzahl von Operationen ausführen kann. Zustände (in diesem Sinne) engen den Benutzer ein und zwingen ihn, von seiner natürlichen Arbeitsweise abzuweichen. Als Konsequenz wird man also statt eines Dialoges, der vom Benutzer nach und nach bestimmte Informationen in einer starren, vom System vorgegebenen Reihenfolge abfragt, ein Formular anbieten, in das der Benutzer die vom Programm benötigte Information in frei gewählter Reihenfolge eintragen kann. Sind verschiedene Zustände (Modes) nicht vermeidbar, empfiehlt es sich, ein eigenes Fenster dafür einzuführen.

Zustände lassen sich auch dadurch vermeiden, dass man komplexe Benutzeraktionen in kleine, einfache, unteilbare Elementaroperationen zerlegt. Z.B. kann man den Befehl move 1-3,10 in vier Elementaroperationen zerlegen:

  1. Auswahl der ersten drei Zeilen (Mausbefehl) ,
  2. Menükommando "Cut",
  3. Versetzen der Einfügemarke vor Zeile 10 (Mausbefehl),
  4. Menükommando "Paste".
Menüs. Sie bedeuten für ungeübte und gelegentliche Benutzer eine erhebliche Arbeitserleichterung. Pulldown -Menüs sind am häufigsten anzutreffen, auch deshalb, weil sie eine große Menge von Befehlen übersichtlich strukturieren können und dem Benutzer die zur Verfügung stehenden Operationen jederzeit übersichtlich präsentieren. Menübefehle können nach ihrer Funktion in drei Klassen eingeteilt werden:
  1. sofort ausführbar (z.B. "Cut" , "Paste")
  2. ausführbar erst, nachdem der Benutzer weitere Parameter angegeben hat (z.B. "Find...")
  3. zur Zustandsänderung (z.B. "Show Controls")
Menübefehle können für geübte Benutzer lästig werden, weil sie durch den Wechsel zwischen Maus und Tastatur den Arbeitsfluss unterbrechen. Daher werden meist Tastaturkürzel angeboten, mit denen die wichtigsten Menübefehle aktiviert werden können.

Oft sind Menübefehle nur in bestimmten Zuständen ausführbar, z.B. ist "Copy" erst sinnvoll, wenn in einem aktiven Fenster etwas selektiert ist. In einem solchen Fall kann man den Menübefehl ohne Wirkung lassen, oder, besser, eine Fehlermeldung nach Aktivierung dieses Befehls ausgeben, oder, am besten, die Auswahl des nicht ausführbaren Befehls von vornherein verhindern. Dies sollte man aber nicht erreichen, indem man den Befehl aus dem Menü entfernt, sondern ihn geeignet als inaktiv markiert.

Masken, Dialogboxen. Sie wurden früher zur zustandsfreien Eingabe von Textfeldern in Bildschirmformularen genutzt. Heute sind weitere Gestaltungsmittel hinzugekommen: Statischer Text, Editierbarer Text, Befehlsknopf, Ein-/Ausschalter, Umschalter, Popup-Menüs, Schieberegler, Auswahlleisten, Piktogramme, Trennlinien, Rahmen, ... Alle gängigen grafischen Benutzeroberflächen bieten Bibliotheken an, mit denen diese Gestaltungsmittel einfach verwendet werden können.

Farbe. Farbbildschirme stehen fast überall zur Verfügung. Der Einsatz von Farbe sollte allerdings folgende Punkte beachten:

Ton. Die Zeiten, in denen Computer nur einfache Piepser von sich geben konnten, sind vorbei. Der sinnvolle Einsatz von Tönen ist heute fast überall möglich. Bei der Gestaltung des Einsatzes sollte man folgende Punkte beachten: Konsistenz. Einheitlichkeit der Benutzerschnittstelle innerhalb eines Programms muß eine Selbstverständlichkeit sein. Dies wirkt sich u.a. aus auf Benenung und Gruppierung der Menübefehle, Tastaturabkürzungen, Beschriftung und Positionierung der Knöpfe.

Ähnlichkeiten und Übereinstimmungen mit den Benutzerschnittstellen anderer Programme, die auf demselben Computer verwendet werden, sollte man anstreben, allein um den Lernaufand für den neuen Benutzer gering zu halten. Ein neues Programm wird eher akzeptiert, wenn es schnell erlernbar ist und keine Überraschungen bereithält. Was würden Sie von einem Auto halten, bei dem die Position von Gas- und Bremspedal vertauscht sind?

Objektorientierter Entwurf

Ein Objekt ist ein Ding mit eigener Individualität und Identität. Es besitzt Attribute, zeigt ein Verhalten, gehört zu einer (Objekt-)Klasse und kann Beziehungen zu anderen Objekten besitzen. Objekte können neu entstehen, sich verändern und auch wieder verschwinden. Mengen gleichartiger Objekte werden zu Klassen zusammengefasst. Eine Klasse läßt sich als Herstellungsvorschrift für ein Objekt deuten, ein Objekt ist Instanz einer Klasse.

Die zentrale Frage des objekt-orientierten Entwurfs lautet: Wie findet man die zur Aufgabenlösung geigneten Objekte und die zu ihnen gehörenden Aktionen? In der Literatur findet man zahlreiche, unterschiedliche und meist recht detailliert ausgearbeitete Ansätze für objekt-orientierte Analyse und objekt-orientierten Entwurf. Häufig liegt das Hauptgewicht auf einer speziellen, meist grafischen Notation. Viele gehen vom Entity-Relationship Modell zur Modellierung der Beziehungen zwischen Objekten aus, andere verwenden semantische Netze. Bisher hat sich keines der empfohlenen Verfahren auf breiter Front durchgesetzt.

Im folgenden wird daher ein sehr elementares Verfahren zum Auffinden der Objekte beschrieben, ohne auf die oben erwähnten, detaillierteren Ansätze näher einzugehen.

Methode von Abbot

Ausgangspunkt und Grundlage ist ein in Umgangssprache formulierter Text, der die Aufgabenstellung verbal beschreibt. Er kann z.B. der Systemspezifikation oder auch anderen Dokumenten (z.B. Formulare, Daten, Gerätebeschreibungen, Archive) entnommen sein. Entscheidend ist, dass sie für den Problembereich relevante Beschreibungen liefern. Abbot empfiehlt, bestimmte Wortarten in der Spezifikation zu suchen und aus ihnen den Entwurf abzuleiten. Ursprünglich zielte die Methode darauf, abstrakte Datenstrukturen zu bilden und die mit ihnen erforderlichen Operationen zu bestimmen. Sie kann aber auch sinnvoll als Grundlage für einen objekt-orientierten Entwurf verwendet werden. Man folgt folgenden Schema:
Hauptwörter herausfiltern
mit dem Ziel, Objekte und Klassen zu identifizieren und zu benennen. Gattungsnamen wie z.B. "Mensch", "Auto", "Ampel", "Vorlesung" sind Kandidaten für Klassen, Eigennamen wie z.B. "Albert Einstein", "Paris", "FH Gießen-Friedberg" sind Kandidaten für Objekte. Häufig führt ein Eigenname auch zu einem entsprechenden Gattungsnamen, z.B. "Physiker", "Stadt", "Hochschule". Unergiebig in diesem Zusammenhang sind Mengen- und Größenangaben ("Liter"), Materialbezeichnungen ("Holz"), Sammelnamen ("Regierung") und abstrakte Begriffe ("Schönheit", "Arbeit"). Sie führen meist nicht zur Identifizierung von Klassen. Im Deutschen werden häufig Zeitwörter als Hauptwörter verwendet, z.B. "das Abspielen von Musik". Sie deuten auf Aktionen hin und werden behandelt wie die zugehörigen Zeitwörter (s.u.).
Gemeinsamkeiten suchen.
In der Regel treten in der Spezifikation viele verwandte Hauptwörter auf, wie z.B. "Abteilungsleiter" und "Vorgesetzter", "Autor" und "Verfasser", "Auto" und "Kraftfahrzeug". Dann ist zu klären, ob es sich wirklich um verschiedene Begriffe handelt. Dies ist der Fall, wenn die Objekte dieser Klassen verschiedene Eigenschaften besitzen, die auch für die Anwendung relevant sind. Steht fest, dass zwei verwandte Begriffe verschieden sind, sollte man klären, in welcher Beziehung sie zueinander stehen. Häufig entdeckt man eine Teilmengenbeziehung (Ist-ein-Relation), die man an Sätzen wie "Jedes Auto ist ein Kraftfahrzeug" erkennt. Die Teilmengenbeziehung ist die Grundlage, auf der Klassenhierarchien (s.u.) gebildet werden.
Relevante Zeitwörter auffinden
Sie bezeichnen Aktionen mit Objekten. Im Gegensatz zum funktionsorientierten Ansatz wird eine Aktion aber nicht isoliert betrachtet, sondern immer im Zusammenhang mit dem Objekt, zu dem sie gehört. Sie wird zu einer Methode dieses Objektes. Zum Beispiel gehört das Zeitwort "umschalten" zu einer Verkehrsampel, das Zeitwort "beschleunigen" hängt mit einem Kraftfahrzeug zusammen. Die Zuordnung von Aktion zu Objekt kann manchmal schwierig sein, wenn z.B. ein Satz wie der folgende vorliegt: "Das Auto soll auf dem Bildschirm angezeigt werden." Wird die Aktion "anzeigen" dem Auto oder dem Bildschirm zugeordnet? Dies wird häufig so gelöst, dass die Aktion beiden Klassen zugeordnet wird, bei der Implementierung eine der beiden Operationen auf die andere zurückgeführt wird.
Die oben genannten Regeln sind kein allgemein gültiges Rezept, das einen guten Entwurf garantiert. Entscheidenden Einfluss hat auch Umfang und Qualität der Spezifikation. Sie sollte möglichst in der Sprache des Problembereichs verfasst sein. Dies führt zu Klassen, deren Bedeutung auch der Auftragggeber verstehen kann.

Eine natürliche, objekt-orientierte Zerlegung des Gesamtsystems führt zu einer Sammlung von Klassen mit klaren Schnittstellen, die weitgehend unabhängig voneinander behandelt werden können. Man geht meist schrittweise vor: Am Anfang des Entwurfprozesses stehen Objekte aus dem Problembereich, die zunächst nur als Black Boxes betrachtet werden, die aber immer konkretere Gestalt annehmen. Beim algorithmischen Entwurf der Aktionen wird man in der Regel auf weitere Klassen stossen, die mit der ursprünglichen Aufgabenstellung nur noch am Rande zu tun haben. Beim Entwurf eines Simulationsprogrammes für eine Ampelsteuerung könnten z.B. der Reihe nach folgende Klassen entstehen:

  1. direkt aus der Spezifikation: Verkehrsampel, Auto, Straße, Kreuzung, Zeit, Statistik.
  2. beim Entwurf der Klassen aus 1: Fahrspur, Richtung, Farbe, Histogramm.
  3. beim algorithmischen Entwurf der Operationen: Ereignis, Generator, Warteschlange, Liste, Menge, Matrix.

Klassenhierarchien

Wesentliches Kennzeichen des objekt-orientierten Ansatzes ist die Möglichkeit, Hierrarchien zwischen Klassen aufzubauen und auszunutzen. Hierbei werden ähnliche Dinge erkannt und unter gemeinsame Oberbegriffe zusammengefasst. Dadurch entsteht eine Baumstruktur, bei der allgemeine, abstrakte Begriffe nahe der Wurzel stehen, und die Blätter die spezialisierten, konkreten Begriffe darstellen.
 
KFZ Auto LKW
PKW Limousine
Cabriolet
Kombi
Zweirad Moped Mofa
Motorrad
Klassenhierarchie der Kraftfahrzeuge
Die Klasse KFZ bestimmt die allgemeinen Eigenschaften der von ihr abgeleiteten Klassen. Unabhängig von der Art des KFZ hat jedes KFZ Marke, Typ, Seriennummer, Motorleistung, .. Jedes Auto hat ebenfalls diese Eigenschaften, weil es (auch) ein KFZ ist. Weiterhin besitzt ein Auto weitere, spezifische Merkmale z.B. Anzahl der Türen. Bei jedem Spezialisierungsschritt kommen weitere Eigenschaften hinzu.

Mit zunehmender Spezialisierung nimmt auch die Funktionalität zu. Mit einem Cabriolet kann z.B. alles machen, was auch mit einem PKW möglich ist, darüber hinaus kann man aber auch sein Dach öffnen.

Für die Implementierungssprache hat die Unterstützung von Klassenhierarchien zwei wichtige Konsequenzen:

Vererbung
Eigenschaften und Funktionen, die für eine allgemeine Klasse definiert sind, gelten automatisch auch für alle von ihr abgeleiteten, spezielleren Klassen. Gibt es z.B. für ein Auto eine Funktion, die aus Luftwiderstandsbeiwert und Motordaten seine Höchstgeschwindigkeit berechnen, so kann diese Funktion auch auf alle Objekt abgeleiteteter Klassen angewendet werden.
Polymorphismus
Ein Programmstück, das für Objekte einer Klasse K funktioniert, kann auch mit Objekten einer von K abgeleiteten Klasse arbeiten, obwohl solche Objekte anderen Aufbau und anderes Verhalten als K-Objekte besitzen können. Dies ist möglich, weil in abgeleiteten Klassen nur neue Eigenschaften hinzukommen, aber niemals welche entfernt werden. Eine weitere Voraussetzung für Polymorphismus ist die strikte Einhaltung des Geheimnisprinzips: das Programmstück funktioniert auch für Objekte mit verschiedenen Implementierungen, weil das Programmstück diese Kenntnis nicht besitzt und auch nicht verwenden kann, sondern lediglich die Information in der Schnittstellenbeschreibung der Klasse K ausnutzen kann.
Abstrakte Klassen. Oft kommen in einer Spezifikation Begriffe vor, die sich in vielerlei Hinsicht ähneln, aber in einigen Details deutlich unterscheiden. Als Beispiel diene ein Programm, das Kreise und Rechtecke anzeigen soll. Beide weisen Eigenschaften auf, die gemeinsam behandelt werden können und sollen (Strichstärke, Farbe, Füllmuster, bewegen auf dem Bildschirm). Sie können aber nicht sinnvoll mit einer Ist-ein-Beziehung verknüpft werden. In solchen Fällen sollte man eine gemeinsame Oberklasse schaffen, der die beiden Klassen untergeordnet werden können, z.B. "Grafik". Die "Rechteck" und "Kreis" gemeinsamen Eigenschaften werden in die gemeinsame Klasse verlegt, nur spezielle Eigenschaften und Operationen (Mittelpunkt und Radius, Breite und Höhe, Zeichenoperationen) verbleiben in den abgeleiteten Klassen. Die gemeinsame Oberklasse ist eine Abstraktion der speziellen Klassen und besitzt keine eigenen Objekte. Man spricht daher von einer abstrakten Klasse.

Das Verfahren von Abbot ist ein analytisches Topdown-Verfahren: Es geht von der Aufgabenstellung aus, beginnt mit dem Entwurf anwendungsspezifischer Klassen und schreitet fort zum Entwurf implementierungsspezifischer Klassen. Dabei wird auf eventuell schon bestehende Klassen keine Rücksicht genommen. Diese werden aber für viele Anwendungsbereiche in Klassenbibliotheken bereitgestellt. Außerdem ist es erklärtes Ziel des objekt-orientierten Ansatzes, bestehende Klassen wiederzuverwenden. Dies wird erreicht durch den alternativen Ansatz des konstruktiven Bottomup-Vorgehens. Hier wird versucht, aus den zur Verfügung stehenden Klassen eine Problemlösung zu konstruieren. Dies wird gelingt jedoch selten vollständig, da problemnahe Klassen in Bibliotheken meist nicht bereit stehen. So wird man beide Ansätze verfolgen müssen und das Produkt von zwei Seiten wachsen lassen:auf der einen Seite durch problemnahe, mit der Abbot-Methode entworfenen Klassen, auf der anderen Seite durch Konstruktion und Kombination bestehender Klassen mit Lösungen für Standardprobleme.

Überlegungen zum Klassenentwurf

  1. Was sind die physischen und logischen Objekte des realen Systems? Die Antwort führt zu den Klassen .
  2. Welche Operationen kann man mit diesen Objekten ausführen? Die Antwort führt zu den Methoden
  3. Welche Daten müssen in einem Objekt gespeichert werden, damit die Operationen ihre Aufgabe erfüllen können? Die Antwort führt zu den Attributen des Objekts, sie bilden den Objektzustand.

Generalisierung

Wiederverwendbarkeit spielt eine zentrale Rolle im objet-orientierten Entwurf. Innerhalb eines Progammes wird Wiederverwendung durch Vererbung unterstützt, bei programmübergreifender Wiederverwendung gehören Klassenbibliotheken zu den wichtigsten Hilfsmitteln. Die Klassen in solchen Bibkliotheken sollten eine möglichst hohe Allgemeinheit anstreben, um ihre Verwendbarkeit in vielen Projekten, auch unter nicht vorhergesehenen Umständen sicherzustellen. Folgende Maßnahmen sind dabei zweckmäßig: Ein weiteres, wichtiges Hilfsmittel ist der Einsatz von erprobten Entwurfsmustern.

Statische Beziehungen zwischen Klasse

Zum Entwurf gehört auch die Analyse der Beziehungen zwischen Klassen. Man kann folgende drei Arten von Beziehungen unterscheiden:
Ist-Ein-Beziehung
Sie gilt zwischen allgemeiner Klasse A und spezieller Klasse S, wenn jedes S-Objekt auch ein A-Objekt ist. Häufig verwendete Sprechweisen: A ist Oberklasse und S ist Unterklasse, A ist die Basisklasse ´und S eine (von A) abgeleitete Klasse.
Aggregationsbeziehung (Hat-Beziehung)
Sie gilt zwischen Objekten G (das Ganze) und Ti (der Teil), wenn Ti ein Teil von G ist. Anders ausgedrückt, wenn G aus ein oder mehreren T1, T2, ..Tn besteht. Z.B besteht ein Auto aus einem Motor, einer Karosserie und vier Rädern.
sonstige Assoziationen
Damit sind alle anderen Beziehung zwischen Objekten gemeint. Z.B. die Beziehung "bucht" zwischen "Passagier" und "Flug"
Die Beziehungen zwischen Klassen kan man in Entity-Relationship Diagrammen grafisch veranschaulichen. Es gibt verschiedene Notationen. In der Chen-Notation werden Entity-Typen (= Klassen) als beschriftete Rechteck dargestellt, die Beziehungstypen als beschriftete Rauten, die mit den beteiligten Entity-Typen durch Linien verbunden sind. An die Linien wird der Grad der Beziehung geschrieben.Auch dafür gibt es (zu)viele Notationen. Bewährt hat sich folgende Intervallnotation. Das Bild
A ---(minA,maxA)--- <R>---(minB,maxB)---B

besagt, dass jedes A-Objekt am R-Beziehungstyp mindestens minA-mal und höchstens maxA-mal beteiligt ist. Analoges gilt für B-Objekte.

Weitere Entwurfshinweise

In einer hybriden Programmiersprache wie z.B. C++, in der man objekt-orientierte Konzepte verwenden kann, aber auch andere Ansätze realisieren kann, stellt sich die Frage: Wann ist es sinnvoll, Klassen einzusetzen? Die folgenden Fragen führen zu einer Antwort:
  1. Bringt Datenabstraktion eine Vereinfachung? Sind die Daten komplex genug? Falls nicht, reicht es, einen konkreten Datentyp der Programmiersprache zu verwenden.
  2. Falls ja, gibt es mehrer Exemplare der Daten? Falls nicht, sollte man sie als abstrakte Datenstruktur anlegen.
  3. Falls ja, existieren Daten in Varianten, die gleich behandelt werden sollen? Falls nicht, reicht es, einen abstrakten Datentyp anzulegen. Andernfalls sollte man eine Klasse vorsehen.
Die folgenden Fehler sind häufig beim objekt-orientierten Entwurf zu beobachten: