Übersicht Inhaltsverzeichnis Vorwort 1 Einführung 2 Klassendiagramme 3 Object Constraint Language 3.1 Übersicht über OCL/P 3.2 Die OCL-Logik 3.3 Container-Datenstrukturen 3.4 Funktionen in OCL 3.5 Ausdrucksmächtigkeit der OCL 3.6 Zusammenfassung 4 Objektdiagramme 5 Statecharts 6 Sequenzdiagramme A Sprachdarstellung durch Syntaxklassendiagramme B Java C Die Syntax der UML/P D Anwendungsbeispiel: Internet-basiertes Auktionssystem Literatur |
3.1 Übersicht über OCL/PAbbildung 3.1 erläutert die wichtigsten Begriffe der OCL.
Die Möglichkeiten der OCL zur Beschreibung von Bedingungen werden in diesem Abschnitt anhand von Beispielen aus dem Auktionssystem demonstriert. In den nachfolgenden Abschnitten werden diese und weitere OCL-Konstrukte vertieft. Eine vollständige Grammatik der OCL findet sich in Anhang C.3. 3.1.1 Der Kontext einer BedingungEines der herausragenden Merkmale von OCL-Bedingungen ist ihre grundsätzliche Einbettung in einen Kontext, bestehend aus UML-Modellen. Meist ist dieser Kontext durch ein Klassendiagramm gegeben. Das Klassendiagramm in Abbildung 3.2 stellt einen solchen Kontext in Form zweier Klassen und einer Reihe teilweise voneinander abhängiger Attribute bereit, die einen Ausschnitt des Auktionssystems modellieren. Die Attributabhängigkeiten können durch OCL/P-Bedingungen dargestellt werden. Eine einfache Bedingung ist zum Beispiel, dass eine Auktion immer startet bevor sie beendet wird. Diese Bedingung wird durch explizite Erwähnung eines Auktionsobjekts im Kontext beschrieben. Der explizit angegebene Kontext einer OCL-Bedingung besteht aus einem oder mehreren Objekten, deren Name durch die Erwähnung im Kontext in der Bedingung bekannt gemacht wird. Die Bedingung nutzt eine Methode der Klasse Time zum Vergleich:
context Auction a inv:
Diese Bedingung benötigt aus ihrem Kontext die Signatur der Klasse Auction. Der Variablenname a wird im Sinne einer Variablenvereinbarung lokal durch die context-Angabe eingeführt. Stattdessen können Variablen auch explizit importiert werden, wenn sie zum Beispiel in einer anderen Bedingung oder einem anderen Diagramm bereits definiert wurden. Mit dieser importierenden Form des Kontexts werden in Kapitel 4 OCL-Bedingungen kombiniert und mit Objektdiagrammen verbunden, denn die in den Objektdiagrammen benannten Objekte können so explizit in den OCL-Bedingungen verwendet werden. Die durch import definierten Kontexte werden deshalb in Kapitel 4 genauer diskutiert. Folgender Kontext charakterisiert zum Beispiel eine Eigenschaft eines Auktionsobjekts a, das aus einem Objektdiagramm stammen kann:
import Auction a inv:
Durch Navigationsausdrücke können die in Assoziationen verbundenen Objekte einbezogen werden. Der Ausdruck a.bidder liefert als Ergebnis eine Menge von Personen, das heißt einen Wert vom Typ Set<Person>, von der mit dem Attribut size die Größe bestimmt werden kann. Um sicherzustellen, dass die Anzahl der aktiven Teilnehmer nicht größer als die Anzahl der tatsächlich an einer Auktion teilnehmenden Personen ist, wird folgende Bedingung formuliert:
context Auction a inv Bidders1:
Einer Bedingung kann wie hier ein eigener Name (Bidders1) gegeben werden, damit darauf an anderen Stellen Bezug genommen werden kann. Navigationsausdrücke können aneinander gereiht werden. Zur Navigation werden jeweils die dem Ausgangsobjekt gegenüberliegenden Rollennamen einer Assoziation verwendet. Ist die Assoziation participants korrekt implementiert, so ist die folgende Bedingung richtig:
context Auction a inv:
In Verschärfung der vorletzten Bedingung Bidders1 wird nun gefordert, dass die Anzahl der aktiven Teilnehmer einer Auktion genauso groß ist, wie die Anzahl der ihr zugeordneten Personen, deren Attribut isActive gesetzt ist:
context Auction a inv Bidders2:
Die dabei verwendete Mengenkomprehension ist eine komfortable Erweiterung gegenüber dem OCL-Standard. Sie wird später in mehreren Formen ausführlicher besprochen. Wird in einem Kontext statt einem expliziten Namen nur die Klasse festgelegt, so wird implizit der Name this als vereinbart angenommen. In diesem Fall kann auf Attribute auch direkt zugegriffen werden. Dies zeigt die folgende Bedingung, in der auch logische Verknüpfungen verwendet werden:1
context Auction inv
Diese Bedingung ist äquivalent zu der Fassung mit expliziter Verwendung des Namens this:
context Auction inv
Geschlossene Bedingungen, wie die Nachfolgende, besitzen einen leeren Kontext. Grundsätzlich kann ein Kontext durch Quantoren ersetzt werden, die über alle existenten Objekte der Klassen aus dem Kontext definiert werden. Die nachfolgende Bedingung mit leerem Kontext ist deshalb äquivalent zur vorhergehenden:
inv:
3.1.2 Das let-KonstruktMithilfe des let-Konstrukts können Zwischenergebnisse einer Hilfsvariablen zugewiesen werden, um diese im Rumpf des Konstrukts gegebenenfalls mehrfach zu nutzen. Nachfolgende Bedingung fordert, dass Start- und Endezeit jeder Auktion in der richtigen Relation stehen, wobei auch das aus Java bekannte if-then-else in der Kompaktform .?.:. zum Einsatz kommt:
context Auction a inv Time1:
Das let-Konstrukt vereinbart lokal benutzbare Variablen und Operationen, die nur innerhalb des Ausdrucks sichtbar sind. Der Typ einer solchen Variable wird durch den rechts gegebenen Ausdruck inferiert, kann aber auch explizit angegeben werden. In einer let-Klausel können mehrere lokale Variablen und Operationen definiert werden, von denen die nachfolgenden bereits auf die jeweils vorhergehenden zugreifen dürfen.2
context Auction a inv Time2:
Hier werden zwei strukturell gleiche Zwischenergebnisse mit unterschiedlichen Parametern definiert. Um dies zu vereinfachen, kann das let-Konstrukt auch dazu genutzt werden, Hilfsfunktionen zu vereinbaren. Folgendes Beispiel zeigt die Verwendung einer Hilfsfunktion zur Berechnung des Minimums der Zeiten und ist damit äquivalent zur Bedingung Time2:
context Auction a inv Time3:
Bei der Definition einer Hilfsfunktion sind wie in normalen Java-Methoden die Argumente gemeinsam mit ihren Typen anzugeben. Die Operationen sind im funktionalen Stil angegeben, der gleichzeitig dem in Java üblichen objektorientierten Stil für Methoden desselben Objekts entspricht. Sollte eine Hilfsfunktion öfter benötigt werden, so ist es sinnvoll, diese in einer Klasse des zugrunde liegenden Modells oder in eine eigens dafür bereitgestellte Bibliothek abzulegen. In Abschnitt 3.4.4 wird eine solche Bibliothek diskutiert. Zwischenvariablen und Hilfsfunktionen können auch als Attribute beziehungsweise als Methoden einer anonymen Klasse verstanden werden, die bei einer let-Konstruktion implizit in den Kontext aufgenommen wird. Dies wird in Abschnitt 3.4.3 nach Einführung der Methodenspezifikation noch an einem Beispiel erläutert. Ein Sonderfall, der im nächsten Abschnitt noch diskutiert wird, besteht jedoch in der Behandlung von undefinierten Ergebnissen. Das let-Konstrukt erlaubt undefinierte Zwischenergebnisse und kann doch in definierter Weise ein Gesamtergebnis erbringen, wenn die Zwischenergebnisse dort nicht auftreten.3 3.1.3 FallunterscheidungenEine Spezifikationssprache besitzt im Gegensatz zu einer imperativen Programmiersprache keine Kontrollstrukturen zur Steuerung des Kontrollflusses. Jedoch werden einige Operationen, die an imperative Konstrukte angelehnt sind, angeboten. Dazu gehört die Fallunterscheidung if-then-else oder die bereits in Bedingung Time1 verwendete äquivalente Form .?.:.. Auf Basis des ersten Arguments wird festgelegt, welches der beiden anderen Argumente evaluiert und als Ergebnis der Fallunterscheidung angenommen wird. Im Gegensatz zur imperativen Fallunterscheidung sind immer der then- und der else-Zweig anzugeben. Beide Zweige beinhalten Ausdrücke mit dem gleichen Datentyp. Die Fallunterscheidung hat dann den gleichen Datentyp wie der erste der beiden Ausdrücke. Das bedeutet, der zweite Ausdruck muss einem Subtyp des ersten Ausdrucks angehören. Eine spezielle Form der Fallunterscheidung erlaubt die Behandlung von Typkonversionen, wie sie bei Subtyphierarchien gelegentlich auftreten. OCL/P bietet dafür eine typsichere Konstruktion an, die eine Kombination einer Typkonversion und einer Abfrage nach dessen Konvertierbarkeit darstellt. Gemäß Abbildung 2.6 lässt sich aus Geboten der Bieter extrahieren:
context Message m inv:
Äquivalent dazu kann die kompaktere Form der Fallunterscheidung gewählt werden:
context Message m inv:
Zusätzlich zu einer normalen Fallunterscheidung wird bei beiden Formen im then-Zweig der Fallunterscheidung der Typ der Variable m auf BidMessage gesetzt. Die Variable m nimmt diesen Typ dort temporär an und ermöglicht dadurch die Selektion m.bidder. Im Gegensatz zur in Java üblichen Typkonversion mit (BidMessage) ist mit dieser Konstruktion die Typsicherheit gegeben. Das heißt, ein Konversionsfehler, der in Java zu einer Exception und in OCL zu einem undefinierten Wert führen würde, kann nicht auftreten. 3.1.4 GrunddatentypenAls Grunddatentypen stehen die aus Java bekannten Sorten boolean, char, int, long, float, byte, short und double zur Verfügung. Auch die aus Java bekannten Operatoren wie + oder - werden in OCL/P eingesetzt. Tabelle 3.3 enthält eine Liste der in OCL/P verfügbaren Infix- und Präfixoperatoren inklusive ihrer Prioritäten.4
Der Datentyp String wird wie in Java nicht als Grunddatentyp, sondern als standardmäßig zur Verfügung stehende Klasse verstanden. Aus den Java-Klassenbibliotheken und den Packages java.util und java.lang stehen eine Reihe solcher Klassen zur Verfügung. Eine Sonderrolle unter den Grunddatentypen nimmt der Typ der Wahrheitswerte boolean ein, weil er auch dazu genutzt wird, OCL-Bedingungen zu interpretieren. Da in der (klassischen) Logik nur zwei Wahrheitswerte verwendet werden und die Behandlung nichtterminierender oder abbrechender Interpretation einige Probleme bereitet, wird im folgenden Abschnitt 3.2 eine detaillierte Untersuchung des Zusammenhangs zwischen dem Datentyp boolean und der in der OCL zu verwendenden Logik vorgenommen.
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||