Ein kleines Rätsel, schauen Sie sich das jetzt mal an.
Da müssen Sie ein bisschen Kopf rechnen oder schlau sein.
Das ist halt nicht so leicht, weil man ziemlich viel rechnen muss,
zumindest Überschlagsrechnen muss man.
Haben Sie das sicher schon mal gehabt, dass Sie sich ein bisschen
rumplagen müssen.
Oberflächlich ist das erstmal, ich rechne die Millisekunden pro Tag,
also 64,96 mal 1000.
Und das andere ist 1000, das gleiche mal 1000.
Und hier wird das dividiert.
Aber passiert das wirklich?
Da müssen wir nochmal kurz überlegen.
Da kann hier ein Überlauf auftreten.
Aber eigentlich haben wir hier ein Long.
64 bit, das ist ziemlich viel.
Also das ist 1000 mal 1000, das ist eine Million.
Dann nehmen wir noch die zwei Nullen hinzu.
Dann haben wir 100 Millionen mal 36.
Also nehmen wir noch einen Faktor 10.
Da haben wir schon eine Milliarde.
Mal 24 noch eine.
Also jetzt können Sie überlegen, passt das rein?
Kann man ja im Kopf überschlagsmäßig rechnen.
Es geht ja um die 10er Potenzen hauptsächlich.
Also ich rechne das so.
10 hoch 6, 10 hoch 7, 10 hoch 8.
36, 6 mal 6, 36.
Noch eine 10er Potenz, 10 hoch 9.
Nochmal eine 10er Potenz von 24.
10 hoch 10.
Also habe ich 2,4 mal 3,6.
Da rechne ich mal 2 mal 4.
Da kann man sich das ausrechnen.
Also was kommt raus?
1000, 5000, 5000, langsam langsam.
Oder eine Ausnahme.
Mal kurz nachlegen.
Nur eine Antwort ist richtig.
Eintippen gilt nicht übrigens.
Was manche Schlauchl machen, das werde ich hier erklären.
Tippen die schnell die Aufgabe ein und schauen nach, was rauskommt.
Also nochmal zurück.
Zwei Longs, dividiert durcheinander, werden ausgedruckt.
Wer ist für 1000?
Wer ist für 5000?
Wer ist für 5?
Es tritt eine Ausnahme auf.
Wer ist für die Ausnahme?
Also ich gebe zu, es ist schwierig.
Es ist tatsächlich 5.
Also die paar, die es hatten, hatten recht.
Haben sie jetzt geraten oder haben sie es nachgerechnet?
Wer war das?
Kannst du jemanden erklären?
Warum 5?
Ja?
Genau.
Und das ist alles richtig.
Sprechen Sie ein bisschen lauter, dann kann ich Sie auch besser hören.
Ich wiederhole es gleich.
Ja gut, aber es tritt tatsächlich einen Überlauf auf, da haben Sie
recht.
Warum erkläre ich auch gleich.
Haben Sie richtig gesagt, aber wieso gerade 5?
Weil das erfordert einiges und Kopfrechnen kann ich nicht mal.
Ist auch nicht so wichtig, dass da gerade 5 rauskommt.
Aber wichtig ist eben, dass hier tatsächlich ein Überlauf aufkommt.
Der Ganzzahlwert, den Sie haben können, ist 2 Milliarden.
Und warum, da steht doch long.
Der Punkt ist, die Dinger hier werden zunächst noch als Ganzzahlen
betrachtet.
Das heißt, die Multiplikation folgt im 32-Bit-Bereich.
Pech gehabt.
Und das ist jetzt nicht so wichtig.
Wo der Überlauf jetzt auftritt,
der Überlauf tritt eben auf, wenn man es nachrechnet, das steht hier
unten, diese größte Zahl, die Sie überhaupt ohne Vorzeichen in 32-Bit
darstellen könnten, was ja dann ausgerechnet wird, das wäre ja kein
Vorzeichen da, ist eben dieses 4 Milliarden mal 20 und wenn Sie das
genau nachsehen, dann kommt irgendwann mal so ein Rest draußen, der
ist das hier.
Und dieser Rest, geteilt durch die andere Zahl, gibt eben 5, irgendwas
und da kommt der 5 raus.
Das ist also nicht so wichtig.
Aber, wie repariere ich es?
Ich möchte, dass das richtige Ergebnis, nämlich 1.000, rauskommt.
Eine L vor die Zahlen schreiben.
Das reicht.
Das würde reichen.
Also eine L an die Zahlen dran, das ist eine Long-Ganzzahl und dann
wird die ganze Arithmetik weitergeführt im Long-Bereich.
Und schon schwimmen wir aus, haben wir das Schlamassel nicht.
Also, Vorsicht bei Überläufen, die sehen manchmal ganz harmlos aus.
Also das hier, wenn man so große Konstanten nimmt, dann ist es schon
vernünftig mal nachzurechnen, ob das über die 2 Milliarden hinausgeht.
Das kann man meistens mit einer Überschlagsrechnung machen.
Sie rechnen einfach die Potenzen zusammen und wenn da noch ein paar
Konstanten dazu sind, dann können Sie die überschlagsmäßigen
multiplizieren.
Sie müssen also gar nicht mal mit riesigen Zahlen hantieren.
Und wenn Sie dann merken, das kann überlaufen, dann ist es ganz
leicht, das zu korrigieren.
Erstens alle Variablen als Long deklarieren und zweitens auch die
Ganzzahlen schon als Long angeben, mit einem großen L.
Keinem kleinen L, denn das kleine L übersieht man oftmals und meint,
das ist eine 1.
Das war es, das war also auch nicht schwierig dieses Mal.
Okay, also Anwendungs- und Klassendiagramm haben wir hinter uns, das
Aktivitätsdiagramm haben wir auch hinter uns.
Ich gebe noch eine kurze Erinnerung.
Wir hatten da eine ausführliche Animation und wir hatten hier diese
Grundkonstrukte, Sie erinnern sich, wir hatten einzelne Knoten, die
sind, das nennt man die Aktivitäten.
Dann kann man auf den Kanten zwischen den Aktivitäten entweder
Kontrollflussmarken marschieren lassen und diese Kontrollflussmarken
gehen von einer Aktivität zur nächsten.
Wenn ich mehrere habe, dann gehen sie zu allen.
Und wir hatten die folgenden Verbindungskonstrukte, nämlich hier so
eine Verzweigung mit einer Raute, das ist eigentlich aus ganz normalen
Kontrollflussdiagrammen geklaut.
Und dann gibt es auch eine entsprechende Verzweigung, hier wird nicht
gewartet, hat mich jemand gefragt, wenn ich hier eine Verzweigung
habe, wird da gewartet?
Nein, wenn hier eine Marke reinkommt, wandert sie sofort hier durch.
Dann sagten wir, es gibt diese Teilung, wenn es also einen
Kontrollfluss aufspalten möchte in mehrere, dann gibt es hier dieses
Symbol dafür.
Interessanter ist das nächste, das hier bedeutet eine Synchronisation,
das heißt, ich warte hier entweder auf Kontrollflussmarken, es müssen
also hier an jedem mindestens eine sein, dürfen auch mehrere sein, das
hatten wir in dem Beispiel gesehen und dieses Ding schaltet durch.
Wenn an allen Stellen mindestens eine ist, erst dann läuft die
Geschichte weiter und dann kommt hier eine Marke raus und wandert
fort, während hier alle Kontrollflussmarken verschwinden, und zwar
alle.
Wenn also hier 25 sich gestaut haben, dann verschwinden alle 25, es
geht trotzdem nur eine weiter.
Anders ist es bei den Datenobjekten, wenn sie hier auf Datenobjekte
warten, sie können auch Datenobjekte verschieben, dazu können sie
Typen usw.
angeben, das sehen wir auch gleich, dann wird hier jeweils nur eine
vertilgt und es kommt hier unten entweder, ja hier unten kann dann nur
noch eine Kontrollflussmarke rauskommen.
So, das geht übrigens auch bei den Aktionen, also hier ist auch ein
impliziter solcher Balken drin, wenn hier und hier eine Marke ankommt,
dann geht es weiter, andernfalls wartet diese Aktion auf beide
Kontrollflussmarken, ähnlich wie vorhin, also ist hierbei eigentlich
ein impliziter solcher Balken dazwischen, mit einer Kante, die weiter
geht.
Das mache ich dann, wenn ich Datenflussmarken, Datenobjekte haben
möchte, weil die mit so einem Balken ja nur zu einem
Kontrollflussmarke zusammengeführt würden und dann wären die
Datenobjekte wieder verloren.
Also mache ich das in diesem Fall so und das Beispiel hatten wir dann
gesehen.
Jetzt muss ich da schnell drüber klicken, weil das hatten wir schon
durchgenommen.
Wie die gegangen sind, haben das leider nicht erlebt.
So,
jetzt gibt es noch ein paar Verfeindungen.
Also das Wesentliche haben wir jetzt gesehen, wir können also
Datenflüsse und Kontrollflüsse damit sehen und damit den Ablauf von
Aktionen modellieren, ohne dass wir ein einzelnes Programm schreiben.
Das brauchen wir manchmal in der Definitionsphase, dass man so einen
Ablauf angibt.
Was kommt zuerst?
Und da gibt es jetzt noch ein paar Verfeinderungen.
Da gibt es diese Art von Stecker, kann man hinmalen, mit einer Eingabe
und einer Ausgabe.
Da gibt man den Datentyp an oder das Objekt hier an.
Englisch wird das als ein Pin genannt, ein Stecker.
Sie können es auch so darstellen, dass Sie sagen, ich habe hier eine
Aktion, hier eine Aktion, hier eine Aktion.
Hier kommt ein Datenobjekt an, da schreiben Sie hin, was das ist.
Zum Beispiel in unserem Beispiel von dem Wasserfallmodell wären das
Dokumente, die von einer Phase in die nächste kommen.
Oder aber Sie können es auch noch so schreiben, was ich nicht
empfehle, denn dann führt das oft zur Verwirrung.
Was ist jetzt Aktion und was sind Daten?
Ich würde also stark empfehlen, diese Notation immer zu benutzen,
obwohl diese auch geht.
Dann gibt es noch mehr Details.
Ich sagte Ihnen ja vorhin oder letztes Mal schon, dass ich so eine
Aktivität auch nochmal aufspalten kann in Subaktivitäten.
Ich habe auch hier wieder die Stecker mit den Eingaben und
Ausgabeobjekten.
Wenn ich diese Aktivität dann aufspalte, dann sieht es so aus, da
kommt auch wieder die Eingabe in die Ausgabe.
Die wird jetzt in diesen Stecker reingebaut, als ob dieser Stecker
hier irgendwie so durchstecken würde, durch die Grenze.
Und das ist dann der Eingangsparameter und das ist der
Ausgangsparameter.
Hier drin kann ich wieder ein ganzes Aktivitätsdiagramm schreiben.
Außerdem kann ich in der Aktivität noch den Typ des Ein- und
Ausgabeobjektes angeben.
Irgendein Datenobjekt, sei es eine Ganzzahl oder ein ganzes Objekt,
also eine Instanz einer Klasse kann ich hier angeben, indem ich
einfach hier den Typ hinschreibe und hier natürlich dann die
Objektschreibweise nehme mit Doppelpunkt irgendwas.
Okay, dann haben wir das gesehen.
Noch eine Kleinigkeit, die ist nicht so furchtbar interessant, aber
wenn Sie so ein Aktivitätsdiagramm haben, dann hört es manchmal
unübersichtlich und Sie können es dann in sogenannte Partitionen
aufteilen.
Das heißt, Sie können sagen, also diese Schritte schreibe ich in diese
Partition oder Teildiagramm rein und diese einen Schritte in das
andere.
Das nimmt man auch noch dafür her, um zu sagen, wo diese einzelnen
Aktionen ablaufen.
Zum Beispiel, wenn Sie eine kleinen Serveranwendung haben, könnte
dieser Schritt und dieser Schritt auf der Klientenseite passieren,
während diese Partition der Dienstgeber oder der Server sein könnte.
Es können also unter Umständen unterschiedliche Rechner sein, diese
Partitionierung, dann ist es recht praktisch.
Und das ist klar, natürlich bedeutet das hier und dieser Übergang dann
später in der Implementierung eine Telekommunikationsoperation und
nicht nur eine normale Parameterübergabe oder Zugriff auf eine
gemeinsame Datenstruktur.
Das glaube ich ist auch recht einsichtig und auch recht praktisch.
Wenn Ihnen das Kästchenschreiben zu blöd wird, weil diese Schritte
alle irgendwie schon auf dem Blatt Papier verteilt sind und Sie sie
nicht mehr auf die Reihe kriegen, auf eine Seite, dann können Sie auch
noch die Partition drüber schreiben.
In dieser Form.
Dann ist das Partition A und das ist Partition B und das ist Partition
A wieder.
Wenn man das machen will, aber natürlich ist es schöner, wenn man es
reinschreibt und dann in diese Form angibt.
Gibt es dazu irgendwelche Fragen?
Okay, jetzt geht es aber viel schneller als mit dem Klassendiagramm.
Dann gibt es noch mehrere Interaktionsdiagramme, von denen wir aber
nur eins anschauen, Sequenzdiagramm.
Hier zeigen wir an, wie Objekte miteinander interagieren.
Es ist einfach in den Kopf zu halten, dass wir noch vor dem
Programmieren sind.
Wir haben also noch keinen Code geschrieben, aus dem wir natürlich die
Interaktion ablesen könnten, sondern wir müssen sie erst einmal
angeben, um zu beschreiben, wie ein bestimmter Ablauf zu denken ist.
Wir brauchen zunächst dafür immer ein Klassendiagramm, denn im
Interaktionsdiagramm kommen die Klassen vor oder zumindest die Objekte
aus Klassen.
Da gibt es jetzt vier Typen, die zeige ich Ihnen kurz an, müssen Sie
sich nicht merken.
Es gibt das Kooperationsprogramm, das sieht so aus, das werden wir
nicht benutzen.
Es gibt ein Zeitdiagramm, das nehme ich eher her bei Echtzeitsystemen.
Dann gibt es ein Interaktionsübersicht und dann gibt es das
Sequenzdiagramm.
Und das Sequenzdiagramm, das schauen wir uns jetzt möglichst an.
Wo es herkommt, ist aus der Modellierung von
Telekommunikationsdiensten und es ist benutzt, um einen Ablauf eines
Anwendungsfalles genauer zu spezifizieren.
Eigentlich ist es nichts anderes als ein Aufrufsdiagramm.
Ein Aufrufsdiagramm, das sagt, die Methode der Klasse so und so ruft
auf eine Methode eines anderen Objektes und das wiederum ruft ein
anderes auf und das wiederum ruft ein viertes auf und dann kehren die
beiden, der letzte zurück und dann macht der dritte weiter und ruft
noch etwas auf und so etwas.
Das nennt man einen Aufrufsgrafen.
Und das Sequenzdiagramm ist im Grunde genommen nichts weiteres als ein
Aufrufsgraf in einer besonderen Form.
Sie wissen alle, was Methodenaufrufe sind, Sie denken, Sie verfolgen
die alle runter, gibt es fünf Aufrufe, dann gibt es einen Rückkehr und
einen anderen Aufruf, noch fünf, sechs Aufrufe und dann kehren Sie
wieder zurück.
Genau das macht ein Sequenzdiagramm in der folgenden Form.
Es geht um den zeitlichen Ablauf, benötigt allerdings viel Platz.
Das läuft also jetzt folgendermaßen.
Wir haben hier immer oben ein Objekt.
Das Objekt ist hier anonym.
Also ist es eine Artikelreservierung.
Vom Typ gibt es also eine Klasse, die heißt Artikelreservierung.
Das können wir ja schon lesen.
Und das ist die sogenannte Lebenslinie.
Hier haben wir noch so ein Objekt, das heißt auch eine Lebenslinie.
Die Lebenslinie, wenn etwas noch nicht aufgerufen wird, wird erstmal
gestrichelt gezeichnet.
Gestrichelt gezeichnet heißt einfach, das Ding ist da, aber es hat
noch keinen Aufruf abgekriegt.
Hier bei der Artikelreservierung haben wir bereits einen Aufruf, einen
Methodenaufruf, nämlich da wurde die Reserviermethode aufgerufen, mit
dem Parameter B meinetwegen.
Da können Sie reinschreiben und dann sagen wir, okay, zu diesem
Zeitpunkt wird dieses Objekt aktiv und das mache ich so, indem ich so
einen größeren, breiten Balken drüber male.
Wie nennt man das?
Standard nennt das eine Swimlane, also eine Schwimmbahn.
Also wie bei einer Schwimmbahn im Schwimmbad.
Das ist die Idee und hier kommt die Antwort zurück beziehungsweise die
Rückkehr und schon haben wir wieder alles mögliche an
unterschiedlichen Pfeilen.
Das hier ist übrigens ein offener Pfeil und der muss gestrichelt sein.
Das ist also die Rückkehr oder gibt natürlich dann eine Antwort
zurück, die kann man übrigens noch drüber schreiben.
Das hier nennt man den Steuerfokus oder Steuerungsfokus oder auch die
Schwimmbahn.
So, wir bauen jetzt ein bisschen auf, dass wir mehrere Aufrufe haben,
dass Sie sehen, wie der Aufrufsgraph läuft.
Hier haben wir noch ein Objekt, eine Bestellung mit einer leeren
Schwimmbahn und jetzt nehmen wir an, wir rufen jetzt die Methode gibt
Bestellung, Bestellposition an der Bestellung auf und als Ergebnis
kriegen wir das Bipost, die Bestellposition zurück.
Hier ist der Rückkehr.
Da ist ein kurzer Aufruf gewesen.
Sie sehen schon, Aufruf, Aufruf, Rückkehr, Rückkehr.
Aber wir treiben das noch ein bisschen weiter.
Wir holen uns noch einen weiteren Aufruf von Bestellposition, den gibt
es auch, den haben wir ja gekriegt, also streiben wir uns den hier
rüber, dass wir damit hantieren können.
Die Bestellposition Bipost, da gibt es jetzt einen Gibartikelaufruf.
In der Bestellposition holen wir uns den Artikel heraus.
Damit kriegen wir als Rückgabe diesen Wert zurück.
Das ist also fast wie ein ganz normaler Aufruf mit Rückgabewert.
Das sind dann sogenannte lokale Attribute, die ich natürlich in diesem
Ablauf brauche.
Und zwar in dieser Reserviere-Methode oder Reserviereaufruf.
Dann hole ich mir die Anzahl raus, ebenso mit einem Aufruf und
Rückkehr.
Das sind also Aufrufe, die hier rausgehen.
Und jetzt kommt einer, der sagt, ich will das auch noch reservieren.
Irgendwie setzt das ein bisschen aus heute.
Da gebe ich dem den Artikel und die Anzahl mit, die ich mir vorhin
geholt habe.
Und das war es.
So ist es eigentlich.
Es kommen jetzt noch ein paar Verfeindungen, aber Sie sehen ganz
deutlich, das ist einfach eine Aufrufs-Hierarchie.
Aufruf, Rückkehr, Aufruf, Rückkehr, Aufruf, Rückkehr, Aufruf,
Rückkehr.
Und der erste Aufruf war der hier.
Natürlich könnt ihr das hier weiterschreiben.
So, jetzt kommen noch ein paar Feinheiten, damit man genauere Sachen
angeben kann.
Die zeige ich Ihnen als nächstes.
Also zuerst mal die Pfeile.
Die synchrone Nachricht oder der synchrone Aufruf ist einfach dieser
Pfeil, geschlossen und durchgeschrieben.
Der Rückkehr-Pfeil ist offen und gestrichelt.
Und der Pfeil, der hier geöffnet ist, ist eine sogenannte asynchrone
Nachricht.
Die hatten wir im Beispiel nicht.
Aber die würde zum Beispiel dazu führen, dass es keine Rückkehr gibt.
Da würde zum Beispiel das, wenn das ein asynchroner Aufruf wäre, der
würde hier einfach weiterlaufen bis zu einem Zeitpunkt.
Wir können dann den Zeitpunkt angeben, wo dieser asynchrone Aufruf
selbst endet.
Mit einem Kreuz, da sagen wir, okay, der stoppt hier.
Brauchen wir relativ selten, aber es gibt es.
Der Steuerungsfokus ist diese Überlagerung der gestrichelten
Lebenslinie.
Und da sehen wir, welche Methoden gerade aktiv sind, d.h.
welche aufgerufen sind.
Natürlich ist bei so einem Aufruf dann immer so, dass wir den Ablauf
betrachten müssen.
Wenn wir zum Beispiel am Ablauf angekommen sind, dann sind die hier
aktiv und die anderen nicht mehr.
Also auch ein zeitliches Diagramm.
Und die Zeit läuft von oben nach unten.
Okay, da haben wir das gesehen.
Jetzt kommen noch die Variationen.
Ich sagte vorhin von einem asynchronen Aufruf, da haben wir einen.
Ein asynchroner Aufruf hier mit dem offenen Pfeil.
Da läuft dieses Objekt, was immer die Methode Nachricht 3 bewirkt.
Und hier sagen wir, okay, hier ist das Ablauf beendet und sogar das
Objekt zerstört.
Dann haben wir hier noch einen rekursiven Aufruf drin.
Der rekursive Aufruf ist das hier, den zeige ich nicht so.
Und indem ich diese Schwimmbahn mit einer kleinen weiteren Schwimmbahn
überdecke.
Wenn ich also mehrere rekursive Aufrufe hätte, dann würde sich das so
gewissermaßen aufstapeln.
Um anzudeuten, dass jetzt mehrere Rückkehr aus einem rekursiven Aufruf
erforderlich sind.
Ferner ist natürlich schon wieder ein gestrichelter Pfeil.
Es kann also sein, dass die Objekte, die Sie brauchen, mit denen Sie
hantieren, am Anfang dieser Methode noch nicht alle existieren.
Ich brauche also eine Möglichkeit, ein Objekt zu zerstören.
Und das geht mit diesem gestrichelten Pfeil.
Auf den schreiben wir Create drüber.
Und sage ich, okay, ab hier gibt es jetzt dieses Objekt der Klasse X.
Und das bedeutet eben jetzt die Objekterzeugung.
Da ist keine Schwimmbahn drüber, denn Create erzeugt erst nur das
Objekt.
Aber wir können damit rechnen, dass kurz darauf natürlich hier nochmal
ein Aufruf erfolgt, an die Klasse X, an das Objekt der Klasse X, um
einen Ablauf in Gang zu setzen.
Das sind also die einfachen Dinge.
Jetzt müssen wir noch diese Kästen anschauen.
Die Kästen sehen so aus, dass hier, wenn Sie so einen Kasten drüber
malen, was ist, wenn ich eine Fallunterscheidung treffen muss mit
einer IF-Anweisung oder einer Switch-Anweisung.
Wie mache ich das?
Das können Sie auch machen.
Alternative schreiben Sie dafür für Alt, hier in dieser Ecke, Kasten
rum.
Und dann schreiben Sie hier die Bedingung hin und hier ein Else.
Sie können sogar mehrere Bedingungen haben.
Es ist also nicht nur eine Aufspaltung in zwei Möglichkeiten, sondern
beliebig viele.
Ähnlich einer Switch-Anweisung.
Sie müssen nur immer hierhin in eckigen Klammern die Bedingung
schreiben.
Dann kann ich also auch Fallunterscheidungen angeben.
Das wird dann oftmals das Diagramm zerfasern.
Sie können das stattdessen oder zusätzlich dazu sagen, also hier ist
eine kompliziertere Interaktion und ein Verweis auf diese.
Ich zeige hier nur Interaktion 2 oder irgendwas rein.
Und das REF bedeutet nur, da gibt es ein weiteres Diagramm, in dem
diese Interaktion genauer gezeichnet wird.
Da steht also dann daran Interaktion 2.
Und dann kann ich da drin wieder zum Beispiel dieses Diagramm
anzeichnen mit der Alternative.
Oder ein komplexeres Unterdiagramm.
Eine Verschachtelung von Diagrammen, ähnlich wie beim
Aktivitätsdiagramm.
Hier ist eine Hand, bitte.
Genau, nein, gibt es nicht.
Also Sie können eigentlich nur hier so eine Selbstrekursion aufführen.
Und selbstverständlich darf, wenn Sie das meinen, darf der hier auch
einen Rückruf machen.
Nur da unten.
Nein, das ist ein Selbstaufruf.
Das ist ein rekursiver Aufruf, aber ich muss nicht hier oben beginnen.
Aber ich muss dann hier einfach die Interaktion mit anzeichnen.
Die kommt halt dann als nächstes.
Das ist also nicht ein Programm, das irgendwie die Rekursion in
knapper Form enthält, wie ich das im Programm hinschreibe, sondern das
ist ein zeitlicher Ablauf.
Wenn erst der Aufruf war, dann kommen halt erst die und dann kommt
erstmal ein rekursiver Aufruf.
Und der rekursive Aufruf, was macht der eigentlich?
Der zeigt also an, was als nächstes käme.
In der Regel wird hier diese Rekursionsstufe, ich habe noch keins
gesehen, wo ich mehr als zwei hatte in der Praxis.
Dass ich solche rektiven Rekursionen brauche, ist eigentlich nicht der
Fall.
Was haben wir noch?
Gibt es sonst noch Fragen?
Die Rückgabe-Pfeile, meinen Sie?
Ja, gut, der Punkt hatte ich noch nicht gesagt.
Die Rückgabe-Pfeile sind optional.
Wenn es klar ist, wo wir hinzurückkehren, dann kann ich sie weglassen.
Insbesondere auch, wenn ich so einen Fall hatte wie vorhin.
Wenn ich sowieso schon angebe, dass ich in der lokalen Variable den
Rückgabe -Wert speichere, dann kann ich mir diesen Rückgabe-Pfeil auch
sparen.
Aber manchmal ist es ganz gut zu sehen, wo ich einfach in der Rückkehr
bin.
Ja, noch eine Frage?
Wie gebe ich Gleichheit an?
Da werde ich zur Sicherheit ein Doppelgleichzeichen nehmen.
Aber eigentlich ist es nicht so wichtig, denn vom Kontext her können
Sie erkennen, was gemeint ist.
Also, das denke ich würde gleich auch reichen, denn hier müssen
Bedingungen stehen und sie sind auch eingeklammert.
Noch Fragen?
Da fällt mir gerade etwas ein, weil wir über Erzeugung sprechen.
Ich glaube, Sie haben mich da letztes Mal gefragt, wissen das im UML
-Diagramm, wenn ich Konstruktoren brauche, wie schreibe ich in ein UML
-Klassendiagramm die Konstruktoren?
Sie erinnern, wir haben in diesem Kasten für die Klassen, da stehen
die Methoden drin und darüber die Attribute.
Und was ist jetzt mit den Konstruktoren?
Die Konstruktoren im UML-Diagramm müssen nicht Klassenname sein.
Sie können sie beliebig nennen.
Sie können sie natürlich auch mit Parametern versehen, wie jede andere
Methode.
Aber sie müssen dann drüber oder davor ein Create schreiben.
Create mit spitzen Klammern, mit zwei spitzen Klammern.
Also diese, wenn das der Konstruktor ist, also diese Klasse hier, wenn
ich die im UML-Klassendiagramm hätte, dann würde ich einen Create,
spitze Klammer, spitze Klammer Create, spitze Klammer zu, spitze
Klammer zu hinschreiben.
Ähnlich wie für Abstrakt und Schnittstelle und so weiter.
Und wie gesagt, UML hat nicht die Konvention, dass der Konstruktor
seinen gleichen Namen haben muss wie die Klasse.
Sie können sie in beliebigen Namen angeben.
Genau, da haben wir das noch nachgeholt.
Das haben wir in die Folien reingeschrieben.
An irgendeiner Stelle finden Sie das, wenn Sie sich sicher sind, dass
Sie die Neueste haben, dann ist alles klar.
Ansonsten holen Sie sich vielleicht nochmal die neueste Version
runter.
Notationselemente.
Diese Operatoren, das nennt man die hier, Alt und Ref und so weiter,
es gibt auch noch Schleife.
Wie gesagt, die machen die Diagramme meistens sehr unübersichtlich.
Es ist dann meist besser zu sagen, okay, gibt es da nicht eine weitere
Methode, die das beinhalten könnte?
Und dann wird die dann aufgerufen.
Das sind die sogenannten Operatoren.
Da gibt es die Alternative, wie gesagt, Bedingung 1, das sollte
eigentlich Bedingung 2 sein, beendet mit einem S.
Break-Bedingung haben Sie auch.
Opt ist eine optionale Sequenz, die wird nur ausgeführt, wenn die
Bedingung wahr ist.
Das ist ein kurzes If, wenn Sie so wollen.
Und hier gibt es Teilsequenzen, die können Sie auch noch parallel
ausführen lassen.
Dann sind wir mit dem Ding schon fertig.
Also das ist das Sequenzdiagramm.
Also ich wiederhole nochmal, wir haben jetzt vier Diagrammtypen
gesehen.
Den Anwendungsfalldiagramm, dann das UML-Klassendiagramm, das war das
hier.
Eines der Interaktionsdiagramme, nämlich das Sequenzdiagramm und das
Aktivitätsdiagramm.
Jetzt folgt ein letztes, nein zwei letztes Zustandsdiagramm.
Das wird uns ein bisschen länger beschäftigen, aber ist eigentlich nur
eine Erweiterung eines normalen endlichen Automaten mit
Zustandsübergängen.
Und am Schluss haben wir noch das Paketdiagramm und das Paketdiagramm
ist was ganz Einfaches.
Das ist sogar noch einfacher als das Anwendungsfalldiagramm.
Okay, also los geht's.
Zustandsdiagramm, State Machine, Finite State Machine ist einfach ein
Automat, ein endlicher Automat, wie Sie ihn aus den Grundbegriffen
kennen, mit Zuständen und Übergängen.
Und mit dem können wir jetzt beschreiben, wenn sich ein Objekt in
verschiedenen Zuständen befindet.
Sie erinnern sich, der Zustand, das sagten wir, dass sich in einem
bestimmten Zustand ein Objekt immer gleich verhält.
Dazu müssen wir natürlich den Zustand kennen und die Zustandsübergänge
beschreiben.
Nicht jedes Objekt hat ein Zustandsautomaten oder Zustandsdiagramm mit
sich assoziiert.
Aber für die Fälle, dass es ein nicht trivialer Zustandsautomat ist,
haben wir auch hier eine Möglichkeit, so einen Automaten in UML zu
schreiben.
Der gilt dann für den gesamten Lebenszyklus eines Objektes oder auch
für die Ausführung einzelner Operationen.
Und das sieht folgendermaßen aus, hier ist ein Beispiel mit ziemlich
viel Zeug schon drin.
Es ist etwas komplizierter, als was Sie in den Grundbegriffen gehört
haben.
Also erstmal haben wir Zustände, das sind die grünen Dinger hier.
Und was wir hier machen ist, wir modellieren ein Objekt, das eine
Flugreservierung speichert.
Es beginnt im Zustand dem hier, das ist angezeigt wie beim
Aktivitätsdiagramm mit diesem Punkt hier.
Wenn wir ein Objekt erzeugen, dann sind wir im Zustand ohne
Reservierung.
Wir gehen über in den Zustand teilweise reserviert, wenn die Eingabe
reserviert erscheint.
In den Grundbegriffen haben Sie dazu wahrscheinlich gesagt, die
Eingabe oder das Ereignis.
In diesem Klassendiagramm sagen wir auch Ereignis dazu.
Allerdings ist das hier ein Methodenaufruf.
Was bedeutet ein Methodenaufruf?
Wir haben keine Eingabe in den Zustandsautomaten, sondern einfach nur
sagen, wenn ein Methodenaufruf passiert, dann bewirkt das einen
Zustandsübergang.
In diesem Fall, wenn ich Reservieren aufrufe, gehe ich in den Zustand
teilweise reserviert, denn jetzt ist mindestens ein Platz reserviert.
So, Sie sehen aber hier noch, gibt es Zustandsübergänge, die bleiben.
Wenn ich hier drin aufrufe, Stornieren, dann bleibe ich in diesem
Zustand, aber hier mit diesem Aufruf komme ich raus, gehe ich zurück
in den anderen Zustand.
Und das liegt daran, dass hier Bedingungen dran stehen.
Ähnlich wie beim Sequenzdiagramm stehen hier Bedingungen unter dem
Ereignis und die sagen, dieser Übergang passiert, wenn diese Eingabe,
dieses Ereignis, nämlich Stornieren, aufgerufen wird und die Bedingung
erfüllt ist, dass die Anzahl reservierter Plätze noch positiv ist.
Dann bleibe ich in diesem Zustand.
Andernfalls, wenn die Zahl der reservierten Plätze vor dem Aufruf des
Stornierens 1 ist, dann werden sie natürlich zu 0 werden und ich gehe
zurück in den ohne Reservierungszustand.
Also das ist schon die erste Änderung, die wir kennen von dem normalen
Zustandsdiagramm.
Das hat keine Bedingungen an den Übergängen dran.
Hier können wir diese Bedingungen dranschreiben und Sie sehen, dann
kann ich das gleiche Ereignis zweimal benutzen.
Wenn Reservieren aufgerufen wird, dann passiert etwas ähnliches.
Solange noch Plätze vorhanden sind, bleibe ich in dem Zustand
teilweise reserviert.
Wenn aber die Plätze ausgefüllt sind, keine freien Plätze mehr da
sind, dann gehe ich in den Zustand ausgebucht.
Wenn ich jetzt wieder storniere, gehe ich teilweise zurück.
Das kann ich jetzt nicht mehr im Einzelnen erklären.
Hier ist auch noch ein Übergang, der ist wieder mal ohne Bedingungen.
Der hier war übrigens auch ohne Bedingungen.
Flugstreichen, das ist auch ein Übergang in das Ende.
Und wenn ich das Ereignis schließen aufrufe, dann gehe ich in den
Zustand geschlossen.
Dieses Objekt, das ist also nochmal zur Erinnerung, Zustandsautomat,
der an ein Objekt gebunden ist.
Und dieses Objekt würde dann wahrscheinlich eine lokale Variable
haben, die heißt Zustand und die nimmt Werte aus einem enumerierten
Datentyp, teilweise reserviert, ausgebucht und geschlossen.
Das war der Anfangszustand, das nennt man Zustand.
Bedingung, auch Guard oder Wächter, das ist auch ein Transition oder
Zustandsübergang.
Das hier ist übrigens ein Epsilon-Übergang, denn da steht kein
Ereignis dran.
Dieser Übergang von geschlossen auf Endzustand kann jederzeit
erfolgen, auch ganz spontan.
Natürlich muss der Zustand dazu geschlossen sein.
Das ist der Endzustand.
Jetzt gibt es noch drei Erweiterungen, die mit den Zustandsübergängen
zu tun haben.
Also ich sagte Ihnen schon, wir haben ein Ereignis mit Parametern und
Argumenten.
Wir haben eine Bedingung dran, wenn wir wollen, ist optional.
Und ein drittes mit dem Querstrich abgetrennt ist eine Operation, die
ausgeführt werden soll.
Wir können also noch zusätzlich sagen, wenn du dieses Ereignis
aufrufst an dem Objekt, dann bei diesem Übergang auch noch die
Operation da unten auszuführen.
Ich kann also an den Übergang sogar noch eine zusätzliche Operation
drankleben.
Das andere haben wir schon besprochen.
Dann gibt es noch zeitliche Abhängigkeiten, die sagen, zu einem
bestimmten Zeitpunkt, sagen wir um 12 Uhr Mittag, erfolgt ein
bestimmter Übergang.
Das ist also am Zustandsübergang dran.
After, das ist ein Ausdruck, der sagt nach so und so vielen Sekunden
zum Beispiel.
Da könnte ich jetzt zum Beispiel sagen, Sie kennen das von den
verschiedensten Apparaten, wie zum Beispiel digitalen Uhren oder sonst
was, wo Sie sagen, ich gehe in den Zustand Zeit einstellen, aber wenn
ich nichts mehr tue, dann kehrt das Ding nach 10 Sekunden zurück in
den Grundzustand und der Grundzustand ist Zeitanzeige.
Dann würde ich also sagen, after 10 seconds, Übergang zurück in den
Grundzustand.
Das ist ja auch sehr praktisch, um gerade diese Zeitabhängigkeit
auszudrücken.
So, Aktionen.
Da gibt es jetzt noch ein Detail.
Sie können an die Zustände Eintritts- und Austrittsaktionen dran
kleben.
Und da schreibt man einfach Exit und eine Schrägstrich-Aktion dazu und
Entry -Aktion.
Das bedeutet, bei jedem Übergang in den Zustand wird diese Aktion
ausgeführt beim Entry und das Exit sagt jedes Mal, wenn ich den
Zustand verlasse, gleich über welchen Übergang muss die Exit-Aktion
ausgeführt werden.
Also haben wir hier einen.
Ich schaue nochmal nach.
Hier haben wir eigentlich keinen.
Ah doch, hier ist eine Eingabe.
Das heißt hier, wenn ich in diesen Zustand komme, zum Beispiel von
hier oder auch von hier, dann rufe ich noch die Funktion Zurücksetzen
auf.
Das ist nochmal das Gleiche, das kann man schon nochmal beschriftet.
Jetzt eine Frage für Sie.
Denken Sie mal über die Entry-Aktion nach.
Ist das jetzt eine notwendige Erweiterung?
Das heißt, wenn ich Entry-Aktionen nicht hätte, könnte ich das
trotzdem modellieren?
Das ist doch immer die übliche Frage.
In der Theorie habe ich mit diesen Änderungen etwas gebaut, was den
Automaten oder was wir da haben, mächtiger macht, dass er mehr kann.
Normalen Automaten ohne diese Eigenschaft der Entry-Aktion nicht
hätte.
Also das könnte ich absolut einfach beseitigen, wenn ich wollte.
Oder das Argument, dass es dadurch nicht mächtiger wird, indem ich die
Zurücksetzen -Operation einfach noch hier dran setze und hier dran.
Aber natürlich ist es bequemer, die Entry-Aktion hinzuschreiben, wenn
an allen Pfeilen, die reingehen, das passiert.
Und das Gleiche mit den Exit-Aktionen.
Da muss ich es eben an allen austretenden Pfeilen ankleben.
Also da ist nichts weiter passiert.
Jetzt kann man sich fragen, wird der Automat mächtiger überhaupt über
diese Aktionen, die ich noch an die Kanten dran schreibe, kann?
Naja, eigentlich nicht, denn ich könnte diesen Methodenaufruf noch mit
dem zusätzlichen Aktionen verknüpfen und ihm einfach einen neuen Namen
geben.
Reservieren -XYZ.
Dann mache ich eine Reservieren-Plus-XYZ-Methode, die das Gleiche tut.
Ist also auch in diesem Fall nicht mächtiger geworden.
Aber diese Frage werden wir uns jetzt noch mehrmals stellen und in den
nächsten beiden Fällen ist es vielleicht nicht mehr ganz so einfach.
Gibt es aber soweit Fragen?
Ja, also wir merken uns, dieses Zustandsdiagramm ist ein ganz normaler
Zustandsdiagramm mit Zuständen und Übergängen.
Die Übergänge sind ausgelöst durch Methodenaufrufe.
Diese Übergänge sind auch noch gesteuert durch Bedingungen, die ich
dran kleben kann.
Und Aktionen, die beim Übergang ausgeführt werden können.
Es gibt übrigens auch Epsilon-Übergänge, da ist eben kein Ereignis
erforderlich.
Ich kann zeitliche Abhängigkeiten abgeben und ich kann für die
einzelnen Zustände auch noch Eintritts- und Austrittsaktionen angeben.
So, jetzt gibt es noch ein paar Verfeinerungen.
Wie immer, irgendwann muss der Automat so groß werden, dass ich ihn
nicht mehr überblicke.
Ich brauche einen hierarchischen Automaten.
Der hier ist jetzt wirklich nicht groß, aber Sie werden sehen, was die
Idee dahinter ist.
Ich sage also folgendes.
Wir schauen uns erst einmal das rechte Bild an.
Das ist die Übersetzung in den normalen Automaten.
Das rechte Bild sagt, ich habe hier so einen Automaten, der geht von A
nach C.
Das wäre der Anfangszustand.
Aber dieser D-Automat hat mehrere Übergänge an das B.
Und zwar Übergänge von allen, die hier drin sind.
Wenn immer es so einen Übergang gibt, dann müsste ich sehr gerne jedes
Mal diesen Übergang hinschreiben.
Ich kann das auch so schreiben, dass ich die hier zusammenfasse und
sage, hier ein Übergang raus nach B und dann der Übergang hier zurück.
Habe ich jetzt wirklich nichts gewonnen, außer dass ich einen Pfeil
weggelassen habe.
Statt zwei Pfeilen habe ich jetzt einen Pfeil geschrieben.
Naja, das ist also nicht gerade berauschend, aber stellen Sie sich
vor, hier steht ein großes Diagramm.
Das ist schon jetzt über eine Seite voll und da gibt es überall Pfeile
raus an diesen anderen Subautomaten.
Na gut, dann kann ich das hier zusammenfassen, hier einen Automaten
zusammenfassen und dann die Übergänge so steuern, vorausgesetzt, sie
sind eben so, dass ich von jedem dieser Zustände an das B übergehen
kann.
Da gibt es jetzt also noch, und natürlich ist klar, durch meine
Zeichnung hier haben Sie schon geraten, dass durch diese Einführung
dieser Gruppierungen keine zusätzliche Eigenschaft des Automaten
entsteht, dass er plötzlich andere Sprachen erkennen könnte oder so
etwas.
Es gibt auch noch, also Sie haben jetzt gesehen, ich muss jetzt in den
Automaten B, der hier drüben ist, stellen Sie sich dafür wieder ein
ganzes Diagramm vor, diese Pfeile reinzeichnen in die Zielpositionen.
Und das kann auch umständlich werden, insbesondere, wenn Sie so etwas
sagen wollten, wenn ich hier rübergegangen bin und hier irgendwie
durch einen dicken Automaten zurückgelaufen bin und dann zurückkehre
in den anderen, dann würde ich eigentlich gerne in den Zustand gehen,
in dem ich war, bevor ich erreicht wurde.
Das geht mit dem H-Attribut, das History-Attribut oder Gedächtnis.
Das deutet Folgendes an, das sagt, wenn Sie irgendwo in diesem
Automaten stecken, in diesem Automaten D, und es erfolgt das Ereignis
C, also irgendein Aufruf, der heißt C, dann verlassen Sie dieses
Diagramm und springen in den Zustand B, hier in einem anderen
Diagramm.
Wenn B dann das Ereignis D bekommt, jetzt gehst du zurück, dann gehst
du genau dahin, von wo du kamst.
Das heißt, dieses History-Attribut deutet also an, dass ich mir
irgendetwas Zusätzliches merken muss, nämlich wo ich das letzte Mal
war.
Ich könnte das mit dem Variablen kodieren und dann wird es immer
verdächtig, ob ich damit nicht wieder die Leistungsfähigkeit des
Automaten erhöht habe.
Könnte ich das auch ohne Zusatzvariable machen, sodass ich mir
gewissermaßen merken kann, von wo ich kam, von A oder von C und dann
zurückgehe in den Ursprungszustand.
Also die Frage ist wieder, wir haben jetzt da eine neue Notation
eingeführt, möglicherweise einen ganz neuen Automaten erzeugt, ist der
überhaupt anders oder ist das nur eine schöne Schreibweise?
Da kam schon eine Hand, hat jemand eine Antwort dafür?
Ja, eins, zwei, drei.
Ich glaube, Sie waren zuerst, mit dem blauen Shirt.
Ja, aber jetzt überlegen Sie sich noch, was Sie machen könnten, wenn
Sie viele Zustände hinzuführen könnten.
Ich glaube, Sie hatten die Idee.
Genau, das ist der Trick.
Der Trick ist einfach, ich repliziere diesen Automaten, was immer der
ist.
Ich habe einen bin-von-A-gekommen-Automaten und einen anderen
Automaten, der sagt bin-von-C-gekommen.
Das führt natürlich zu einer gewaltigen Aufblähung.
Aber daran sieht man, dass dieser Automat eben noch nicht mehr leisten
kann.
Also hier in unserem Fall sieht es absolut einfach aus wieder.
Ich habe hier das BA, also hier sagt das bin-von-A-gekommen, der sagt
bin -von-C-gekommen, repliziere einfach alles und der Rückkehrpfeil
geht dann eben an A oder an C.
Also haben wir hier auch keine neue Art von Automat gemacht, sondern
wir haben nur eine Schreibweise ausgedacht, die es uns erlaubt,
umfänglichen Automaten knapper hinzuschreiben.
Okay, also diese Idee, diesen Automaten mit diesem Automaten zu
simulieren, das gebe ich Ihnen noch eine Erweiterung.
Da können Sie sich dann gleich überlegen, wie Sie den simulieren
können, wenn es geht.
Also der heißt, ein Automaten, der parallel ist.
Und das ist jetzt wirklich scheinbar etwas ganz anderes.
Ich habe also jetzt diesen Automaten und der sagt, ich habe zwei
Zustände, da kann ich mit A und B dazwischen hin und her wechseln.
Das ist der Anfangszustand und gleichzeitig auch noch den hier, da
könnte zum Beispiel auch A und B vorkommen.
Ich habe es ja C und D, aber es ist keine Einschränkung an welche Art
von Ereignissen.
Das hat jetzt den Erfolg, wenn hier also noch ein A stünde, wenn das
Ereignis A auftritt, dann geht ich in dem Zustand von A nach B und in
dem Zustand von C nach D gleichzeitig.
Deswegen nebenläufig.
Und das hatten wir jetzt in einem normalen Automaten jetzt tatsächlich
nicht.
Also wie gesagt, rentiert sich alles nicht für Zustände mit diesen
paar Zuständen, sondern es wird erst interessant, wenn ich etwas
Größeres zeichnen muss.
Also Sie könnten jetzt sagen, ich habe einen Zustandswechsel hier und
einen weiteren Zustandswechsel dort, alles in einem gleichen Diagramm.
Jetzt ist die Frage, ist das jetzt ein neuer Automat oder kann ich ihn
mit einem normalen Zustandsdiagramm nachmodellieren?
Ja, Sie haben Ihre Hand, graues Hemd.
Exakt, das ist die exakte Lösung.
Also einfach auch wieder beim Simulieren, replizieren Sie Zustände und
da sagen Sie, ja gut, ich kann sowohl in A als auch C und A und in D
sein.
Also habe ich hier zwei Zustände, A, C und A, D.
Und wenn ich im Zustand B bin, kann ich hier drüben im Zustand C und D
sein.
Also nehme ich einen neuen Zustand B, C und B, D.
Ich nehme also einfach das Kreuzprodukt aus allen Zuständen und baue
mir einen neuen Automaten.
In unserem Fall ist der auch wieder ganz einfach.
Gibt es ein A, C, ein A, D, ein B, C und ein B, D und dann kann ich
die Zustandsübergänge eintragen und habe jetzt einen ganz normalen
Automaten.
Übrigens, diese Idee der Nebenläufigkeit, wie auch der hierarchischen
Aufteilung und diesen anderen Erweiterungen, haben also nicht die UML
-Standardisierer erfunden, sondern ein Wissenschaftler namens Harrell,
ein Israeli, der sich eben die Frage gestellt hatte, wie man mit
großen Zustandsautomaten, zum Beispiel in Flugzeugen, in
Kampfflugzeugen, wie man die modellieren kann und hat diese
Erweiterung unter anderem angegeben, aber auch Verifikationstechniken
dafür.
Deswegen könnten wir diesen Automaten auch den Harrell-Automaten
nennen.
Genauso wie es den Miele- und den Moore-Automaten gibt, das hier wäre
ein Harrell-Automat.
Im Prinzip sind sie alle äquivalent.
Der Harrell-Automat ist aber in der Praxis sehr viel kürzer
hinzuschreiben.
Gibt es noch Fragen zum Automaten?
Also werden Sie dann in den Übungsaufgaben auch damit traktieren.
Gibt es noch Fragen dazu?
Es gibt übrigens auch Techniken, die sagen, wir mögen keine Epsilon
-Übergänge, also solche, die leer sind.
Wie kann ich Epsilon-Übergänge vermeiden?
Da kann ich auch den Automaten umschreiben, sodass er das Gleiche
akzeptiert, die gleichen Übergänge hat, aber kein Epsilon-Übergang
mehr vorkommt.
Das ist eigentlich auch ganz trivial.
Ich sage mir einfach den Epsilon-Übergang an und sage, woher komme ich
überall her in diesen Epsilon, in den Zustand vor dem Epsilon-Übergang
und die schließe ich einfach alle kurz.
Dann hat man auch wieder mehr Übergänge.
Okay, wenn es keine Fragen mehr gibt, dann machen wir jetzt das letzte
Diagrammchen und dann müssen wir uns darum befassen und was machen wir
mit dem Zeug alles.
Wie komme ich auf diese Diagramme?
Und das ist ja auch Teil Ihres Übungsblattes, wo Sie ein Pflichtenheft
bauen sollen.
So, das letzte ist, wie gesagt, das Paketdiagramm.
Ich zeige Ihnen einfach, wie es aussieht.
Man stelle sich, dass ich lange darüber rede.
Im Paketdiagramm können Sie mehrere Klassen zusammenfassen, sagen, das
ist jetzt ein Subsystem.
Das ist die ganz normale, wieder mal, Hierarchiebildung.
Wir können also sagen, zum Beispiel Übersetzer.
Das schreiben Sie als ein Paket, mit diesem Reiter oben.
Und da sagen Sie, da ist ein Paket drin, das heißt Zerteiler, ein
Paket drin, semantische Analyse, ein Paket drin, Codegenerierung und
ein Paket, abstraktes Syntax bauen.
Dann können Sie noch Benutztrelationen eintragen und das war es.
Natürlich müssen Sie jetzt noch sagen, was dieser Zerteilerpaket
enthält und da geben Sie dann in einen weiteren Paketdiagramm, steht
dann Zerteiler dran und da schreiben Sie rein, welche Klassen, ich
nehme an, dass wir dann kein Subpaket mehr brauchen, sondern nur noch
ein paar Klassen, die schreiben Sie da dran.
Und genauso mit semantischer Analyse und Codegenerierung.
Das wäre zum Beispiel ein Java-Übersetzer.
Sie können es auch so schreiben, in UML gibt es immer Alternativen und
das kommt davon, dass es eben von vier Leuten definiert wurde.
Drei, vier Leuten, die alle zunächst ihre eigenen Diagrammtypen hatten
und sie wissen, wie bei Standardisierung passiert.
Es wird einfach alles genommen, irgendwie zusammengefügt.
Sie können es also auch in dieser Form schreiben.
Sagen Sie, gehört der Übersetzer, besteht aus abstrakter Syntaxbau,
Zerteiler, semantische Analyse, Codegenerierung.
Allerdings können Sie da jetzt die Benutztrelation nicht mehr
einzeichnen, sondern das ist jetzt nur noch die Bestandsherrsche und
klar geht die zu einer beliebigen Tiefe runter.
Und schließlich, wenn Ihnen dieses Paketzeichnen zu blöd ist, können
Sie es auch nur noch textuell machen.
Ein Paket schreiben, Übersetzer, so wie den hier, und hier das so
reinschreiben.
Da müssen Sie also keine Paketchen mehr malen.
Dann kann man allerdings nicht erkennen, ob das jetzt eine einzelne
Klasse ist oder selbst wieder ein Paket.
Wenn ich das angeben will, brauche ich dann doch das da oder das da.
Ach ja, noch etwas, bevor ich da zurückgehe.
Letztes Mal hat mich jemand gefragt, wegen Sichtbarkeit, ob ich bei
Klassen auch angeben kann, ob sie öffentlich sind oder verdeckt.
Kann ich im Klassendiagramm nicht, aber im Paketdiagramm.
Im Paketdiagramm kann ich hergehen und ein Paket oder eine Klasse
markieren als public oder protected oder private.
Wobei das protected wenig Sinn hat, weil ich bei Klassen...
Ja doch, kann ich machen.
Hat durchaus Sinn, auch protected.
Dann gibt es eben nur die Unterklassensichtbarkeit.
Also, wenn Sie fragen, wo sage ich, dass eine Klasse privat ist?
Im Paketdiagramm und nicht im Klassendiagramm.
Okay, das ist schon der Ende der Geschichte.
Gibt es dazu noch Fragen?
Die Umweltspezifikation hatte ich Ihnen gesagt.
Hier ist der Abschnitt, in dem Sie das finden.
Jetzt gehen wir über zu der Frage, wie und jetzt habe ich diese
schönen Diagrammtypen und wie komme ich darauf?
Ich habe jetzt irgendwo ein Problem, ein Lastenheft und soll jetzt die
zugehörigen Umweltklassendiagramme und Zustandsdiagramme und so weiter
schreiben.
Wir werden uns jetzt bis zum Ende der Stunde der Vorlesung jetzt damit
beschäftigen, wie komme ich zu einem Klassendiagramm.
Und die Beschreibung ist so detailliert, ich hoffe, ich langweile Sie
nicht so sehr damit, aber Sie können diese Beschreibung dann hernehmen
und quasi neben sich leben und sie einfach der Reihe nach abhaken, um
die erste Aufgabe im Übungsblatt 3 zu machen.
Okay, da haben wir jetzt ein paar Beispiele.
Das ist also gewissermaßen jetzt, wie programmiere ich Umweltklassen?
Muss man noch sehen, dass ich hier weiterkomme?
Ich mag das irgendwie nicht, wenn ich zu früh komme.
Sie erinnern sich, das Erste, was wir machten, war diese
Planungsphase.
Da kamen wir mit Szenarien, Andrangsfälle raus und dokumentierten ein
Pflichtenheft.
Und da sagten wir, ja gut, wir fragen die Kunden, die Auftraggeber,
wir schauen unsere Forschungsergebnisse intern der Firma an, schauen
uns existierende Systeme an, schauen uns Konkurrenzsysteme an,
studieren den Arbeitsprozess, studieren Formulare, studieren den
Anwendungsbereich, benutzen unser eigenes Wissen, fragen andere Leute,
interviewen sie.
Und damit kommen wir hinter, wie wir das Lastenheft machen.
Und jetzt brauchen wir aber ein Pflichtenheft.
Und jetzt müssen wir eine Objektmodellierung machen.
Und da sind die Klassen gefragt.
Welche Klassen brauche ich?
Welche Assoziationen bestehen?
Welche Attribute werden gebraucht?
Welche Methoden muss ich haben?
Und wie sieht es mit der Vererbung aus?
Und in genau dieser Reihenfolge werden wir vorgehen.
Das heißt also, als erstes machen wir die Klassen und als letztes erst
machen wir die Vererbungsstruktur.
Die Vererbungsstruktur setzen wir hinten an, weil das oftmals einfach
zu einer Verwirrung führt.
Erstmal wollen wir Klassen und Assoziationen herausfinden und dann das
Gruppieren in Hierarchien von Klassen, das können wir zuletzt machen.
Entweder von unten her oder von oben her.
Und dann haben wir das sogenannte Objektmodell, das besteht jetzt aus
Klassen.
Vielleicht zur Illustration auch noch mit Objekten versehen.
Okay, das dynamische Modell, das sind das Aktivitätsdiagramm, parallel
und sequenziell Abläufe beschreiben.
Das Sequenzdiagramm selbst identifiziert, welche Methoden welche
anderen Methoden brauchen und Aufrufe sendet zwischen Objekten und
zeigt uns die Aufrufabläufe.
Und das Zustandsdiagramm, das übrigens nur bei wenigen Klassen
benötigt werden wird, gibt uns ein Genauer an, welche Zustände das
Objekt annehmen kann, was die Übergänge sind.
So, und jetzt müssen wir hergehen und sagen, das machen wir auch in
dieser Reihenfolge.
Erst machen wir das statische Modell, fangen wir mit den Klassen an,
suchen wir die Assoziationen dazu, die Attribute dazu und schließlich
die Vererbung, Methoden auch noch und dann machen wir die dynamischen
Modelle.
Wir werden in der Regel sehr viel weniger dynamische Modelle brauchen
als Klassen.
So, jetzt ist die Frage, ja und, wie finde ich die Klassen jetzt?
Wie finde ich die denn eigentlich?
Da sagen sie, gut, lassen sich eigentlich konkrete Objekte
identifizieren, die wir zu Klassen machen können und denen es mehrere
gibt und dafür wollen sie sie in Klassen beschreiben.
Da sagen sie, und gibt es reale Objekte?
Gibt es reale Objekte in dem System, die ich beschreiben muss, deren
Zustand ich festhalten muss?
Also denken Sie, da hatten wir mal als Beispiel das Toll-Collect
-System.
Im Toll-Collect-System geht es ja darum, die Maut für Schwerlaster
automatisch abzurechnen.
Und welche realen Objekte habe ich denn da drin?
Ja klar, ich habe den Laster, ich brauche also bestimmten Objekt
-Laster und zwar viele davon.
Aha, das muss die Klasse sein.
Und welche anderen echten Objekte gibt es?
Na ja, die Strecken, die gefahren sind.
Ja klar, da brauche ich eine Klasse dafür.
Es gibt viele Strecken, haben unterschiedliche Länge, unterschiedliche
Bemautung.
Es gibt nicht nur die Strecken, es gibt offensichtlich ein ganzes
Streckennetz.
Das muss ich auch irgendwie modellieren.
Also gut, Klasse, her damit.
Und das Streckennetz besteht natürlich aus Strecken.
Aha, da habe ich meine Aggregation.
Sie erinnern sich, die Aggregation mit dieser komischen Raute, da habe
ich schon meine erste Beziehung.
Und nächste Beziehung ist, wo ist der Laster gerade, auf welche
Strecke befährt er?
Schon wieder eine Beziehung.
Also ich schaue mir einfach die realen Objekte an.
Bei kommerziellen Systemen finden Sie sie auch oft, wie auch bei der
Definitionsphase, in Formularen.
Ich habe ein Formularbeispiel für Sie.
Lassen sich Verträge, Formulare in Altsystemen formalisieren?
Ich nehme mal die Verträge her, was steht denn da drin?
Welche Daten werden in diesen Verträgen oder Formularen erfasst?
Ist das vielleicht ein Objekt oder mehrere Objekte, in die ich diese
Informationen gliedern kann?
Und schon habe ich meine Klasse oder Klassen.
Das bezeichnen wir übrigens als Border-Map-Vorgehensweise von unten
her, wo ich sage, was sind die einzelnen Elemente, die ich brauche und
fasse die in Klassen zusammen.
Hier zum Beispiel unser Seminarorganisationsbeispiel.
Sagen wir, Sie hatten vorher ein Papiersystem, in dem Sie
Seminarorganisationen erledigt hatten.
Und da schauen Sie, das Anmeldeformular, also noch in der alten Welt
vor Internet, wird nicht auf dem PC ausgefüllt, sondern auf Papier.
Und da finden Sie, Anmeldung, Teilnehmer zur Nachfolge des Teachware
-Seminars wird angemeldet.
Ein Titel, Vorname, Name, Veranstaltungsnummer, Seminarbezeichnung von
bis.
Da gibt es mehrere davon.
Dann gibt es eine Anmeldebestätigung und Rechnung erbeten an, Titel,
Vorname, Name, Firma, eventuell Straße, Landeskennzahl, Postleitzahl,
Ort, Telefon.
Wie viele Klassen entdecken Sie hier?
Wie viele?
Also ich brauche nur eine Zahl.
Wer ist für eins?
Das ganze Formular.
Wer ist für zwei?
Ober- und Unterteil.
Wie wäre es mit drei?
Drei ist gut.
Gibt es mehr?
Ein paar mehr.
Genau, ich kann es genauso machen.
Ich nehme mal die Lösung mit rein.
Ist klar, ich brauche einen Teilnehmer.
Das ist der hier.
Titel, Vorname, Name.
Ich habe eine Anmeldungsbestätigung, den ich schicken soll.
Rechnungsempfänger oder so etwas kann ich den nennen.
Der hat auch diese Informationen drin.
Das ist meine erste Zeiteklasse.
Und dann brauche ich noch die Veranstaltung, an der er teilnehmen
will.
Die Veranstaltung, die hat natürlich einen Zeitpunkt von bis und eine
Seminarbezeichnung.
Also ist es sehr wahrscheinlich, dass ich auch noch ein Seminar
selbst, ein Seminartyp brauche.
Also komme ich zu diesen drei Dingen und wie gesagt, wahrscheinlich
noch einen vierten.
Da hatten Sie recht, die Seminarbeschreibung selbst.
Und wo kriege ich die Attribute dafür her?
Na ja, da sind sie, Titel, Vornamen, wie sie da drin standen.
Hier drüben, Seminarveranstaltung, Bezeichnung, Beginn, Ende.
Also hier habe ich die Bezeichnung als Zeichenreihe angegeben, aber
ich könnte sie natürlich auch als Seminarveranstaltung angeben.
Eigentlich ganz einfach.
Denken Sie jetzt an Ihre Aufgabe, gehen Sie durch, schauen Sie nach
Klassen, nach Objekten, die drin vorkommen und modulieren Sie einfach
aus Klassen.
Das ist gar nicht schwierig.
Dann gibt es noch eine andere Methode.
Die ist eigentlich für Ihre Hausaufgabe jetzt besser.
Und das ist ein syntaktisches Verfahren.
Nach Abbott heißt es das Nomen-Verb-Analyse.
Oder eine linguistische Analyse nach thematischen Rollen.
Die machen wir aber erst später.
Sie nehmen die Texte her, die Sie haben, zum Beispiel die
Aufgabenbeschreibung und durchforsten Sie nach potenziellen Klassen
und Akteuren, über die man sich etwas merken muss.
Das geht zum Beispiel so, Sie haben einen Satz, der sagt, der Aufzug
schließt seine Türen, bevor er zu einem anderen Stockwerk fährt.
Dann gehe ich her und sage, Aufzug, das ist ein Nomen, das ist die
Wahrscheinlichkeit hoch, dass sich das modulieren muss als Klasse.
Ich habe eine Klasse für das.
Die Tür ist auch ein Nomen, die könnte ich wahrscheinlich auch
brauchen als Klasse.
Da habe ich aber noch etwas dazu zu sagen.
Das Stockwerk brauche ich wahrscheinlich auch, muss ich wahrscheinlich
auch modellieren.
Also habe ich mir schon mal drei Klassen, habe noch keine Attribute
dazu.
Ich kann aber noch etwas ablesen aus diesem einfachen Satz, dass ich
wahrscheinlich eine Methode brauche, die schließen heißt für den
Aufzug.
Aus diesem einfachen Satz habe ich schon so viel herausgeholt.
Die Aufzugstür modelliere ich als Klasse, nur wenn sie eine eigene
Operation besitzt.
Also wenn ich eine Operation habe, die, sagen wir, schließen und
öffnen heißt, in diesem Fall ist es wahrscheinlich naheliegender, die
Methode öffne und schließe Tür in den Aufzug zu versetzen.
Und dann brauche ich die Tür nicht als Objekt.
Sie sehen, es ist nicht automatisch, dass jedes Nomen eine Klasse
wird.
Wenn Operationen von anderen Abgedeckten, wie das Schließen und
Öffnen, dann brauche ich die Klasse nicht.
Und wie gesagt, hier ist nicht mehr viel herauszuholen als das.
Diese Syntaktische Struktur zu analysieren, geht auf einen gewissen
Herrn Abbott zurück und er sagt, wenn ich einen Nomen habe, dann ist
die Wahrscheinlichkeit hoch, dass das eine Klasse wird.
Es kann sein, dass ich sie später nicht brauche.
Und zum Beispiel Auto, Hund, Aufzugstür, Stockwerk und so weiter.
Ich habe einen Namen und das ist wahrscheinlich ein Exemplar von
etwas.
Zum Beispiel, wenn ich den Namen Peter habe oder IBM oder Google oder
so etwas, dann heißt es, das ist ein Exemplar, aber von was?
Was ist das eigentlich?
Naja, das ist eine Firma oder eine Person, also brauche ich eine
Klasse Person dafür.
Ich muss zu dem Exemplar dann wahrscheinlich eine Klasse finden, wenn
ich sie nicht schon modelliert habe.
Ein intransitives Verb.
Intransitives Verb, laufen, schlafen, schließen, öffnen.
Intransitives Verb ohne direktes Subjekt, das wandelt sich um in eine
Botschaft, also eine Methode, Methodenaufruf.
Ein transitives Verb, zum Beispiel etwas essen, jemanden lieben,
jemanden heiraten.
Ein transitives Verb heißt, ich habe ein direktes Subjekt, das Subjekt
und das direkte Objekt könnten in einer Beziehung stehen, nämlich
verheiratet.
Also Unterscheidung dieser Verben und das Verbsein.
Der Laster ist eines der Fahrzeuge, die im Toll-Collect-System
blablabla.
Moment, Laster ist ein Fahrzeug, das heißt Hierarchie.
Das heißt, es gibt eine Beziehung, eine Oberklassen-Hierarchie von
Laster zu Fahrzeug.
Da habe ich schon mal eine Vererbung reingebaut, das ist unser Sein.
Daher ist diese Beziehung, die Oberklassenbeziehung, heißt ja auch
eine Ist-ein-Beziehung.
Das Verb haben.
Der Laster hat sechs Achsen.
Ah ja klar, Aggregation.
Haben oder besteht aus.
Haben, Aggregation, hat ein, das ist eine Aggregation.
Modalverb, Zusicherung, könnte sein, müsste, sollte, immer, jeden Tag.
Das sind Zusicherungen, die kann ich als Bedingungen formulieren.
Das hatten wir jetzt in der UML-Modellierung noch nicht besprochen.
Da gibt es eine spezielle Sprache dazu, die heißt OCL, Object
Constraint Language.
Die würde ich übersetzen in Bedingungen.
Und ein Adjektiv, grüner Laster, das ist wahrscheinlich dann ein
Attribut.
Aber Warnung, nur die Annäherung brauchbar.
Das kann ich so mal so machen, aber ich habe schon Fälle gesehen, wo
Studenten dann in der Prüfung dieses Ding einfach durchgezogen haben,
ohne zu denken.
Also jedes Wort genommen haben und sagt, jedes Nummern wird eine
Klasse.
Und jedes Verb wird entweder eine Methode oder eine Transition, also
eine Assoziation.
Und da kommen oft Modelle raus, die sind total unbrauchbar.
Die sind nämlich nicht reflektiert.
Zum Beispiel gibt es dieses Problem der Nominalisierung, dass Sie ein
Verb eigentlich nominalisieren.
Angenommen, Sie haben folgenden Satz.
Der Laster führt eine Fahrt von A nach B durch.
Er führt eine Fahrt durch.
Eine Fahrt durchführen ist einfach eine Nominalisierung für Pferd.
Und wenn ich das jetzt blind anwende, führt eine Fahrt durch, dann
mache ich eine Klasse Laster oder eine Klasse Pferd.
Das kann vernünftig sein.
In diesem Fall würde ich sagen, nein, das ist keine vernünftige
Modellierung, sondern ich brauche eine Methode, die heißt Pferd.
Und ja, wie kriege ich das raus?
Das geht halt nicht mehr mechanisch, sondern ich muss mir das
überlegen.
Also wenn Sie die Abortion-Methode benutzen, als ersten Ansatz, als
Hausaufgabe gehen Sie einfach durch und sagen, wo sind die Nomen, wo
sind die Verben, die streichen wir alle an und dann wende ich das an.
Vorsicht, führt nicht immer zu einer hundertprozentig guten Lösung.
Aber als erster Ansatz sehr brauchbar.
Fragen dazu?
Also nicht stur durchführen, nicht einfach nur durchziehen.
Mechanisch, da kann ich es auch vom Computer machen lassen.
In der Tat sollte ich darauf verweisen, dass man in der Tat auch
wieder in der aktuellen Forschung versucht, diese Ableitung der
Klassen, die Umwandlung von Texten in UML-Klassen automatisch zu
machen.
Also die ganze Modellierungsarbeit, die wir jetzt lernen, kann zum
Teil schon automatisch ausgeführt werden.
Das haben wir in einem anderen Projekt gezeigt.
Das benutzt aber nicht das Abortion-Verfahren, da haben wir ziemlich
schnell gemerkt, dass das zu viel Mist erzeugt, sondern wir benutzen
das, was ich vorhin erwähnt hatte, diese sogenannte linguistische
Analyse.
Aber dazu kommen wir später.
Da muss man eben inhaltlich mehr einsetzen.
Gut, also aus diesem Abortion-Verfahren kriegen Sie jetzt Vorschläge
für Klassen, Möglichkeiten für Klassen und davon müssen Sie einige
verwerfen.
Wann haben Sie denn eine Klasse vor sich, die Sie nicht brauchen, die
Sie verwerfen können?
Naja, wenn Sie eine Klasse haben, für die finden Sie weder Attribute
noch Methoden.
Keine Operationen dran, keine Attribute dran, dann brauche ich Sie
wahrscheinlich nicht, diese Klasse.
Die Klasse enthält dieselben Attribute, Operationen, Restriktionen,
Aggregationen und so weiter.
Alles andere ist gleich mit einer anderen Klasse.
Dann haben Sie ein Duplikat.
Dann können Sie eines davon verwerfen oder die beiden vereinen.
Wenn Sie, und das hatten wir bereits in dem Aufzugbeispiel, Methoden
haben, die eigentlich einer anderen Klasse zugeordnet werden können,
dann schmeißen Sie die eine Klasse weg.
Wenn Sie eine Klasse haben, die modelliert nur
Implementierungsdetails, die brauche ich zwar später, wenn ich
implementiere, da können durchaus Klassen hinzukommen, aber wenn es
nur um diese Implementierungsdetails geht, wie genau stelle ich jetzt
ein Datum dar?
Das ist auf dieser Ebene wahrscheinlich uninteressant.
Dann lassen Sie die Klasse auch weg.
Haben Sie jetzt eine Klasse, die hat nur ein Attribut und keine
Operationen?
Ich brauche sie einfach nicht.
Dann kann man sich überlegen, ich kann die Klasse nehmen.
Irgendwo muss ich das Zeug ja speichern.
Aber vielleicht kann ich das Attribut dann einer anderen Klasse
zuordnen.
Dann überlege ich mir, ob ich diese Klasse einfach bei einer anderen
unterbringen kann.
Ganz einfache Überlegung.
Da haben Sie also Kandidaten und schauen Sie nach, ob sie überhaupt
sinnvoll sind.
Haben Sie Attribute, haben Sie keine Überlappung mit anderen.
Dann ist natürlich klar und das kennen Sie jetzt schon, Klassennamen
sollten singular sein, aussagefähig sein, sollten die Gesamtheit der
Attribute beschreiben und nicht die Rollen beschreiben, die sie in der
Assoziation vertreten.
Aber das wissen Sie schon.
Wir bilden aber noch keine Vererbungshierarchie.
Na ja, wenn wir sehen, wenn wir etwas Offensichtliches haben, dann
können wir uns das schon merken.
Aber die eigentliche Hierarchisierung verschieben wir auf später.
Es kann durchaus sein, dass Sie eine Klasse haben, für die es nur ein
einziges Objekt gibt.
Das ist völlig okay.
Wenn Sie sich nicht sicher sind, ob Sie Klassen aufspalten sollen und
alles zusammenfassen sollten in eine Klasse, zum Beispiel die Linie,
dann mache ich die als zwei Punkte, also zwei Paaren von Koordinaten,
oder als zwei Punkte und führe eine Klasse Punkte ein.
Im Zweifelsfall ist der Regel immer, machen Sie mehr Klassen in diesem
Fall, aber nur dann, wenn Sie für die Klasse Punkt zum Beispiel auch
eine Operation identifizieren können.
Wenn Sie nur ein Attribut haben, dann ist es eigentlich langweilig.
Im Punkt kann ich natürlich selbstverständlich mehrere Operationen
mehr denken, nämlich zum Beispiel verschieben.
Der wäre ganz gut zu gebrauchen.
Jetzt haben wir also Kandidaten für Klassen.
Wir haben es jetzt sortiert, die Klassenanzahl ein bisschen
verringert, für unnötige Klassen aussortiert.
Der nächste Schritt ist die Assoziationen, genau wie in der Vorlesung,
wo wir über Klassendiagramme gesprochen haben.
Jetzt müssen wir die Assoziationen definieren und da frage ich mich,
gibt es dauerhafte Beziehungen zwischen einzelnen Objekten?
Dann merke ich mir die als Assoziationen.
Sind die Assoziationen auch problemrelevant, brauche ich sie?
Natürlich merke ich mir nur solche, die ich gebrauchen kann.
Und existieren diese Beziehungen auch unabhängig von anderen Klassen?
Wenn sie unabhängig von anderen Klassen sind, dann merke ich mir das.
Wenn nicht, wenn noch andere Objekte eine Beziehung reinspielen, dann
muss ich mir überlegen, ob es eine ternäre Assoziation wird oder ob
ich Assoziationsattribute brauche.
Diese Überlegungen mache ich mir dann.
Und wie finde ich die jetzt?
Wie komme ich denn auf gute Assoziationen?
Das sind ein paar Hinweise, ähnlich wie beim abortischen Verfahren.
Gibt es irgendwie eine räumliche Nähe?
Gibt es räumliche Beziehungen?
Wohnt in, liegt in, gehört zu einem geografischen oder sonstigen Ding?
Gibt es Aktionen?
Kommunikationen?
Redet mit, besitzt, hat?
Das sind die Aggregationen.
Andere Beziehungen wie verheiratet, wohnt in, räumliche Nähe, fährt
von wo nach wo?
Es gibt Assoziationen, die ich brauche.
Sind die beteiligten Klassen gleichrangig, das heißt auf der gleichen
Stufe, dann ist es eine normale Assoziation, wenn es eine Überordnung
gibt.
Zum Beispiel, dieser Raum besteht aus Bänken und eine Bank besteht aus
Sitzfläche und Schreibfläche und Rückenlehnen usw.
Da habe ich eine Ober-Unterbeziehung, das heißt, dann habe ich eine
Aggregation.
Wenn ich mir nicht sicher bin, dann nehme ich halt die Assoziationen.
Würden Sie bitte draußen bleiben.
Gehen Sie raus, sofort.
Ich habe Vorlesung.
Gratulation zu Ihrer Dissertation übrigens.
Großartig.
Machen wir weiter.
Genau das wollte ich verhindern.
So, wo bin ich jetzt?
Gut, dann ist klar, ist die Assoziation so, dass ich sie von zwei
Seiten traversieren muss, dann machen wir das so.
Es darf durchaus mehrere Assoziationen zwischen den gleichen Klassen
geben, wenn Sie unterschiedliche Rollen machen.
Zum Beispiel, ich habe eine Bestellung.
Die Bestellung muss an eine Adresse geschickt werden, das wäre die
Versandadresse oder die Rechnungsadresse.
Sie können sich was schicken lassen und die Rechnung Ihren Eltern
schicken.
Genau, und da gebe ich eben das mit diesen Rollen an.
Die Rollenbezeichnung hatten wir auch schon im Klassendiagramm
gesehen.
Okay, Rollennamen gebe ich an, vor allen Dingen, wenn die Rollen
benötigt sind, wenn ich mehrere dieser Assoziationen habe, damit ich
sie unterscheiden kann.
Es reicht also nicht, hier zwei Linien zu zeichnen und dann es zu
belassen.
Dann muss ich auch sagen, was ist denn die Rollenbeziehung hierbei.
Das ist alles erledigt.
Eine Klasse kann natürlich auch in anderen Beziehungen andere Rollen
spielen.
Diese Adresse könnte nicht die Versandadresse sein, sondern ein
Wohnort sein oder Zweitwohnsitz oder so etwas.
Das ist natürlich legal.
Der Rollennamen spezifiziert das also genauer.
So, haben wir die Assoziationen, ist die nächste Frage und was sind
die Kardinalitäten?
Gibt es eine Muss-Beziehung, eine Eins-Beziehung gewissermaßen?
Wenn ich A habe, brauche ich immer ein B.
Dann schreibt man das natürlich als Kardinalität als Eins in diesem
Falle.
Können natürlich auch mehrere sein, kann optional sein, Null oder
Eins, Null oder Viele.
Dann weiß ich schon, wie ich die Kardinalitäten eintragen muss.
Ist aber einfach.
In unserem Fall, wenn Sie sich erinnern, eine Seminarorganisation, da
hieß es, das Pflichtnetz sagt, Ersterfassung, Änderung und Löschung
von Dozenten sowie Zuordnungen zu Seminarveranstaltungen und
Seminartypen.
Also, wir haben erstmal die drei Klassen, Seminarveranstaltung,
Dozent, Seminartyp.
Was sind die Kardinalitäten?
Und die Beziehung ist natürlich, der Dozent kann, hält eine
Seminarveranstaltung, also zum Beispiel die hier, Softwaretechnik 1
halte ich gerade, das ist die Veranstaltung, aber das Seminartyp ist
Softwaretechnik 1, die gibt es jedes Jahr und die kann auch mal von
jemand anderem gehalten werden.
Also, wieder als Beispiel, in der Seminarveranstaltung kann ein Dozent
folgende Rollen einnehmen, er kann der Referent sein, er kann sie also
tatsächlich halten, so wie ich jetzt gerade, oder er ist der
Seminarleiter, das heißt, jemand anderer hält ihn, aber er ist dafür
verantwortlich, dass er einen Referenten findet.
Also gibt es hier zwei mögliche Beziehungen, wo der Dozent entweder
Referent oder Seminarleiter oder beides ist.
Um diese Assoziationen mit einer Rolle zu versehen, wenn ich das will,
kann ich sie auch so beschreiben, nämlich kann fachlich abhalten bei
dem Dozenten.
Das war also dieses Ende von der vorigen Folie.
Das sieht also dann so aus, das ist Seminarveranstaltung, Dozent,
Seminartyp und Dozent, kann fachlich abhalten, Referent, Seminarleiter
und hier sind die Kardinalitäten, da kann ich jetzt weitergehen.
Enger semantischer Zusammenhang, Sie erinnern sich.
Die Bestehtausbeziehung kann ich auf zweierlei Arten modellieren, mit
der offenen Raute und der geschlossenen Raute.
Wenn der Bezug auf die Teilobjekte ausschließlich über die
Aggregatobjekte erfolgt, dann liegt eindeutig eine Aggregation vor,
das heißt also eine Beziehung, die sagt, die Teile verschwinden mit
dem Ganzen.
Andernfalls besteht aus, ist Teil von, ein Hinweis auf
Aggregationsbeziehung.
Damit wären wir also schon durch mit den Assoziationen.
Ich sagte Ihnen ja, das können Sie neben Ihre Aufgabenblatt legen und
einfach der Reihe nach abarbeiten.
Das ist eine Art Checkliste.
Ich hatte in der vorigen Präsentation am Schluss ja auch eine UML mit
Checklisten hieß da ein Buch, das geht so.
Vor ist natürlich ausführlicher, wenn Sie wollen, können Sie sich da
mehr Anregungen holen, aber im Wesentlichen ist es so.
Attributkandidaten, wie finde ich jetzt die?
Wir hatten auch noch keine Methoden, nur Klassenbeziehungen.
Finde ich wieder Dokumentanalyse, Formulare nach realen Eigenschaften
identifizieren, dann finde ich meine Attribute.
Dann muss ich mich fragen, ich finde meistens mehrere Attribute, als
ich brauche.
Ist das bei Attributproblemen relevant?
Muss ich es wirklich aufbewahren?
Kann es jemals an der Benutzerschnittstelle erscheinen?
Wir erinnern uns, wir schreiben immer noch das System aus Sicht des
Benutzers, aber jetzt so vollständig, dass es implementiert werden
kann.
Wenn ein Attribut irgendwo ein Schlüssel ist, den ein Benutzer nie
sehen will, dann lasse ich das weg an dieser Ebene der Modellierung.
Gehört jetzt das Attribut zur Klasse oder zur Assoziation?
Ja klar, dann muss ich es eben an der Assoziationsklasse unterbringen.
Wenn ich es nicht zuordnen kann, dann spricht viel dafür, dass ich
irgendwo eine Klasse vergesse.
Okay, natürlich, Attributnamen kennen Sie schon aus der Java,
Programmierung sollte aussagekräftig sein, der Typ sollte bedacht
gewählt werden, zum Beispiel bei der Telefonnummer.
Nehme ich das jetzt als Ganzzahl, ist diese ganz genug?
Was ist, wenn ich spezielle Zeichenketten nehme, wie rufe ich mich an?
Also ist es wohl besser, wenn ich Zeichenketten nehme, dass ich auch
Buchstaben unterbringen kann, wenn Leute sie so speichern wollen.
Klassenattribute ist klar.
Gehört dieses Attribut, ist das Attribut das gleiche, mit dem gleichen
Wert, für alle Objekte, für alle Instanzen, dann gehört es in die
Klasse?
Oder sagt es etwas aus über alle Objekte, zum Beispiel Anzahl der
Konten?
Ich habe eine Klasse Konto und da gibt es viele Instanzen, aber ich
würde sie gerne zählen, permanent wissen, wie viele Konten ich
vergeben habe, dann gehört dieses Attribut Anzahlkonten natürlich in
die Klasse und nicht in die einzelnen Kontenobjekte.
Aber auch diese Überlegung ist Ihnen vertraut und Programmieren her.
Es gibt auch Gründe, warum ich ein Attribut nicht brauche, wenn es nur
zum Identifizieren des Objektes dient, denn jedes Objekt hat bereits
seine eigene Identität.
Ich brauche es also nicht, eine andere Klasse zu referenzieren, da
nehme ich eine Assoziation her, dieses Attribut muss dann
verschwinden, das war eines der Beispiele, die wir hatten, Entwurfs-
oder Implementierungsdetail brauche ich auch nicht, kann aus anderen
Attributen abgeleitet werden, dann kann ich mir überlegen, ob ich es
auch bewahre oder ein anderes streiche.
Also zum Beispiel speichere ich besser das Geburtsdatum oder das Alter
ab.
Und wenn Sie das Alter abspeichern, ist klar, dann haben Sie immer das
Problem, dass Sie jedes Mal, an jedem Tag durch alle Ihre Objekte
durchgehen müssen und sagen, hat einer heute Geburtstag gehabt, ist
sein Alter gerade um eins höher geworden.
Geschickter ist es, das Geburtsdatum zu speichern und das Alter zu
berechnen, mit der Hilfe einer Methode, die heißt dann, gib Alter oder
so etwas.
Und schon ist das Problem vermieden.
Wenn Sie nicht sicher sind, ob Sie ein Attribut oder eine Klasse
haben, dann im Zweifelsfall eine neue Klasse hernehmen.
In diesem Fall etwas in die Klassen nehmen.
Wenn Sie Sachen haben wie, ich habe eine Reihe von Attributen, die
zusammenhängen und dann gibt es noch extra Attribute, die mit diesem
Zusammenhang weniger zu tun haben, dann deutet vieles darauf hin, dass
Sie zwei Klassen brauchen und eine Assoziation dazwischen.
Also zum Beispiel, wenn ich eine Klasse habe, in der stehen Name,
Vorname, Adresse, Geburtsdatum oder so etwas drin und dann anderes
Zeug wie zum Beispiel, hat sich für folgendes Seminar registriert.
Dann scheint es mir eher so zu sein, die ersten drei, vier mit den
Adressen und Namen haben stärkeren Zusammenhalt als der Rest.
Also gliedere ich den Rest aus in Teilnahmen, ein Teilnahmeobjekt und
baue mir eine Assoziation zwischen den beiden.
Wir haben noch eine Minute.
Vererbungsprinzip anwenden.
Das Vererbungsprinzip anwenden heißt, ich mache B erst zu einer
Unterklasse von A, wenn ich in allen Zuständen ein Exemplar von B auch
als ein Exemplar von A bezeichnen könnte.
Das haben wir letztes Mal ausführlich besprochen, das
Substitutionsprinzip also gegeben ist.
Nur dann mache ich mir wirklich eine Unterklasse.
Ich habe nur noch ein paar Sachen zu sagen, dann sind wir mit der
Vererbung fertig und den Rest, glaube ich, können Sie selbst
studieren.
Sie können Oberklassen aber auch anders bilden.
Sie müssen sie jetzt finden.
Manchmal ist es ganz klar, wie zum Beispiel Fahrzeuglaster.
In anderen Fällen müssen Sie sie erst bilden und das bilden Sie dann,
wenn Sie Klassen finden, die viele gemeinsame Attribute haben, aber
noch ein paar extra.
Jeder hat ein anderes extra.
Dann können Sie hergehen und die gemeinsamen Attribute herausziehen,
eine Oberklasse davon bilden und dann die Unterklassen mit den extra
Attributen bilden, die dann hoffentlich für jede Unterklasse anders
sind, andere Kombinationen.
Sie können auch umgekehrt vorgehen.
Sie können Klassen, die sehr viele Attribute oder Operationen
besitzen, versuchen aufzuspalten in spezialisiertere Klassen.
Und dann die Ist-Einbeziehung überprüfen.
Sie selbst lesen, keine Vererbung liegt vor, wenn Sie zwei
Unterklassen haben, aber Sie besitzen keine zusätzlichen Operationen,
dann können Sie eine davon oder beide davon sich sparen.
Und keine Operation ist überschrieben.
Oder aber die Superklassen, Subklassen 1 und 2 bezeichnen nur
verschiedene Typen der Klasse Super.
Dann kann es sein, dass Sie nur die Klasse Super brauchen, mit einer
Attributvariable, die sagt, ich bin von der Typ oder von dem Typ.
Wenn es sonst keine zusätzlichen Methoden, andere überschriebene
Methoden oder Attribute gibt, dann machen Sie keine Unterklasse davon.
Das ist also auch oftmals die Frage.
Ich brauche nur zwei unterschiedliche Arten von Unterklassen, aber Sie
haben keine eigenen Operationen, keine eigenen Attribute, dann
wegschmeißen und Enumeration einführen und ein Attribut, das das
klärt.
So, dann machen wir für heute Schluss.
Viel Erfolg bei der Hausaufgabe.