Grundlagen der Modellierung - Objektorientierte Modelle: Unterschied zwischen den Versionen

Aus FernFH MediaWiki
Zur Navigation springen Zur Suche springen
Zeile 9: Zeile 9:
Bei der objektorientierten Modellierung werden Daten und Funktionen in Objekten abgebildet. Dabei werden alle Modellelemente einem oder mehreren Objekten zugeordnet.
Bei der objektorientierten Modellierung werden Daten und Funktionen in Objekten abgebildet. Dabei werden alle Modellelemente einem oder mehreren Objekten zugeordnet.


Bei der objektorientierten Modellierung werden die realen Objekte abstrahiert und dabei weiterhin als Objekte betrachtet. So wird beispielsweise ein ''Kunde'' als Objekt mit den Attributen ''Name'', ''E-Mail'' und ''Kundennummer'' abgebildet. Die grundlegenden Gliederungen der Objekte sind daher auch mit denen der ER-Datenmodelle aus Lektion 2.1 vergleichbar.
Bei der objektorientierten Modellierung werden die realen Objekte abstrahiert und dabei weiterhin als Objekte betrachtet. So wird beispielsweise ein ''Kunde'' als Objekt mit den Attributen ''Name'', ''E-Mail'' und ''Kundennummer'' abgebildet. Die grundlegenden Gliederungen der Objekte sind daher auch mit denen der ER-Datenmodelle aus dem Kapitel [[Entity-Relationship_Modell_(ER-Modell) | ER-Modell]] vergleichbar.


Zusätzlich zu Daten, werden einem Objekt auch Funktionen und Methoden zugeordnet. Durch sie kann es mit der Außenwelt interagieren. So kann Beispielsweise bei einem Objekt ''Auto'' eine Funktion ''„bremse aktivieren''“ existieren, die sich um das Einleiten einer Bremsung kümmert.
Zusätzlich zu Daten, werden einem Objekt auch Funktionen und Methoden zugeordnet. Durch sie kann es mit der Außenwelt interagieren. So kann Beispielsweise bei einem Objekt ''Auto'' eine Funktion ''„bremse aktivieren''“ existieren, die sich um das Einleiten einer Bremsung kümmert.
Zeile 102: Zeile 102:


<span id="die-unified-modeling-language-uml"></span>
<span id="die-unified-modeling-language-uml"></span>
== Die Unified Modeling Language (UML) ==
== Die Unified Modeling Language (UML) ==



Version vom 31. Oktober 2023, 19:45 Uhr

Objektorientierte Modelle

Die Grundlagen der objektorientierten Programmierung waren bereits Inhalt der Lehrveranstaltung „Einführung in die Programmierung mit C++“ und werden hier daher nicht mehr im Detail beschrieben. Nachfolgend werden die Grundlagen der objektorientierten Modellierung und die konkrete Anwendung durch die Unified Modeling Language (UML) genauer erläutert. Weiter werden die unterschiedlichen UML Modelle angeführt, welche ebenfalls zur Modellierung von Daten-, Prozess-, Ablauf- und Geschäftsmodellen eingesetzt werden können.

Grundlagen der objektorientierten Modellierung

Bei der objektorientierten Modellierung werden Daten und Funktionen in Objekten abgebildet. Dabei werden alle Modellelemente einem oder mehreren Objekten zugeordnet.

Bei der objektorientierten Modellierung werden die realen Objekte abstrahiert und dabei weiterhin als Objekte betrachtet. So wird beispielsweise ein Kunde als Objekt mit den Attributen Name, E-Mail und Kundennummer abgebildet. Die grundlegenden Gliederungen der Objekte sind daher auch mit denen der ER-Datenmodelle aus dem Kapitel ER-Modell vergleichbar.

Zusätzlich zu Daten, werden einem Objekt auch Funktionen und Methoden zugeordnet. Durch sie kann es mit der Außenwelt interagieren. So kann Beispielsweise bei einem Objekt Auto eine Funktion „bremse aktivieren“ existieren, die sich um das Einleiten einer Bremsung kümmert.

Klassen, Objekte und Vererbung

Die Definition des Aufbaues und der Struktur eines Objektes wird als Klasse bezeichnet. Ein Objekt ist eine konkrete Repräsentation einer Klasse, welche selbst eine eigene Identität innerhalb des Programmes zur Laufzeit hat. Das Ausführen von Objekt-Methoden und die Änderung von Objekt-Variablen hat damit eine Auswirkung auf das konkrete Objekt, nicht aber auf die Klasse und nicht auf die übrigen Objekte der Klasse. Bei einem Objekt als Repräsentation einer Klasse spricht man von einer Instanz und bei ihren Variablen von Instanz-Variablen, da ihr Inhalt nur für diese eine Instanz der Klasse gültig ist.

Eine Klasse gibt es daher immer nur einmal, da es sich dabei um die Definition möglicher Objekte handelt. Zu einer Klasse kann es beliebig viele Objekte geben.

Ein Beispiel für eine Klasse mit dazugehörigen Objekten ist in Abbildung 67 dargestellt. Es handelt sich dabei um die Klasse Kunde, welche den Aufbau der Kundenobjekte definiert. Davon existieren zwei Instanzen, welche nun konkrete Kunden-Objekte repräsentieren.

Jedes der beiden Kunden-Objekte hat eigene Daten. Eine Änderung der Daten eines Kunden hat weder Auswirkung auf die anderen Kunden-Objekte, noch auf die Klasse.

Die verwendete Darstellform der Abbildungen ist das UML Klassendiagramm, welches später, in Abschnitt UML Klassendiagramm, genauer beschrieben wird.

Klasse mit instanziierten Objekten

Bei der Vererbung handelt es sich um einen der wesentlichsten Teile der Objektorientierung. Es handelt sich dabei um die Möglichkeit einzelne Klassen, und damit ihre Objekte, zu gliedern und zu konkretisieren oder in die andre Richtung weiter zu abstrahieren. Soll beispielsweise die Klasse Kunde aus Abbildung 67 weiter konkretisiert werden um zwischen normalen Kunden und Geschäftskunden zu unterscheiden, könnte diese neue Klasse mittels Vererbung von der Klasse Kunde abgeleitet werden. Sie erbt damit alle Variablen und Methoden der Klasse Kunde und ergänzt diese um weitere, für den Zweck der neuen Klasse konkretere, Variablen. Da die Klasseneigenschaften immer von einer Klasse zur nächsten weitervererbt werden, spricht man in diesem Zusammenhang oft von einer Mutterklasse und Tochterklasse. Ein entsprechendes Beispiel findet sich in Abbildung 68. Dabei wurde die neue Klasse Geschäftskunde um eine Umsatzsteuer-Identifikationsnummer und einen Firmennamen erweitert. Sie erbt dabei alle Eigenschaften ihrer Mutterklasse und kann diese wiederum selbst verwenden.

Klasse mit Vererbung

Eine Klasse kann zusätzlich zu Variablen auch Methoden enthalten. Es handelt sich dabei um Methoden, welche innerhalb der jeweiligen Instanz der Klasse ausgeführt werden. Sie können daher auf die jeweiligen Daten der Objekte zugreifen und diese verarbeiten und verändern. Im Rahmen der objektorientierten Modellierung ist es üblich, die Variablen eines Objektes nicht direkt abzurufen und zu befüllen, sondern dies über eigene Methoden zu bewerkstelligen. Dabei handelt es sich meist im eine Get- und eine Set-Methode. Sie werden daher auch als Getter und Setter bezeichnet. Für das Beispiel in Abbildung 68 werden daher Get- und Set-Methoden für die Variablen Name, E-Mail, KundenNr für die Klasse Kunde und für UstId und Firmenname der ihrer Tochterklasse Geschäftskunde angelegt. Das neue Modell ist in Abbildung 69 ersichtlich.

Klassen mit Get- und Set-Methoden

Eine weitere Möglichkeit bei der Vererbung von Klassen und ihrer Methoden ist die Überlagerung oder Polymorphie. Dabei können bereits in der Mutterklasse definierte Methoden erneut definiert und damit überlagert werden. Dies kann erforderlich sein, wenn der Methodenzweck sich durch die abgeleitete Klasse und ihrer konkreteren Daten verändern muss, um weiterhin ein korrektes Ergebnis zu liefern. Zur Veranschaulichung dieses Prinzips wird das Kundenbeispiel um eine Methode getKundenString erweitert. Der Zweck der Methode soll die Rückgabe einer Zeichenkette sein, welche immer alle relevanten Kundendaten enthalten soll, um sie beispielsweise später in einer Liste anzudrucken. Je nachdem, ob es sich um einen Kunden oder einen Geschäftskunden handelt, sollen die Werte Name und Kundennummer, und gegebenenfalls auch der Firmenname enthalten sein. Dazu wird die neue Methode nun sowohl in der Mutterklasse Kunde, als auch in der Tochterklasse Geschäftskunde definiert und dadurch für jede Instanz der Klasse Geschäftskunde in der Mutterklasse überlagert. Die Definition der überlagerten Methode getKundenString ist in Abbildung 70 ersichtlich.

Klassen mit überlagerter Methode getKundenString()

Eine Ausnahme unter den Variablen und Methoden einer Klasse sind statische Variablen und statische Methoden. Diese sind direkt der Klasse zugeordnet und können keinen Einfluss auf Instanz-Variablen der Objektinstanzen nehmen. Statische Methoden können daher nicht nur über ein instanziiertes Objekt der Klasse, sondern auch ohne Objekt direkt über die Klasse aufgerufen werden. Diese Art der Methoden wird häufig in Klassen verwendet, von denen keine Objekte abgeleitet werden sollen, sondern die nur als Gruppierung von Methoden dienen. Ein Beispiel dafür sind mathematische Methodensammlungen. Klassen aus welchen selbst keine Objekte instanziiert werden dürfen werden selbst als statisch definiert. Statische Klassen können daher auch keine Instanz-Variablen beinhalten, sondern nur statische Variablen. Statische Variablen können sowohl durch statische, als auch durch nicht statische Methoden verändert werden. Sie werden jedoch auf der Ebene der Klasse geführt und nicht auf der der Objekte. Der Inhalt statischer Variablen gilt daher immer übergreifend für alle Objekte und wird auch nur übergreifend geändert. Es sind daher gemeinsame Variablen der Objekte der Klasse.

Kapselung

Damit die Variablen und Methoden einer Klasse nicht wahllos durch Zugriffe von außerhalb der Klasse aufgerufen und verändert werden können, gibt es die Möglichkeit, diese über die Kapselung zu schützen.

Grundsätzlich sollte der Zugriff auf die Elemente des Objektes so eingeschränkt wie möglich sein. Das bedeutet, dass die Variablen eines Objektes möglichst nur über die entsprechenden Getter und Setter Methoden ausgelesen und verändert werden sollten. Auch sollten Methoden, welche nur für objektinterne Operationen verwendet werden sollen, nicht außerhalb des Projektes aufgerufen werden können.

Um diese Kapselung sicherzustellen gibt es vier verschiedene Zugriffsmodifikatoren (Access-Modifier), mit denen der Kapselungs-Level definiert wird:

  • Public,
  • Package,
  • Protected und
  • Private.

Um eine Variable oder Methode mit einem Kapselungs-Level zu versehen wird dieser meist direkt bei ihrer Definition angegeben. In UML geschieht dies vor dem Variablen- oder Methoden-Namen (siehe 5.4).

Der offenste Level ist der Level Public. Er ermöglicht einen direkten Zugriff von außerhalb des Objektes oder der Klasse. Ein Beispiel für Methoden, welche diesem Level unterliegen sind die Getter- und Setter-Methoden.

Der Level mit der größten Einschränkung ist Private. Auf alle Methoden und Variablen, welche mit diesem Level versehen sind, dürfen nur innerhalb des eigenen Objektes zugegriffen werden. Dieser Zugriffschutz gilt auch gegenüber abgeleitete Klassen und deren Objekten. Wurde somit in einer Mutterklasse eine private Variable x definiert, können neue oder überlagerte Methoden des Tochterelements nicht direkt auf sie zugreifen. Der Zugriff ist nur über Methoden möglich, welche auch auf Ebene des Mutterobjektes definiert wurden. Ein Zugriff wäre damit nur über eine Methode der Mutterklasse möglich, die selbst nicht als private definiert wurde.

Der Level Protected ist ein Kompromiss zwischen den Level Public und Private für den Zugriff innerhalb der Vererbungshierarchie. Alle Variablen und Methoden dieses Levels sind nicht von außerhalb des Objektes oder der Klasse zugreifbar. Innerhalb der Vererbung darf jedoch voll auf sie zugegriffen werden. Somit kann eine Variable x mit dem Level protected einer Mutterklasse durch ihre Tochterklasse voll ausgelesen und beschrieben werden, nicht jedoch von außerhalb der Klassen und Objekte.

Der Level Package entspricht dem Prinzip des Levels Protected. Die Zugriffserlaubnis wird jedoch über die Vererbungshierarchie hinaus auf alle Klassen und Objekte desselben Packages ausgeweitet. Ein Zugriff von außerhalb des Packages ist hier ebenfalls nicht gestattet. Er ist meist der Standardlevel, welcher zur Anwendung kommt, wenn kein spezieller Level angegeben wurde, wobei der sich Standardwert je nach Programmiersprache auch unterscheiden kann. Bei einem Package handelt es sich um eine logische Gruppierung von Klassen.

Abstrakte Klassen

Abstrakte Klassen sind Vorlagen für die Vererbung und dienen auch als generalisierte Übergruppen ihrer Tochter-Klassen. Aus Ihnen können keine Objekte generiert werden. Wird aus einer abstrakten Mutter-Klasse eine Tochter-Klasse abgeleitet, kann diese abstrakt aber auch nicht abstrakt sein. Ist die abgeleitete Klasse nicht mehr abstrakt, können aus ihr Objekte generiert werden.

Damit eine Klasse abstrakt wird, muss sie selbst als abstrakt gekennzeichnet werden. Weiter gibt es die Möglichkeit, abstrakte Methoden zu definieren. Abstrakte Methoden sind nur eine Definition des Methodenkopfes, der aus Name und den übergebenen und zurückgelieferten Datentypen besteht. Sie müssen in den abgeleiteten Klassen überlagert und entsprechend ausprogrammiert werden. Die Tochter-Klasse ist dann solange selbst eine abstrakte Klasse, bis alle abstrakten Methoden der Mutter-Klassen überlagert und implementiert sind.

Abstrakte Klassen können jedoch auch eine Basisimplementierung bestimmter Methoden zur Verfügung stellen, welche dann von allen abgeleiteten Klassen eingesetzt werden können.

Ein Beispiel einer abstrakten Klasse wäre ein Klasse Fahrzeug mit den abstrakten Klassen-Methoden „bewegen“ und „stehen bleiben“. Objekte der Klasse Fahrzeug machen noch keinen Sinn, da noch nicht klar ist wie das jeweilige Fahrzeug die Ausführung der beiden Methoden bewerkstelligen kann. Von ihr können nun die Klassen Auto und Fahrrad abgeleitet werden, welche die beiden Methoden jeweils überlagern und entsprechend der Anforderungen an das jeweilige Fahrzeug fertig implementieren.

Prinzipien objektorientierten Designs (SOLID object-oriented design)

Im Jahr 1994 entwickelte Robert C. Martin die Prinzipien objektorientierten Designs und veröffentlichte dazu eine Vielzahl von Artikel. Eine Zusammenfassung der Prinzipien kann im Detail in (Martin, 2000) nachgelesen werden. Dabei gibt es jeweils eigene Gruppen von Prinzipien für das Klassen- und Package-Design.

Die wichtigsten fünf Prinzipien des Objektorientierten Designs sind:

  • Das Single Responsibility Prinzip:

Eine Klasse soll nur für einen Anwendungsbereich verantwortlich sein, damit spätere Änderungen nicht mehrere Anwendungsbereiche betreffen und damit zu Fehlern führen können.

  • Das Open Closed Prinzip:

Eine Klasse soll offen sein erweitert zu werden, jedoch soweit geschlossen sein, um keine Modifikationen an ihr selbst zuzulassen.

  • Das Liskov Substitution Prinzip:

Eine Instanz einer abgeleiteten Klasse muss sich so verhalten wie eine Instanz der Mutterklasse. Ihre Funktionen dürfen nicht grundlegend anders sein.

  • Das Interface Segregation Prinzip:

Die Funktionalitäten müssen soweit entkoppelt sein, dass eine Verwendung von Klassen möglich ist, die nur den benötigten Zweck erfüllen. Der Client darf nicht gezwungen werden, Klassen einzusetzen von denen er nur einen Teil wirklich benötigt. Dadurch werden Ressourcen gespart und der Aufwand von späteren Softwareanpassungen wird geringer.

  • Das Dependency Inversion Prinzip

Abstraktionen dürfen nur in eine Richtung erfolgen. Eine Abstraktion auf einer höheren Ebene darf nicht von Attributen einer niedrigeren Ebene abhängen. Das bedeutet, dass eine Mutterklasse keine Elemente von Tochterklassen benötigen darf, eine Tochterklasse hingegen jedoch Teile der Mutterklasse.

Da aus den Anfangsbuchstaben der Prinzipien das Akronym SOLID gebildet werden kann, wird ein an ihnen orientiertes Objekt-Design oft als SOLID object-oriented design bezeichnet.

Die Unified Modeling Language (UML)

Durch die Verbreitung der objektorientierten Konzepte bei der Analyse und dem Design von Informationssystemen und auch durch die Notwendigkeit dynamische Aspekte formalisiert in einem Gesamtmodell zu beschreiben, wurden die Bemühungen intensiviert, eine möglichst umfassende und konsistente Modellierungssprache zu entwickeln. Dies führte schließlich nach einem heftigen „Methodenkrieg“ zur Definition der objektorientierten Modellierungssprache UML, der Unified Modeling Language, die auch als Standard (Object Management Group (OMG), 2011) von der OMG akzeptiert wurde.

Ziel war es, eine Sprache zu entwickeln, die komplexe Systeme in ihrer Gesamtheit erfassen kann. Da hierzu ein einziges Modell nicht ausreicht, erschien es notwendig, verschiedene Sichten auf die zu modellierende Realität zu definieren, die durch unterschiedliche, relativ unabhängige Modellen innerhalb eines konsistenten Gesamtkonzepts dargestellt werden. Dieser Ansatz führte zur Entwicklung von UML, einer graphischen Sprache für die objektorientierte Modellierung von industriellen Softwaresystemen und anderer komplexer Systeme. Sie erlaubt hierbei die Visualisierung, Spezifikation, Konstruktion und Dokumentation der verschiedenen Elemente der zu modellierenden Systeme. UML vereinigt dabei die Notationen von Booch, Rumbaugh und Jacobson, indem sie fast alle Modelle der drei Methoden enthält und weitere Notationsformen hinzufügt.

Ziele von UML:

  • Sie stellt dem Benutzer eine verwendbare, ausdrucksstarke visuelle Modellierungssprache zur Entwicklung und dem Austausch inhaltsvoller Modelle zur Verfügung.
  • Sie erlaubt Erweiterungs- und Spezialisierungsmechanismen zur Erweiterung der Kernkonzepte.
  • Sie ist unabhängig von spezifischen Programmiersprachen und Entwicklungsprozessen.
  • Sie ist durch eine rigorose (semi-formale) Modellierungssprache (UML-Meta-Modell) definiert.
  • Sie ermutigt die Entwicklung des OO Tool Markts.
  • Sie unterstützt abstrahierte Entwicklungskonzepte, wie Kollaboration, Frameworks, Patterns und Komponenten.

Beschränkungen von UML:

  • Sie ist keine visuelle Programmiersprache, d.h. sie bietet keine Unterstützung für eine volle Programmiersprache, wie zum Beispiel Ausdrücke, Kontrollkonstrukte, …
  • UML definiert keine Schnittstelle zu spezifischen Softwarewerkzeugen.
  • UML definiert keinen Entwicklungsprozess, d.h.

Sie schreibt keinen Ansatz vor, wie man Klassen, oder Verhalten findet, sie enthält keine Design Richtlinien oder Empfehlungen. UML unterstützt jedoch Prozesse, die folgende Eigenschaften aufweisen:

  • Use-Case-gesteuert,
  • Iterativ,
  • Architekturzentriert und
  • Inkrementell.

UML Diagrammtypen

Die zentrale Eigenschaft der Notation ist die Unterstützung von verschiedenen Sichten auf das zu modellierende System. Hierzu stellt UML eine Reihe von unterschiedlichen Diagrammtypen, sogenannten Spracheinheiten (language units), zur Verfügung. Diese Diagrammtypen erlauben es dem Benutzer einen ausgewählten Aspekt eines Systems mit einem bestimmten Formalismus zu modellieren.

UML 2.0 stellt hierzu insgesamt 13 Diagrammtypen zur Verfügung, die grundsätzlich in zwei Gruppen eingeteilt werden können, in sechs Strukturdiagramme, die die statischen Aspekte darstellen, und sieben Verhaltensdiagramme für die dynamischen Aspekte, wobei drei allgemeines Verhalten und vier Interaktionen beschreiben. Im Folgenden werden diese 13 Diagramme kurz erläutert [1] . In den nachfolgenden Abschnitten 5.4 und 5.5 werden das Objektdiagramm und das Anwendungsfalldiagramm genauer behandelt.

Strukturdiagramme

Klassendiagramm

Stellt den „strukturellen“ Kern von UML dar, fasst gleichartige Objekte zusammen und definiert die Beziehungen untereinander

Wiba mt233 201607 a.076.png

Objektdiagramm

Stellt einen prototypischen Ausschnitt aus dem System dar, besteht nur aus Objekten

Wiba mt233 201607 a.077.png

Paketdiagramm

Erlaubt die Gruppierung von Systembestandteilen und verschiedenen Ebenen und dient zur Reduzierung der Komplexität in der Darstellung

Wiba mt233 201607 a.078.png

Komponentendiagramm

Definiert Komponenten (modulare Systemteile) und deren Abhängigkeiten unter einem softwareorganisatorischen Aspekt

Wiba mt233 201607 a.079.png

Kompositionsstrukturdiagramm

Erlaubt die (kontextabhängige) hierarchische Strukturierung von Systemteilen

Wiba mt233 201607 a.080.png

Verteilungsdiagramm

Beschreibt die eingesetzte Hardwareinfrastruktur und deren Aufbau und das Laufzeitsystem

Wiba mt233 201607 a.081.png

Verhaltensdiagramme

Anwendungsfalldiagramm

Spezifiziert die Funktionalität des zu entwickelnden Systems aus der Benutzersicht auf der Basis von Szenarien

Wiba mt233 201607 a.082.png

Aktivitätsdiagramm

Stellt den Kontroll- und Datenfluss von Abläufen im System dar (Prozessmodellierung)

Wiba mt233 201607 a.083.png

Zustandsdiagramm

Definiert das Verhalten eines Objekts über seine erlaubten Zustände und Zustandsübergänge (Lebenszyklus eines Objekts)

Wiba mt233 201607 a.084.png

Sequenzdiagramm

Definiert die Interaktionen von Objekten bei einer spezifischen Aufgabe, der Fokus liegt hier bei der Beschreibung der zeitlichen Reihenfolge

Wiba mt233 201607 a.085.png

Kommunikationsdiagramm

Eigentlich analog zum Sequenzdiagramm werden die Interaktionen zwischen Objekten beschrieben, der Schwerpunkt liegt hier aber auf den strukturellen Beziehungen

Wiba mt233 201607 a.086.png

Zeitdiagramm

Spezielle Form des Interaktionsdiagramms für präzise zeitliche Spezifikationen, eignet sich für die Beschreibung von Echtzeitsystemen

Wiba mt233 201607 a.087.png

Interaktionsübersichtsdiagramm

Beschreibt abstrakt den Kontrollfluss zwischen verschiedenen Interaktions­abläufen, erlaubt die Beschreibung der logischen Reihenfolge von Interaktionsdiagrammen

Wiba mt233 201607 a.088.png

UML Klassendiagramm

Ein Klassendiagramm beschreibt den strukturellen Aspekt des zu modellierenden Systems. Es unterstützt die objektorientierte Betrachtungsweise indem es Modellierungselemente für Klassen, ihre Eigenschaften (Attribute), ihr Verhalten (Operationen, Methoden) und ihre Beziehungen zur Verfügung stellt. Neben reinen Assoziationen wird auch die Beschreibung von Generalisations- und Aggregationsbeziehungen unterstützt.

Eine Klasse wird in UML durch ein Rechteck dargestellt, das in horizontale Abschnitte gegliedert wird, die den Namen der Klasse, die Attribute, Operationen und optionalen weiteren, nicht normierte, „Compartments“ für textuelle Beschreibungen, wie Verantwortlichkeiten, Ausnahmen, etc. enthalten (siehe Abbildung 71). Mit Ausnahme des Namens der Klasse können alle weiteren Beschreibungselemente fehlen.

Klassendiagramm

Bei der Definition von Klassen sind eine Reihe weiterer Angaben möglich. Beim Klassennamen können auch noch ein Stereotyp, in doppelten spitzen Klammern << … >>, und Eigenschaften, in geschwungenen Klammern, { … } angegeben werden.

Stereotype sind ein Mechanismus, Sprachkonzepte von UML zu erweitern, wobei UML einige standardisierte Stereotype zur Verfügung stellt, wie zum Beispiel << entity >>, das die Klasse als persistente Problembereichsklasse identifiziert.

Über Eigenschaften können Klassen gekennzeichnet werden. Eine häufig benutzte Eigenschaft ist die Verwendung der Eigenschaft { abstract } zur Kennzeichnung einer abstrakten Klasse. Es kann auch zum Beispiel das Speicherverhalten einer Klasse mit { persistence = persistent } definiert werden, das angibt, dass Objekte dieser Klasse dauerhaft (z. B. in einer Datenbank) abgelegt werden.

Es kann auch eine Multiplizität für Klassen rechts oben beim Namen angegeben werden. Diese besagt, wie viele Objekte dieser Klasse existieren dürfen. Falls nichts angegeben ist, ist die Zahl unbegrenzt.

Bei den Attributen können Anfangswerte (z. B. Bonität: Integer = 0) und Sichtbarkeiten bzw. Zugriffsberechtigungen angegeben werden:

  • - für private,
  • + für public,
  • # für protected und
  • ~ für package.

Für die Operationen müssen Parameterlisten angegeben werden. Es reicht die Angabe eines Namens, weitere Spezifikationen, wie Typ, Angabe, Eingabe-/Ausgabeparameter und Standardwert sind optional. Funktionen werden durch die Angabe eines Ergebnistyps vereinbart; bei Prozeduren fehlt dieser. Die Sichtbarkeiten können bei Operationen analog zu den Attributen definiert werden.

Attribute und Operatoren können ebenfalls mit Eigenschaften versehen werden, wie beispielsweise { static } zur Kennzeichnung als statisches Element auf Klassenebene.

Es können weiter auch bei den Operationen Stereotype angegeben werden, die helfen, die Operationen zu gruppieren. Ein entsprechend erweitertes Beispiel ist in Abbildung 72 abgebildet.

Erweitertes Klassendiagramm

Klassen erlauben auch abgeleitete Attribute zu spezifizieren. Das bedeutet, dass solche Attribute aus anderen Informationen berechnet werden. Diese Attribute werden durch einen vor den Namen gestellten Schrägstrich gekennzeichnet. Es kann auch die Berechnungsvorschrift in geschwungenen Klammern angegeben werden. Feldartige Attribute werden über eine Intervallschreibweise vereinbart.

Ein Beispiel, das diese Möglichkeiten veranschaulicht, ist in der Abbildung 73 angegeben.

UML Klasse Angestellter

Assoziationen

Eine Assoziation zeigt eine Beziehung zwischen zwei Klassen an und kann einen Namen haben. Mit anderen Worten ausgedrückt zeigt eine Assoziation an, dass eine Klasse von der Existenz einer anderen Klasse „wissen“ muss. Zum Beispiel kann ein Objekt einer Klasse durch Änderungen von Objekten einer anderen Klasse beeinflusst werden. Praktische Gründe für Assoziationen können sein:

  • schickt Message an ein Objekt der Klasse
  • erzeugt ein Objekt der Klasse
  • verwendet die andere Klasse als Typ für ein Methodenargument
  • verwendet die andere Klasse als Typ eines Attributes
  • ...

Betrachten wir hierzu folgendes Beispiel (Abbildung 74):

Assoziation

Das (optionale) gefüllte Dreieck () gibt die Leserichtung der Assoziation an und hilft die Beziehung einfacher zu interpretieren. Auch hier können, wie bei der ER-Notation, Multiplizität (multiplicity) angegeben werden, die spezifizieren, wie viele Objekte an der Beziehung teilnehmen. Die Multiplizität liefert die Anzahl von Objekten einer Klasse in Bezug auf ein Objekt der anderen Klasse. In unserem obigen Beispiel bedeutet dies, dass jede Bestellung genau einen Kunden hat, jeder Kunde aber 0 bis beliebig viele (0..*) Bestellungen durchführen kann.

UML unterstützt auch weitere Formen der Assoziationen, wie

* Reflexive Assoziation

Diese Assoziationsform besteht zwischen Objekten derselben Klasse. Es müssen aber Rollennamen angegeben werden (Abbildung 75).

Reflexive Assoziation

  • Assoziationsklassen

Eine Assoziationsklasse erlaubt die detaillierte Beschreibung von Assoziationseigenschaften (Abbildung 76). Die Darstellung verwendet das Klassensymbol, das durch eine gestrichelte Linie mit der Assoziationskante verbunden ist.

Assoziationsklasse
  • N-äre Assoziation

Dies ist eine Assoziation zwischen 3 oder mehr Klassen (Abbildung 77). Jede Instanz einer n-ären Assoziation ist ein n-Tupel von Instanzen der beteiligten Assoziationen (können auch Assoziations­klassen sein).

N-äre Assoziation
  • XOR-Assoziation

Eine Klasse kann potentiell Assoziationen zu mehreren anderen Klassen aufweisen, auf Instanzebene tritt aber immer nur eine dieser Assoziationen auf. Im Diagramm werden die betroffenen Assoziationskanten mit einer gestrichelten Linie verbunden (Abbildung 78).

XOR-Assoziation

Objektdiagramm

Ein Objektdiagramm zeigt eine mögliche Systemkonfiguration durch ein Menge von Objekten und ihre Verbindungen. Es stellt quasi einen Snapshot einer prototypischen Systemsituation dar. Ein Objektdiagramm muss dem Klassendiagramm entsprechen und zeigt eine mögliche Interpretation (von vielen). UML verwendet eine einheitliche Darstellung, um Instanzen von dem dazugehörigen Typ zu unterscheiden, indem die Instanz dasselbe graphische Symbol wie der Typ verwendet, jedoch der Name unterstrichen wird. Siehe hierzu Abbildung 79, die die Klasse und das entsprechende Objekt darstellt.

Objektdiagramm

Gerichtete Pfeile zeigen die Richtung der Implementierung an, die andere Richtung geht nicht. Man kann den Attributen von Objekten Werte zuweisen. Grundsätzlich sollten Objekte Instanzen existierender Klassen (durch „:“ gekennzeichnet) und Verbindungen Instanzen existierender Assoziationen sein, wobei etwaige Randbedingungen eingehalten werden.

Generalisierung und Spezialisierung

Die Generalisierung stellt eine hierarchische Beziehung zwischen einer allgemeineren Klasse (Oberklasse) und einer spezialisierten Klasse (Unterklasse) dar. Wir bezeichnen diese Generalisierung als eine IS-A Beziehung. Die Unterklasse erbt die Eigenschaften der Oberklasse, kann aber weitere spezifische Eigenschaften hinzufügen. In UML kennzeichnet man diese Generalisierungshierarchie durch einen nicht ausgefüllten Pfeil. Siehe hierzu folgendes Beispiel (Abbildung 80):

UML Generalisierung

Analog zu den ER-Diagrammen lassen sich auch hier die Überdeckungen spezifizieren. Man kann im Diagramm neben dem Generalisierungsdreieck die Überdeckung in geschwungenen Klammern entsprechend angeben:

  • überlappend / exklusiv entspricht overlapping / disjoint (UML) und
  • Total / Partiell entspricht complete / incomplete (UML).

Siehe hierzu das erläuternde Beispiel in Abbildung 81:

UML Überdeckung

Mehrfachvererbungen

UML unterstützt auch die Notation von Mehrfachvererbungen. Siehe hierzu das folgende Beispiel in Abbildung 82:

UML Mehrfachvererbung

Aggregation

Die Aggregation ist eine spezielle Form der Assoziation, die anzeigt, dass ein Objekt einer Klasse Teil eines Objektes einer anderen Klasse ist. Wir bezeichnen dieses Beziehung daher als „part-of“ / “has-a“ Beziehung („teil-von“ / „hat-ein“). Auch Aggregationen können (und sollten) einen Namen haben. Es kann auch hier die Multiplizität angegeben werden. Wir verwenden hierzu in UML die nicht ausgefüllte Raute. Siehe hierzu das folgende Beispiel (Abbildung 83):

UML Aggregation

Komposition

Eine strengere Form der Aggregation ist die Komposition, bei der der Teil nur Kompositionsteil eines Ganzen sein darf. Das Kompositum ist auch für das Erzeugen und Zerstören des Teils verantwortlich. In UML wird dazu die ausgefüllte Raute verwendet. Siehe das folgende Beispiel (Abbildung 84):

UML Komposition

Das Kompositum („Ganze“) darf in der Kompositionsassoziation nur einmal oder keinmal auftreten, daher darf die Multiplizität auf Seiten des Kompositums nur 1 oder 0..1 sein.

In den nachfolgenden, etwas umfangreicheren, Beispielen (Abbildung 85 und Abbildung 86) sind die Ausschnitte zweier Realitäten modelliert, eine Fachhochschule und eine Bank. Sie erkennen hier den Einsatz von Generalisation und Aggregation.

UML Beispiel Fachhochschule
UML Beispiel Bank

UML Anwendungsfalldiagramm (Use Case Diagramm)

Anwendungsfalldiagramme oder auch Use Case Diagramme dokumentieren das Verhalten des Systems vom Blickpunkt des Benutzers aus. Sie helfen bei drei wichtigen Aspekten der Entwicklung:

  • Finden der Anforderungen an das System (Systemspezifikation)
  • Planung der Zyklen der Entwicklung (bezogen auf den Benutzer)
  • Erstellen sinnvoller und aussagestarker Systemtests

Use Case Diagramme wurden ursprünglich von Jacobson (in den frühen 90er) in seinem OOSE Modell eingeführt und haben sich aus den „Scenarios“ entwickelt. Use-Cases sind unabhängig von einer objektorientierten Betrachtungsweise. Dies kann eine Stärke, aber auch eine Schwäche sein.

Darstellung

Beginnen wir mit einem einfachen Beispiel für ein Anwendungsfalldiagramm, das die wichtigsten Elemente dieser Notationsform enthält (siehe Abbildung 87):

Anwendungsfalldiagramm Beispiel (nach Jacobson)

Ein Use Case repräsentiert eine mögliche Interaktion mit dem System. Ein System wird durch ein Rechteck dargestellt, das die Anwendungsfälle enthält. Ein spezifischer Anwendungsfall wird durch eine Ellipse dargestellt, bei der der Name des Falls in oder unter der Ellipse angegeben wird. Das zweite wichtige Element ist der sogenannte Aktor, der als Strichfigur dargestellt und benannt wird. Ein Aktor kann ein menschlicher Benutzer oder eine Benutzergruppe des Systems in einer spezifischen Rolle, aber auch ein Programm oder ein externes System sein, das in einer spezifischen Rolle mit dem System interagiert. Die Verbindung zwischen Anwendungsfall und Aktor ist durch eine einfache Linie dargestellt. Derselbe menschliche Benutzer oder dasselbe externe System kann mit dem System in mehr als einer Rolle interagieren. Sie werden dann durch mehrere Aktoren realisiert.

Use-Cases enthalten (normalerweise) eine textuelle Beschreibung über die Folge der zwischen dem Aktor und dem System ausgetauschten Botschaften (Messages) und die Aktionen des Systems, um die Funktionalität zu realisieren. Diese Beschreibung kann auch logische Fallunterscheidungen für Ausnahmefälle enthalten, wie zum Beispiel: „falls Kontostand zu niedrig, stop und Fehlermeldung“. Ein Use-Case kann auch mit anderen UML Diagrammen verbunden werden, um seine Realisierung zu zeigen.

Wir wollen das Anwendungsfalldiagramm anhand eines weiteren Beispiels erläutern. Es soll ein Softwaresystem zur Unterstützung der Buchungen in einem Reisebüro entwickelt werden. Wir betrachten hierzu einen speziellen Aktor, nämlich den Reisebüroagenten. Die Funktionen dieses Aktors (Reisebüroagenten) sind die folgenden:

* Eine Reise für eine Gruppe buchen:

Der Reisebüroagent bucht eine Gruppenreise, die aus mehreren Einzelreisen besteht. Die Bezahlung erfolgt erst nach der Buchung (z. B. über Kreditkarte). Jede gebuchte Einzelreise wird vom vorhandenen Reisekontingent des Reisebüros abgezogen.

Wiba mt233 201607 a.106.png
  • Die Reise für die gesamte Gruppe stornieren:

Der Agent storniert die gesamte Gruppenreise. Jede einzelne Einzelreise muss storniert werden und auf das Kontingent des Reisebüros zurückgebucht werden.

Wiba mt233 201607 a.107.png
  • Die Reise eines einzelnen Reisenden (Einzelreise) in der Gruppe stornieren:

Der Agent storniert eine Einzelreise aus der Gruppenreise, die auf das Kontingent des Reisebüros zurückgebucht wird.

Wiba mt233 201607 a.108.png
  • Ein Luxus-Gruppenreise buchen:

Eine Gruppenreise kann durch einen Upgrade zu einer Luxus-Gruppenreise erweitert werden (5-Stern Hotel, All-Inklusiv).

Wiba mt233 201607 a.109.png

Wir können daher diesen Use cases in das folgende Anwendungsfalldiagramm eintragen (Abbildung 88):

Use Case Reisebüro Buchungssystem

Beziehungen zwischen Use Cases

Use Cases können nicht nur Beziehungen zu Aktoren, sondern auch untereinander haben. Es werden drei unterschiedliche Beziehungsarten unterschieden: die include-, die extend- und die Generalisierungsbeziehung.

Die include-Beziehung besteht zwischen Use-Cases, die ein ähnliches Verhalten zeigen. Sie wird verwendet, um Aktionsfolgen nur einmal zu beschreiben, die aber in mehreren Use-Cases vorkommen.

In unserem Reisebüro Beispiel liegt eine include-Beziehung zwischen dem Use Case „Storniere Gruppenreise“ und „Storniere Einzelreise“ vor, da im Fall der Stornierung einer gesamten Gruppenreise alle in ihr enthaltenen Einzelreisen storniert werden müssen. Das Gruppenreisestornieren verwendet („include“) das Verhalten des Einzelreisestornieren. Graphisch lässt sich das folgendermaßen darstellen (Abbildung 89):

Include Beziehung

Die include-Beziehung wird durch einen gestrichelten Pfeil dargestellt, der mit dem Schlüsselwort <<include>> beschriftet ist.

Die extend-Beziehung wird verwendet, um Spezialfälle zu beschreiben, d.h. Aktionsfolgen in einem durch eine extend-Beziehung verknüpften Use-Case sind optional. Man spricht auch davon, dass der Use-Case A ein zusätzliches Verhalten zum Use Case B zeigt (Hauptfall B - Nebenfall A).

In unserem Beispiel des Reisebüros könnte zum Beispiel bei der Buchung einer Gruppenreise eine Erweiterung zu einer Luxus-Gruppenreise durchgeführt werden. Das bedeutet, dass der Use Case der normalen Gruppenbuchung durch den Luxus-Upgrade erweitert (extend) wird. Dies lässt sich graphisch durch die <<extend>>-Beziehung darstellen (Abbildung 90):

Extend Beziehung

Die extend-Beziehung wird durch einen gestrichelten Pfeil dargestellt, der mit dem Schlüsselwort <<extend>> beschriftet ist.

Die Generalisierungsbeziehung ist ähnlich der Vererbung im objektorientierten Ansatz und kann auf Aktivitäten (Funktionen) und Teilnehmer (Aktors) angewendet werden. Sie sollte vor allem eingesetzt werden, um Beziehungen zwischen abstrakten und konkreten Use Cases darzustellen.

In unserem Beispiel könnten wir daher unsere Gruppenstornierung und Einzelstornierung als Spezialisierung eines abstrakten Stornierungsfalls sehen (Abbildung 91):

Use Case Generalisierung

Wir können jetzt diese Beziehungen in unser ursprüngliches Anwendungsfalldiagramm eintragen und dadurch die Beschreibung erweitern (Abbildung 92):

Erweiterter Use Case Reisebüro Buchungssystem

Im Folgenden wollen wir noch einige Faustregeln aufstellen, wann welcher Beziehungstyp eingesetzt werden soll:

  • Die include-Beziehung verwendet man dann, wenn der benutzte Use Case unbedingt notwendig ist, die Funktionalität des benutzenden Use Case sicherzustellen.
  • Die extend-Beziehung erläutert, dass der zu erweiternde Use Case vom erweiterten Use Case übernommen werden kann, aber nicht muss.
  • Die Generalisierungsbeziehung sollte man zwischen konkreten und abstrakten Use Case einsetzen.

Einsatz von Use Cases

Use Cases sind sehr gut dazu geeignet oder können zumindest helfen, die Anforderungen (Spezifikationen) an das System zu identifizieren. Die Vorgangsweise ist hierbei relativ simpel:

  1. Finde die Aktoren des Systems

  2. Finde für jeden Aktor heraus:

Was benötigt der Aktor vom System.

Welche sonstige Interaktion hat der Aktor mit dem System.

Welche Use-Cases besitzen welche Priorität für den Aktor.

Es ist dabei aber zu beachten, dass es ein Systemverhalten geben kann, das nicht direkt aus einem Use-Case für einen Aktor erkannt (abgeleitet) werden kann.

Die Kritik an der Verwendung von Use Cases sieht folgende Gefahren. Use-Cases können zu einer funktionalen Betrachtungsweise führen und man vernachlässigt den objektorientierten Ansatz. Der Entwickler kann weiter den Blick auf die System- und Objektarchitektur verlieren und er könnte daher Design mit Anforderungen verwechseln. Die letzte Gefahr liegt darin, dass Anforderungen übersehen werden, die mit keinem offensichtlichen Aktor verbunden sind. Man sollte daher immer beachten, dass Use Cases zu einer disziplinierten objektorientierten Modellierung führen können, sie aber NICHT die Modellierung selbst sind.

Use Cases besitzen aber auch eine „politische“ Komponente während eines Projektablaufs. Sie können helfen, Motivation, Verständnis für das Projekt zu erzeugen und die Bedeutung des Projekts zu verdeutlichen. Die Anforderungen, die sich aus Use-Cases ableiten lassen, zeigen nämlich WAS für WEN WICHTIG ist! Diese Information muss schnell, an alle Personen, die davon betroffen sind, und in jedem Zyklus des Entwicklungsprozesses geliefert werden. Das Ergebnis ist dann (hoffentlich), dass man Unterstützung für ein Projekt erhält und vielleicht auch dass ein Projekt nicht abgebrochen wird.

  1. Die graphischen Darstellungen sind aus Wikipedia, http://de.wikipedia.org/