Herzlich Willkommen zur heutigen Übung Softwaretechnik 1.
Endlich auch mal wieder mit mir und Professor Tisch ist übrigens auch
wieder da.
Alle heil wieder im Land und so.
Allerdings müsst ihr vielleicht mit mir ein bisschen Rücksicht nehmen
heute.
Ich bin gestern früh erst gelandet, bisschen Jetlag noch, aber kriegen
wir schon hin.
Ist eigentlich mitten in der Nacht für mich, aber was man halt so als
Informatiker macht um die Uhrzeit.
Genau, wir fangen heute an mit mal wieder einen kleinen Risk to the
Public, eine kleine Softwarepanne.
Diesmal sogar noch ein bisschen, ja vielleicht noch schlimmer als die
letzten, die wir uns angeschaut haben.
Es geht um diesen kleinen Hubschrauber hier unten oder
Senkrechtstarter wohl eher.
Naja, der fliegt da ganz nett von dem Flugzeugträger runter, aber wenn
man hier schon sieht, naja, das ist schon die Kante des
Flugzeugträgers.
Er schwebt irgendwie über dem Meer.
Wenn man sich das Bild anschaut, ich glaube, da wollte er nicht hin.
War nicht ganz so geplant.
Was da jetzt passiert ist, in diesem Fall ist, dass die zwei Piloten
mit dem Ding gestartet sind, obwohl sich das Ganze im Maintenance-Mode
befand.
Naja, der Maintenance-Mode war an der Stelle eingeschaltet worden,
weil sie eine Software-Update bekommen haben für diesen Hubschrauber.
Das Problem war, es war für die Piloten nicht zu erkennen, welchen
Modus sich das System befand an der Stelle.
Das Einzige, was die beiden Piloten festgestellt haben, ist, dass
nachdem sie den Motor gestartet haben, dass der für 15 Sekunden kurz
gestockt hat und dann einfach wieder ganz normal lief und alles sah so
aus wie sonst.
Das war alles, was sich für die beiden geändert hat.
Außer dass noch eine, ich glaube, es war noch die Option des Exhaust
-Deflektors, der anstatt auf Auto, wie er normalerweise steht, das
haben sie in ihr Protokoll geschrieben.
Aber ansonsten war das Flugzeug genauso, wie sie es normalerweise
gecheckt hätten.
Das Problem ist, wenn man mit diesem Helikopter oder Säcke-Starter
oder Flugzeug, Richtung daraus, was auch immer, im Maintenance-Mode,
also im Wartungs-Mode fliegt, hat er 20 Prozent reduzierte Schubkraft,
was dazu geführt hat, dass das Flugzeug dann abgestürzt ist.
Traurigerweise ist dabei tatsächlich auch einer von den beiden Piloten
ums Leben gekommen.
Das heißt, so ein bisschen, was man hier sehen kann, man muss
aufpassen, wie man solche Geschichten darstellt, gerade in
sicherheitskritischen Bereichen.
Nämlich, sie dachten eigentlich, dass der Austausch von On- und Auto
-Software -Update, naja, aus diesem Software-Update resultiert ist,
wovon die beiden Piloten keine konkrete Information hatten, was da
tatsächlich passiert ist.
Das heißt, so ein bisschen, was man hier jetzt rausziehen kann aus
dieser Panne ist, naja, man sollte immer wissen, in welchem Zustand
sich das System befindet, mit dem man gerade interagiert.
Man sollte aber vor allen Dingen auch als Software-Entwickler eine
Möglichkeit einvorsehen, dass die Leute wissen, wo sich die Systeme,
mit denen sie arbeiten, befinden.
Vor allen Dingen auch, vielleicht nicht unbedingt irgendwelche
Probleme, die aus Software-Updates entstehen, einfach verharmlost.
Das vorneweg zu unserem kleinen Risk to the Public.
Und Martin macht jetzt weiter mit der Übung.
Genau, auch von mir nochmal Hallo.
Ich muss das Mikro ein bisschen weg machen.
Du hast wunderbar den Foliensatz, sehr schön.
Gut, ich fange auch einfach gleich an.
Sie sollten in Aufgabe 1 eine Einschub-Architektur machen.
Also Sie sollten dieses wunderbare JMJ-RST, das ja qualitativ sehr
hochwertig ist, dazu bringen, mit gewissen Erweiterungen, dass Sie
eigene Plugins, eigene Einschübe dran machen können.
Warum wir Ihnen das aufs Auge gedrückt haben?
Wir wollten, dass Sie sehen, dass auch bei solcher Software, die
vielleicht nicht so ganz den Qualitätsstandards von manchen Firmen
genügt, dass man das trotzdem so machen kann, dass man relativ leicht
so eine Software doch noch erweiterungsfähig machen kann durch solche
Einschübe.
Wir hatten Ihnen gesagt, Sie müssen sich da ein bisschen einlesen in
diese Service Loader API von Java, hatten Ihnen dann einen Link dazu
gegeben und hatten Ihnen dann auch eine Vorlage in Elias
bereitgestellt, die Sie verwenden sollten.
Zunächst sollten Sie eben diese Architektur dahin kriegen, dass
überhaupt solche Plugins geladen werden können.
Das heißt, so ein Service Loader soll einfach mal schauen, was gibt es
denn alles für Plugins für JMJ-RST und soll die dann in der Liste
sammeln.
Und später hatten Sie auch die Aufgabenstellung, dass Sie alle
sortieren sollen.
Das eigentliche Sortieren sehen Sie auf der nächsten Folie.
Das, was Sie hier sehen, das ist das, was Sie mehr oder weniger aus
diesem Link, den wir Ihnen zur Verfügung gestellt haben, herausziehen
konnten.
Also da war beschrieben, wie Sie diesen Service Loader einsetzen.
Im Endeffekt diese Load-Methode und dann können Sie sagen, was für
eine Art von Plugins Sie suchen.
Sie suchen jetzt quasi alle Plugins, die von dieser Plugin für JMJ-RST
Klasse, abstrakte Klasse war es glaube ich, erben und dann können Sie
die halt eben, in dem Fall würden wir das jetzt in die Liste rein
sammeln, also in diese Plugin-Liste.
Dann können Sie damit irgendwas machen.
Sie können Sie das Menü hinzufügen oder in unserem Fall jetzt erstmal
in irgendeiner Form sortieren oder was auch immer Sie machen möchten.
Das Sortieren an sich, dieses Jahr sollten Sie das sortieren nach der
Länge der Namen.
Das heißt, Sie sollten hier diese, am besten diese Comparable
-Schnittstelle implementieren.
Die zwingt Sie dann dazu, diese Compare-To-Methode zu überschreiben,
in der Sie dann eben sagen, wie so eine Sortierung auszusehen hat.
Wie Sie sehen, wir benutzen hier die Compare-Methode, die die Klasse
Integer schon mitbringt.
Es sortiert einfach zwei Integer aufsteigend.
Wir nehmen hier diesen GetSimpleName, das ist der Name der Klasse,
also der übergeben wird, und nehmen davon die Länge.
Das heißt, die Länge von diesem Namen, von diesem simplen Namen und
vergleichen Sie eben mit dem anderen Namen.
Und dann kommt halt irgendwie was raus mit minus 1, 0 oder 1, je
nachdem, ob das halt kürzer ist, länger oder ob es halt gleich lang
ist.
Das war die eigentliche Sortierung, die Sie machen sollten.
Dann sollten Sie noch den Konstruktor von Menü anpassen, also Sie
sollten irgendwie das Ganze noch hinzufügen in das Menü von JMJ-RST,
diese ganzen Plugins.
Wie kann das aussehen?
Na ja, Sie müssen erst mal zwei Menüs anlegen, eins eben für die
Konfiguration und eins zum Starten.
Wir holen uns den String, also den Namen von dem Menü, irgendwie aus
diesem Endpunkt Messenger, das haben wir dort hinterlegt.
Das können Sie natürlich anders machen, Sie können auch hier fest den
Namen rein codieren, wenn Sie das möchten.
Da haben wir zwei Menüs angelegt.
In diesen Menüs müssen wir dann eben alle gefundenen Plugins
hinzufügen.
Das sehen Sie dann auf der nächsten Seite, diese Create-Plugin-Menü
-Methode.
Wenn wir das gemacht haben, müssen wir das eben noch an dieses Option
-Menü dran klatschen.
Das steht hier in der Aufgabenbeschreibung, also unter Optionen
möchten Sie eben die ganzen Plugins, die es gibt, konfigurieren können
bzw.
aufrufen können.
Genau, wir hatten noch gefordert, dass Sie noch solche Trenner
hinmachen, oben und unten.
Das sind hier diese Add-Separator, die eben einmal oben und unten
drankommen.
Gut, wie sieht es eigentlich erweitern von diesem Menü aus?
Sie müssen in irgendeiner Form über alle Plugins, die Sie gefunden
haben, drüber iterieren, die ganzen Plugins initialisieren und dann
eben als einzelne Menüeinträge... Bin ich jetzt irgendwie komplett
weg?
Jetzt bin ich wieder da.
Dann wird es jetzt ein bisschen lauter und ich spreche leiser.
Gut, also wie funktioniert das?
Naja, man muss so ein neues Menü-Item machen für jedes Plugin, das man
findet.
Idealerweise nimmt man natürlich den Namen des Plugins.
Dann muss man noch sagen, was passieren soll, wenn jemand auf diesen
Menü -Eintrag draufklickt.
Das können Sie entweder in dieser schönen Variante machen, also Sie
müssen diesen ActionListener definieren und Sie können sagen, okay,
wenn jemand draufklickt, also wenn so eine Aktion ausgeführt werden
soll, dann soll eben die Run-Methode des Plugins aufgerufen werden.
Das hier ist eine schöne Variante, wie man das machen kann.
Sie können es natürlich aber auch, also das kann man erst seit Java 8
machen, Sie können es natürlich aber auch ohne diesen Lambda-Ausdruck
machen.
Sie können auch schreiben, so mit einer anonymen Klasse,
AddActionListener, NewActionListener und dann hier drin so eine
anonyme Methode machen, in der Sie halt die eine Methode, die es da
zur Verfügung gibt, überschreiben oder halt eben so.
Also Sie müssen die ActionPerformed-Methode überschreiben, die eben in
so einem ActionListener zur Verfügung gestellt wird und in die würden
Sie jetzt auch dieses Run reinschreiben.
Das ist jetzt einfach nur eine kürzere Schreibform, die Sie wählen
können.
Wie Sie es gemacht haben, ist aber letztendlich egal.
Also hier machen Sie den Menü-Eintrag, eben wenn jemand dieses Plugin
ausführen möchte.
Dann hatten wir noch gesagt, es muss auch konfigurierbar sein, aber
nicht jedes Plugin ist vielleicht konfigurierbar.
Das heißt, Sie können hier zum Beispiel nachschauen, ist es
konfigurierbar?
Wenn nicht, naja, dann continue, also dann spring weiter zum nächsten
Plugin, dann bin ich ja an dieser Stelle fertig.
Oder Sie können sagen, naja, wenn es konfigurierbar ist, dann mache
ich halt eben auch noch so ein Konfigurations-Menü-Eintrag und wenn
ich dort halt auf den Knopf drücke, dann wird halt eben die Configure
-Methode des Plugins aufgerufen und nicht die Run-Methode.
Haben Sie bis hierher Fragen zum Plugin?
Ja, bitte.
Das E, das ist der, lassen Sie mich kurz spicken, bei der Action
-Performed -Methode, die Sie da in Kurzvariante definieren möchten, da
gibt es so einen Action-Event-E, der mit übergeben gibt.
Den würden Sie hier nehmen.
Also dieser Add-Action-Listener hat eine anonyme, also die anonyme
Klasse dieses Action-Listeners hat eine Methode, die Sie überschreiben
müssen, das ist die Public-Void-Action-Performed und die hat einen
Parameter namens Action-Event-E.
Wenn Sie den haben möchten, dann können Sie das so schreiben.
Wenn Sie den aber nicht benutzen, können Sie jetzt auch nur Klammer
auf Klammer zunehmen.
Also wir benutzen das E nicht, das könnte man sich hier auch sparen an
dieser Stelle.
Okay, genau.
Sonst noch Fragen bis hierher?
Bringe ich einfach weiter.
Gut, der Name wäre hier Instagram, von der zweiten Aufgabe
beispielsweise.
Plugin zum Menü hinzufügen und alles andere habe ich schon gesagt.
Das hier stand glaube ich nicht auf der Aufgabenbeschreibung, das
mussten Sie auch nicht machen, nur damit es hübsch ist.
Was ist, wenn es keine Plugins gibt oder wenn es nichts zu
konfigurieren gibt?
Das würde einfach nur dafür sorgen, dass wir hier trotzdem eine schöne
Ausgabe hätten.
Das würde hier dafür sorgen, dass der Menü Eintrag ausgegraut oder
deaktiviert wäre, also Sie können es nicht anklicken.
Das gleiche auch für die Konfiguration.
Auch da, wenn es keinen Eintrag gibt, dann könnte man auch hier
irgendwie sagen, kein Eintrag vorhanden und das Ganze ausgrauen.
Aber das ist nur eine Variante, wie Sie das hübsch machen könnten,
wenn Sie wollten.
Gefordert hatten wir das dieses Jahr nicht.
Hoffe ich.
Du widersprichst mir, wenn ich was Falsches sage.
Aber das steht auch, war nicht gefordert.
Gut, das war die Aufgabe 1, die Vorbereitung der Architektur für
Einschübe.
Haben Sie noch Fragen?
Zu meiner letzten Frage, ob Sie Fragen haben, ist noch nicht viel
passiert.
Wunderbar, dann wird jetzt Aufgabe 2 machen.
Hier sollten Sie mal einen konkreten Einschub, ein konkretes Plugin
machen, das dann solche Freitext-Kommentare erzeugt, die IMAGE mehr
oder weniger subtil loben sollen.
Und Sie sollten dazu eben diese Architektur aus Aufgabe 1 verwenden.
Sie sollten ein neues Modul namens Instagram-Plugin erstellen und dann
dort die abstrakte Klasse IMAGE-Plugin for JMJ-RST beerben, die
nötigen Methoden implementieren.
Wir hatten Ihnen hier in Aufgabe F noch gesagt, dass Sie hier dieses
Meta -Inf verwenden können.
Also können Ihre Implementierungen wie folgt aussehen.
Was macht jetzt hier diese Annotation Meta-Inf-Services?
Die sorgt einfach nur dafür, dass eine Textdatei erzeugt wird, in der
reingeschrieben wird, was es für Plugins gibt, die eben diese Plugin
for JMJ-RST-Schnittstelle, beziehungsweise in dem Fall abstrakte
Klasse, implementieren.
Also das ist einfach nur so eine Textdatei, in der steht halt drin,
was es für Plugins gibt und diese Plugins können dann eben geladen
werden.
In unserem Fall wäre das jetzt eben dieses Plugin, was Sie gerade
schreiben.
Und es sorgt halt dafür, dass es sagt, ja, ich bin ein Plugin von eben
genau diesem Plugin for JMJ-RST.
Ansonsten müssen Sie dann, wenn Sie hier die Plugin for JMJ-RST
abstrakte Klasse beerben, dann sind Sie gezwungen, ein paar Methoden
zu überschreiben.
Unter anderem die getName-und-is-configurable-Methode.
Na ja, guten Namen müssen Sie irgendwie setzen.
Das Ding nennt sich dann Instagram und in dem Fall ist es
konfigurierbar.
Da müssen Sie auch den Bullshit-Wert setzen.
Wanderwitz natürlich hier bei den anderen Methoden.
Wir brauchen irgendwo diese Kommentare, die gelesen werden sollen und
ausgespuckt werden sollen.
Wir haben uns hier dafür entschieden, dass wir das einfach in so eine
Liste von Strings reinmachen.
Natürlich können Sie das auch in eine andere Datei auslagern, zum
Beispiel so eine Properties-Datei, in der Sie dann die Kommentare
zeilenweise einlesen.
Das wäre natürlich schöner.
Das ist jetzt hier nur wegen der Darstellung haben wir es so gewählt.
Kennt jemand dieses ListOf?
Einer, zwei?
Also hier oben diese Variante ListOf.
Gibt es auch noch nicht so lange in Java, seit Java 8 um genau zu
sein.
Das erzeugt einfach so eine Immutable List, also eine Liste, die nicht
geändert werden kann, wenn sie erzeugt wurde.
Einfach eine schönere Variante, als wenn man erst irgendwie ein Array
erzeugt und diesen Array dann in eine Liste konvertieren will.
So kann man halt relativ schön eine Liste machen und gleich solche
Werte mitgeben.
Aber müssen Sie natürlich nicht so machen.
Gut, also hier hätten wir jetzt diese Auswahl von Kommentaren, die wir
anzeigen möchten und die möchten wir zufällig ausgeben.
Wie kann das zufällig ausgeben funktionieren?
Na ja gut, man könnte hier irgendwie so einen Zufallsgenerator machen,
der eben aus diesen Kommentaren, die wir da drin haben, zufällig einen
zieht und den dann ausgibt.
Konfigurierbar soll das Ganze auch sein.
Wir hatten gesagt, dass ein spezieller Satz ausgegeben werden sollte.
Das stimmt gar nicht.
Es sollen erstmal alle Kommentare ausgegeben werden.
Dazu noch diesen Satz hier.
Das Ausgeben von allen Kommentaren, da können Sie auch, wenn Sie
möchten, einmal über diese Liste drüber iterieren und einfach jeden
Wert ausspucken.
Komma getrennt zum Beispiel.
Ne, stimmt gar nicht, es war nicht Komma getrennt.
Wir haben gefordert, dass es teilenweise gemacht wird.
Oder Sie nehmen hier diese wunderbare Variante mit String.join.
Da können Sie sagen, ok, nehmen jeden Wert aus diesem Array raus und
verbinde die einzelnen Werte eben mit diesem backslash n.
Also sprich, nehmen jeden Wert und macht diesen Zeilenumbruch.
Das kommt beim init.
Also die Frage war, ob nicht auf der Standardfehlerausgabe was
ausgegeben werden sollte.
Das ist in der anderen Teilaufgabe.
Das ist der init-Teil.
Der Configure-Teil ist Aufgabe D.
Genau, also andere Aufgabe.
Sonst Fragen zu dieser Folie?
Ja.
Der Satz soll im Konfigurierfenster nicht auftauchen.
Lassen Sie mich kurz nachgucken, bevor ich etwas Falsches behaupte.
Also es sollen alle vorhandenen Freitextkommentare aufgelistet werden.
Sorgen Sie dafür, dass die Kommentare teilweise angezeigt werden.
Also Sie meinen, der untere Satz sollte dort nicht kommen?
Das ist richtig, oder?
Ja.
Ich weiß auch nicht, warum der da ist.
Sehr gut aufgepasst.
Sie haben recht, der hat da eigentlich nichts zu suchen, der Satz.
Gut.
Aber die Kommentare sollten ausgegeben werden und das passt.
Naja, daneben.
Ist das der Titel vom Dialog?
Ja, wunderbar.
Ja, dann ist ja okay, dann ist es ja hier mit Komma getrennt, dann
gehört es zu diesem ShowMessageDialog.
Okay, Dankeschön.
Dann ist es doch nicht so falsch, dann ist es einfach nur die
Überschrift in diesem Fenster, was wir hier mit
JOptionPaneShowMessageDialog aufmachen.
Da ist das hier der Inhalt und das hier die Überschrift.
Puh, Glück gehabt.
Sehr gut aufgepasst und mich gut gerettet, merkt ihr den mal.
Gut, was haben wir hier noch?
Das war die Einblendung dazu für Ihren Ausdruck.
Hier ist der Teil, den Ihr Kommilitone angesprochen hatte.
Soll da nicht irgendwie was noch ausgegeben werden auf diesem Error
-Kanal, SystemError?
Ja, das sollte aber hier in dieser init-Methode passieren.
Da hatten Sie diesen Satz vorgegeben und dann sollten Sie auch immer
noch den aktuellen Benutzernamen machen.
Mit ein bisschen googeln, bingen, duckduckgoen bekommt man heraus,
dass es mit System.GetProperty.User.Name machbar ist.
Gut, dann wäre ich auch schon durch mit Aufgabe 2.
Gab es da irgendwelche Schwierigkeiten oder haben Sie noch Fragen zur
Aufgabe 2?
Vielleicht mal eine kurze Frage.
Wer hat denn alles die Aufgaben, Programmieraufgaben bearbeitet?
Okay, das sind sehr viele.
Wunderbar, sehr schön.
Wer fand die Aufgabe zu schwierig?
Also jetzt nur die Programmieraufgabe.
Wenig, dann rechnen wir noch die drauf, die sich nicht trauen, sich zu
melden.
Aber das geht dann, glaube ich, trotzdem.
Ich rede es mir zumindest ein.
Gut, wenn Sie so weit gekommen sind, dann können Sie ja schön Aufgabe
3 machen.
Da sollten Sie das Ganze bündeln.
Das heißt, Sie sollten eben nicht nur... oder Sie sollten eben alle
Module zusammenschnüren und ausführbar machen.
Also wenn Sie das eben ohne so ein Bundle machen, dann ist das Ganze
nicht ausführbar, weil dieses Hauptprojekt nicht ausführbar ist.
Das macht einfach so eine Packaging-Prom und es kann halt nicht
gestartet werden.
Wenn Sie diese Module als Abhängigkeit machen würden, dann können die
Abhängigkeiten auf JMJ-RST haben und zirkuläre Abhängigkeiten haben.
Das möchten Sie nicht.
Das hier sind schon die ersten Punkte, die Sie bei dieser Aufgabe
bekommen konnten.
Oder der erste halbe Punkt zumindest, ich bin mir nicht sicher.
Ich denke, das war jetzt nicht so ganz schwer.
Sie sollten einfach die Main-Methode der App-Klasse so implementieren,
dass JMJ-RST gestartet wird.
Ja, das war wirklich alles, was Sie da machen mussten.
Sie delegieren einfach die Argumente, die Sie hier bekommen, an die
Main -Methode von JMJ-RST.
Vor allem wird es natürlich, wie man jetzt diese POM-Datei
manipulieren muss, damit es unseren anderen Aufgaben von C genügt.
Also Sie sollten beispielsweise die Hauptklasse in das Manifest
hinzufügen.
Das können Sie hier über dieses Main-Class machen, was Sie hier im
Konfigurationsblock setzen können.
Da müssen Sie einfach den Klassennamen angeben von dieser Klasse, die
Sie starten möchten.
Also die Klasse, die eben diese Main-Methode enthält.
Dann hatten wir Ihnen auf dem Blatt geschrieben, Sie sollten etwas
machen, oder damit es aufgrund der von uns vorgegebenen Artifact-ID
nicht zu Konflikten kommt, da ja alle Module gleich sind, oder die die
gleiche Artifact-ID haben, sollten Sie diese Option Graph-Path-Layout
-Type setzen.
Die kommt auch hier rein und die müssen Sie dann auf Repository
setzen.
Das sorgt einfach dafür, dass der komplette Pfad genommen wird und
nicht nur der Name.
Und dann unterscheidet sich das eben bei allen Abhängigkeiten, die Sie
rein machen.
War das schon alles auf dieser Folie?
Okay.
Das sorgt dafür, dass der Klassenpfad hinzugefügt wird, dieses Add
-Class -Path-True.
Und dann sollten Sie später auch sagen, wo die ganzen Abhängigkeiten
hinkopiert werden sollen.
Wir hatten gesagt, in den Target-Ordner.
Sie können es auch in den Target-Lib machen.
Das ist ein bisschen handlicher, damit Sie nachher diese
Abhängigkeiten wieder wegkopieren können.
Also bei mehreren hat es nicht funktioniert.
Okay.
Ja, die Group-ID wird auch als Ordner genommen, soweit ich weiß.
Tobias, du widersprichst mir, wenn es nicht stimmt.
Also soweit ich weiß, wird Group-ID genommen, Artifact-ID.
Ja, das Problem ist ja eigentlich, dass die Group-ID bei allen gleich
ist, Artifact-ID, oder?
Ich will nochmal genauer nachschauen.
Aber haben Sie eine Lösung gefunden für das Problem?
Okay.
Hat jemand es hinbekommen, ohne diese Zeile rauszulöschen?
Möchte einer sagen, wie er es gemacht hat von denjenigen?
Nein?
Okay.
Alles klar.
Gut, dann müssen wir uns das nochmal anschauen, glaube ich.
Gut, wir werden es ins Forum schreiben, was es da für Probleme gab.
Aber wenn es geklappt hat mit rauslöschen, ist ja schon mal gut.
Das heißt, Sie haben es überhaupt, also Sie haben es hingekriegt, in
irgendeiner Form.
Okay, wunderbar.
Dann müssen wir mal schauen, woran das lag.
Gut.
Was sollten Sie dann noch machen?
Sie sollten noch dieses Maven-Dependency-Plugin anpassen.
Was macht dieses Plugin?
Naja, dieses Plugin sorgt dafür, dass alle Abhängigkeiten kopiert
werden.
Also, dass alle Abhängigkeiten, die Sie haben, auch in diese Char
-Datei, die erzeugt wird, gelangen.
Ein paar Sachen mussten Sie dort konfigurieren.
Sie können in Maven hier angeben, mit diesem Face-Package, wann dieses
Kopieren stattfinden soll.
Durch diese Zeile sagen Sie immer dann, wenn Maven-Package aufgerufen
wird, soll eben dieses Goal-Copy-Dependencies aufgerufen werden.
Dieses Goal gehört halt eben zu diesem Maven-Dependency-Plugin und es
sorgt dafür, dass, so wie es hier konfiguriert ist, dass eben alle
Abhängigkeiten dorthin kopiert werden.
Und zwar halt immer dann, durch dieses Lifecycle-Management von Maven,
immer dann, wenn halt Maven-Package aufgerufen wird.
Das ist das, worum wir Sie zu diesem Repository-Layout nötigen
wollten.
Wir wollten eben, dass diese komplette Ordnerstruktur übernommen wird.
Also, JUnit, JUnit, die Versionsnummer, eben halt die Kombination aus
Artifact -ID und Group-ID.
Das hier war, glaube ich, nicht gefordert.
OverrideSnapshots und OverrideIfNewer.
Das sorgt dafür, dass immer die aktuellsten Abhängigkeiten verwendet
und kopiert werden.
Das ist jetzt vielleicht in diesem Projekt nicht ganz so spannend,
aber wenn Sie jetzt ein eigenes Projekt haben und Sie haben
irgendwelche Abhängigkeiten, die Snapshots sind, also Sie benutzen
irgendein anderes Projekt, das Sie vielleicht auch gerade
programmieren und Sie haben dann immer so eine 001-Snapshot, die Sie
halt ab und zu ein bisschen ändern.
Dann bauen Sie sie neu.
Und jetzt möchten Sie hier das Ganze bauen und kopieren.
Dann schaut Maven nach.
Okay, die Variante, die Bibliothek, habe ich als 001-Snapshot.
Brauche ich mir nicht neu bauen, habe ich ja schon.
Weil die denselben Namen haben, diese Snapshots.
Und damit würden Sie die halt zwingen, dass sie trotzdem jedes Mal neu
gebaut wird, falls Änderungen da sind.
Aber wie schon gesagt, war bei uns hier nicht gefordert.
Dann müssen Sie noch sagen, wohin das Ganze kopiert werden sollte.
Wohin müssen diese ganzen Dependencies?
Sie können hier diese Variable ProjectBuildDirectory nehmen.
Das entspricht ja in diesem Target-Ordner.
Und wir haben vorher auf der Folie zuvor gesagt, naja, wir wollen die
im Lib-Ordner haben.
Wir haben den Klassenpfad so gesetzt, dass eben dieser Lib-Ordner
verwendet wird.
Wie Sie das verwenden, ist egal.
Wir hatten nur Target gefordert und nicht Lib explizit.
IncludeScope.
Runtime sorgt dafür, dass nur die Abhängigkeiten kopiert werden, die
auch zur Laufzeit benötigt werden.
Das heißt, in diesem Fall würde JUnit nicht mit kopiert werden, weil
JUnit würde nur während der Testphase verwendet werden.
Das macht immer dann Sinn, wenn Sie jetzt größere Projekte haben mit
ganz vielen Abhängigkeiten und Sie möchten dem Kunde jetzt nicht
unbedingt JUnit mit ausliefern und Sie möchten auch keine 600 Megabyte
Datei liefern, sondern Sie möchten wirklich nur das haben, was zur
Laufzeit benötigt wird.
Dann kann man das hier einschränken mit Runtime oder Compile.
Eins davon ist auch der Standard.
Ich glaube, Runtime ist sogar der Standard.
Gut, also JUnit schon mal nicht.
Haben Sie Fragen zur Aufgabe 3?
Ich habe schon gesagt, das eine müssen wir nachschauen.
Werden wir Ihnen im Forum Bescheid geben.
Aber gab es sonst irgendwelche Unklarheiten bei dieser Aufgabe?
Gut, alle Klarheiten beseitigt.
Dann übergebe ich Herrn Tobias.
Bist du noch wach?
Weiß ich nicht, mal gucken.
Sehr gut.
Gut, aber ich meine, das Aktivitätsdiagramm wird mich bestimmt genug
aktivieren, dass wir hier irgendwie durch die Aufgabe kommen.
Okay, der war wirklich schlecht, sorry, ich bin müde.
Also, Aufgabe 4, das Aktivitätsdiagramm.
Kurze Frage, wer hatte Probleme mit der Aufgabe?
Hatte jemand Probleme mit der Aufgabe?
War sie zu unverständlich?
Vielleicht ein bisschen.
Vielleicht schauen wir uns das mal genauer an.
War zumindest viel Text.
Genau, schauen wir uns mal genauer an, was da gefordert war.
Sie sollten ein Aktivitätsdiagramm zu diesem Szenario schreiben.
Das Szenario kannten wir ja schon vom vorherigen Blatt.
Genau, jetzt schauen wir uns doch mal an, was in diesem
Aufbeschreibungstext so alles drin steckt.
Zunächst mal, naja, in der ersten Zeile hat man die Applikation, man
hat noch den Nutzer und man hat auch noch irgendwann später diesen
Peer -Co-Op-Zentral-Server.
Das wären jetzt potenzielle Kandidaten für die Partition in unserem
Aktivitätsdiagramm.
Genau, dann gehen wir das Ganze jetzt mal von vorne durch.
Wir haben im ersten Satz eine Aktivität drin, nämlich die Applikation
zeigt die Startseite an.
Daraufhin klickt der Nutzer auf das HDR-Bild und die Vorschau wird
erzeugt und angezeigt.
Außerdem kann er dann durch Betätigen der Teilenschaltfläche das Bild
auf Phasing hochladen.
Genau, dann wird das entsprechende Bild auf den Zentralserver gesucht
und an Phasing gesendet und gleichzeitig damit, mit diesem Senden,
kehrt die Applikation auf die Startseite zurück.
Das gleichzeitig schauen wir uns natürlich gleich noch genauer an,
weil, ja, Gleichzeitigkeit in Aktivitätsdiagrammen können wir ja
gesondert modellieren.
Genau, dann haben wir noch das Klicken der Schaltfläche in neues HDR
-Bild, woraufhin dann halt die Übersicht auf dem Mobiltelefon
gespeicherten Bilder angezeigt wird.
Daraufhin wählt der Nutzer drei Bilder aus, aus der Bildreihe und
bestätigt seine Auswahl mit einem Klick auf HDR-Bild erstellen.
Und die Eingabebilder werden anschließend wieder auf den, oder die
Eingabebilder werden dann auf den Zentralserver hochgeladen.
Das HDR-Bild erzeugt daraufhin auf dem Server und dann kommt die
Beschreibung, wie das Ganze geht mit dem HDR-Bild.
Man rekonstruiert für den Server zunächst die Antwortkurve, dann
kombiniert er die Eingabebilder.
Hierzu iteriert er über die Pixel des Bildes und bestimmt für jeden
Pixel den neuen Farbwert.
Das funktioniert dann wiederum dadurch, dass er halt die gewichteten
Einzelfarbwerte kombiniert mit der Antwortkurve und dann gewichtete
Summe davon benutzt zur Normierung.
Das ist ziemlich genau den Ablauf, den wir ja auch schon auf Blatt 2
implementiert hatten.
Der auch schon auf Blatt 2 als Beispiel ja auch schon in unserem
Lastenheft -Szenario drin vorkam.
Dann daraufhin wird das Bild in den RGB-Farbraum gewandelt vom Server
und beide Bilder gespeichert, sowohl das HDR als auch das RGB-Bild.
Und die Applikation wartet, solange die Erzeugung nicht beendet ist.
Das heißt, wir haben ein aktives Warten auf der Seite der Anwendung.
Außerdem per Klick auf die Schaltfläche HDR-Bild abholen, kann dem
Nutzer das Vorschaubild angezeigt und die Kaufoptionen angezeigt
werden.
Und der Nutzer, wenn er eine Kaufoption gewählt hat, speichert die
Applikation direkt das Bild im Bilderordner, besitzt den Nutzer aber
bereits ein Monatsabonnement, mit dem direkt die Schaltfläche HDR-Bild
jetzt speichern angezeigt von der Applikation.
Jetzt haben wir hier ganz viel Rot, bisschen Gelb und die drei Grünen.
Die drei Grünen waren jetzt potenzielle Partitionen.
Wir haben mit den gelben Geschichten quasi Bedingungen, die wir an den
Stellen in das Aktivitätsdiagramm einfließen lassen können.
Und die Roten sind Kandidaten für eigentliche Aktivitäten.
Die Aktivitäten sind immer, also eine Aktivität ist immer etwas, was
tatsächlich ausgeführt wird, was getan wird.
Außerdem hatten wir noch den Hinweis gegeben, dass sie für die
Darstellung des Aktivitätsdiagramm auch geschachtelte
Aktivitätsdiagramme benutzen können.
Das sehen wir gleich noch später.
Man kann das auch noch vor allen Dingen für das Erzeugen des HDR
-Bildes in ein extra Diagramm auslagern.
Das mussten sie aber nicht.
Sie können es auch einfach in einem Diagramm lösen.
Wenn man sich das Ganze jetzt so anschaut und einfach von vorne
loslegt und das Aktivitätsdiagramm zeichnet, dann fängt man erst mal
an und hat hier die Nutzer, man hat die Applikation, man hat den
Server, man startet irgendwie bei Startseite Anzeigen.
Dann gibt es da irgendwie diese Kante von Startseite Anzeigen von der
Applikation auf HDR-Bild klicken des Nutzers.
Gut, wenn man sich da jetzt mal drüber nachdenkt, das bedeutet, dass
die Aktivität auf ein HDR-Bild klicken des Nutzers tatsächlich davon
abhängt, oder dass eigentlich die Startseite Anzeigen dafür sorgt,
dass der Nutzer daraufhin auf das Bild klickt.
Wenn man da ein bisschen semantisch drüber nachdenkt, ergibt das nicht
so ganz Sinn, weil das ist eigentlich nicht das, was passiert.
Eigentlich müsste man da, genau zu sein, müsste man eigentlich drei
verschiedene Aktivitätsdiagramme an der Stelle machen, die horizontal
durch das Ganze durchgehen.
Wir haben uns aber dafür entschieden, das Ganze ein bisschen anders zu
lösen.
Wir haben nämlich nur zwei Partitionen.
Wir haben nicht den Nutzer als Partition, sondern modellieren den
Kontrollfluss des Nutzers als Bedingungen in der Applikation.
Das heißt, wir haben eigentlich nur die tatsächliche Darstellung des
Programms, der Applikation und des Servers in unserem
Aktivitätsdiagramm und nicht den Nutzer, der auf irgendwas drauf
klickt.
Was auch semantisch für ein Aktivitätsdiagramm eines Programmes
durchaus Sinn ergibt.
Das heißt, wir haben jetzt am Anfang die Aktivität Startseite
Anzeigen, die erst dann in den nächsten Zustand übergeht, wenn die
Bedingung Klick auf HDR-Bild erfüllt ist.
Das heißt, es wurde ein Klick auf diesem HDR-Bild ausgeführt, erst
dann wird die Vorschau erzeugt.
Das heißt, man kann diese Bedingungen, die wir hier sehen, wir haben
die bisher in der Vorlesung immer nur dann an diesen Rauten gesehen,
die wir später auch noch auf der nächsten Folie sehen werden.
Man kann diese Bedingungen aber durchaus in einem UML
-Aktivitätsdiagramm an jegliche Kante dran schreiben.
Das heißt dann, dass diese Kante nur dann ausgeführt wird, wenn diese
Bedingung auch erfüllt wird.
Das heißt, wenn wir die Vorschau erzeugt haben, geht es direkt weiter
auf Vorschau anzeigen.
Ja, eine Frage.
Die Frage war, ob es hier nur weitergeht genau dann oder nur dann,
wenn diese Bedingung erfüllt ist.
Es geht nur weiter, wenn die Bedingung erfüllt ist an der Stelle.
Genau dann also.
Also, Moment, Frage.
Was war das Ziel Ihrer Frage an der Stelle?
Ja, okay, jetzt habe ich Ihre Frage verstanden.
Also, Ihr Kommilitone fragt, ob diese Bedingung hier vorne zwar
erfüllt sein kann, wir verbleiben aber noch in dem vorherigen Zustand
und springen erst dann irgendwann später zu einem späteren Zeitpunkt
weiter.
Im Aktivitätsdiagramm ist es immer so, dass die Token, die da
weitergereicht werden, immer an die jeweiligen Kanten angelegt werden,
sobald die Aktivität beendet ist.
Also, wenn jetzt die Aktivitätsstartseite Anzeigen beendet ist, liegt
hier am Ende dieser Aktivität bereits das Token an und sobald diese
Bedingung erfüllt wird, wird dieser Token weitergereicht.
Das heißt, wir können nicht in diesem Startseite Anzeigen verweilen,
außer Startseite Anzeigen ist noch nicht beendet.
Sobald die Aktivitätsstartseite Anzeigen... ja okay, ich sehe Ihren
Punkt an der Stelle.
Okay, das ist tatsächlich ein valider Punkt.
Also es ist eigentlich genau dann, wenn diese Bedingung erfüllt wird,
geht die Aktivität weiter.
Machen wir mal weiter.
Wir sind jetzt in Vorschau Anzeigen, da Vorschau Erzeugen keine
Bedingung danach hat.
Wir haben dann die Bedingung, Klick auf Teilen ist erfolgt und senden
dann oder schicken dann das Bild an den Server, beziehungsweise der
Server sucht das Bild in der bisherigen Darstellung.
Noch eine Frage.
Die Frage Ihres Kommilitonen war, ob man da noch weiteren
Kontrollfluss bräuchte.
Die Frage war, an der Stelle, noch können Sie noch mal kurz
wiederholen.
Aber ich glaube, im Text ist tatsächlich die Aktion, die beschrieben
wird...
Moment, mal kurz schauen.
Ja, da steht aber nur, dass der Nutzer die Teilenschaltfläche
betätigt, um das Bild hochzuladen.
Da steht keine Aktion von, dass das Bild noch geteilt wird von der
Applikation.
Sie können natürlich, wenn das valide ist, was Sie modelliert haben,
also wir haben jetzt hier zum Beispiel hier unten auch noch weitere
Aktionen eingeführt, die vollkommen okay sind.
Sie durften das gerne erweitern, wenn das semantisch sinnvoll ist an
der Stelle.
Es geht jetzt nicht darum, dass das hier die einzige Lösung ist für
das Aktivitätsdiagramm, sondern wir zeigen jetzt eine Lösung, die wir
für sinnvoll halten an der Stelle.
Genau.
Machen wir mal weiter.
Wenn wir jetzt auf dem Server das Bild gesucht haben, haben wir jetzt
hier die Aufteilung.
Es ging ja, wir erinnern uns eben dran, dass wir diese
Gleichzeitigkeit hatten im Aktivitätsdiagramm.
Mach mal kurz noch kurz den Seine, dann machen wir die nächste Frage.
Und das Bild an Phasing gesendet wird, da beenden wir den
Kontrollfluss an der Stelle, weil der Server dann erstmal dort nicht
mehr weiter handelt im Aktivitätsdiagramm, aber gleichzeitig zu diesem
Senden an Phasing zeigen wir halt wieder die Startseite an.
Jetzt können wir fragen, vielleicht erst...
Also die Frage Ihrer Kommilitonin war, da wir ja jetzt hier beim
ersten Mal Startseite anzeigen, eigentlich jetzt nur, also wir haben
noch kein Bild theoretisch in unserer Aktivität hier modelliert an der
Stelle.
Was wir jetzt hier in diesem Szenario nur abbilden, ist tatsächlich
das, was im Szenariotext dasteht.
Wenn Sie natürlich jetzt ein vollständiges Aktivitätsdiagramm dieser
Applikation und wie das Ganze funktionieren würde, umsetzen wollen
würden, vielleicht würden Sie es dann auch leicht nicht in der Form
umsetzen, wie wir das jetzt hier haben, weil Sie natürlich dann auch
noch verschiedene Möglichkeiten haben.
Sie hätten dann mehr Kanten, die von der Startseite weggehen, weil Sie
ja je nachdem, welchen Kontrollfluss Sie nehmen, dann entscheiden
müssen.
Das funktioniert aber im Aktivitätsdiagramm auch so dann nicht.
Da würden Sie dann vielleicht eine andere Darstellung wählen.
Aber vielleicht nochmal den Hinweis, unten dieser Satz, setzen Sie die
oben stehende Szenario-Beschreibung als Aktivitätsdiagramm um.
Also so wie es dasteht.
Auch wenn es Quatsch ist an manchen Stellen, behaupte ich jetzt
einfach mal.
Wenn man hier davon ausgehen muss, dass schon ein HDR-Bild da ist.
In dem Szenario ist es da, dann müssen Sie das aber so modellieren.
Also auch für die Klausur als Hinweis.
Sie können natürlich, wenn es semantisch Sinn macht, was Kontrollfluss
angeht und so weiter, das Ganze dann noch abändern, aber halt nichts
dazu texten, was halt vielleicht Sinn machen würde, aber so im
Szenario nicht vorgesehen ist.
Lieber gebt ihr die Fragen wieder.
Genau.
Richtig.
Also ein vollständiges Aktivitätsdiagramm dieser Applikation zu bauen.
Oder warten wir nochmal einen Schritt zurück.
Aktivitätsdiagramme modellieren immer einen gewissen Ablauf einer
Durchführung, einer Interaktion mit einem Programm.
Das heißt, wir modellieren dort nicht alle möglichen Abläufe, die es
geben kann, sondern nur den, den wir in dem Fall modellieren wollen.
Wenn wir jetzt tatsächlich alle möglichen Abläufe von der
Geschichte...
oder ich würde tatsächlich in dem Fall dann eher ein Zustandsdiagramm
wählen, um wirklich sagen zu können, wie kann ich von einem Zustand
des Systems in ein anderes übergehen oder tatsächlich ein
Sequenzdiagramm, um die Abläufe darzustellen.
Aber eigentlich sind diese Diagramme in dem Fall nur dafür da,
beispielhafte Anwendungen dieses Programms zu zeigen.
Ist das etwa Ihre Frage?
Es ist ja auch nicht vollständig.
Der Benutzer könnte ja jetzt jederzeit nochmal woanders klicken oder
zweimal auf den selben Knopf drücken.
Das ist hier alles gar nicht modelliert.
Also das soll keine vollständige Möglichkeit aller möglichen
Interaktionen zeigen, sondern halt eben diesen konkret beschriebenen
Ablauf.
Ich glaube, da hinten war zuerst die Frage.
Ja, also die Frage des Kommilitonen war, wir haben jetzt hier nicht
modelliert, dass man die Applikation in irgendeinem Punkt zwischendrin
beenden könnte oder dass man irgendetwas anderes machen könnte.
Das ist aber so ähnlich die Beschreibung, die ich gerade eben auf die
Frage auch schon geliefert habe.
Sie sollten genau dieses Szenario an dieser Stelle als
Aktivitätsdiagramm darstellen.
Das ist eigentlich das Aktivitätsdiagramm in dem Fall mehr ein
Flussdiagramm, was einem zeigt, wie der Ablauf in diesem Fall
funktioniert.
Vielleicht auch nochmal, jedes UML-Diagramm zeigt einen Aspekt.
Klassendiagramm hat irgendwelche strukturellen Abhängigkeiten,
Objektdiagramme, irgendwelche Kontrollflussdiagramme, hier auch
Aktivitätsdiagramme.
Es soll einfach die Abfolge von Aktivitäten hintereinander zeigen und
drum bauen wir solche Guards ein, die sagen, diese Aktivität wird aber
erst gestartet, wenn das hier eingetroffen ist, also wenn einer
draufgeklickt hat.
Da geht es darum, dass man modelliert, wie diese Aktivitäten
hintereinander geschaltet werden oder wann welche Aktivität in welcher
Form stattfindet.
Okay, also die Aussage Ihres Kommilitonen war, ob das jetzt wirklich
die gesamte Wahrheit an der Stelle ist, weil wofür bräuchte man, also
warum kann man überhaupt Bedingungen und warum kann man überhaupt
verschiedene Flüsse und Gleichzeitigkeiten so etwas darstellen.
Gleichzeitigkeit vielleicht schon, aber Bedingungen in dem Fall
überhaupt darstellen, in einem Aktivitätsdiagramm, wenn man immer nur
genau einen Ablauf zeigen will.
Naja, man möchte, vielleicht habe ich mich nicht gut genug an der
Stelle ausgedrückt, man möchte schon zeigen, dass man vor allen Dingen
mit unterschiedlichen Daten und unterschiedlichen Objekten, mit denen
man hantiert, auch unterschiedliche Abläufe darstellen kann.
Wir haben jetzt hier den Objektfluss komplett rausgelassen, aber
eigentlich gehört zu einem Aktivitätsdiagramm auch noch ein
Objektfluss, der je nachdem dann die Bedingungen auch in dem Fall,
naja, je nachdem mit welchen Daten wir das Programm ausführen, haben
wir einen anderen Fluss an der Stelle.
Dafür benutzt man eigentlich das Aktivitätsdiagramm.
Hätten sie das jetzt aber auch noch modellieren müssen, wäre dieses
Diagramm, naja, dreimal so groß geworden.
Das wollten wir von Ihnen an der Stelle nicht fordern.
Das ist eigentlich eine Vereinfachung, die wir jetzt für diese Übung
getroffen haben und die wir meistens auch in der Klausur durchführen,
dass wir sie nur ein bestimmtes Szenario darstellen lassen.
Wenn sie das natürlich jetzt vollständig machen, wird das Ganze
deutlich größer.
Man muss viel mehr Optionen an der Stelle mit betrachten.
Wir möchten aber in dieser Übung nur zeigen, dass sie in der Lage
sind, mit den Elementen umzugehen und diese Elemente auch so
einzusetzen, dass sie einen bestimmten Fluss mit zwei kleineren
Varianten an der Stelle tatsächlich umsetzen können.
Sie müssten ja auch alle Fail-Off-Fälle reinmachen.
Sie würden dann noch andere Diagrammtypen verwenden, Sequenzdiagramme
beispielsweise, um das Ganze noch zu unterstützen, Wegflussdiagramme.
Wir haben hier immer nur eine begrenzte Aufgabe, damit das Ganze noch
handelbar ist und der Klausur auch.
Das ist einfach nur der Grund.
Wir haben noch mehr Fragen.
Also Ihr Kommiliton hat gefragt, ob jetzt natürlich, wenn man jetzt
mehr Varianten in dieser Applikation modelliert hat und man das
Szenario sinnvoll erweitert hat, ob das jetzt ein Fehler wäre.
Also solange das semantisch korrekt ist natürlich nicht.
Also ich zeige Ihnen jetzt hier diese eine Lösung an der Stelle und
die ist schon groß genug und das ist das, was wir quasi als
Minimallösung sehen.
Sie können natürlich beliebig viele weitere Objektflüsse,
Aktivitätsflüsse an der Stelle modellieren und das Ganze sinnvoll
erweitern.
Das ist wie gesagt nicht die eine Lösung hier.
Ich glaube, da war noch eine Frage.
Also die Frage Ihres Kommilitonen war, wenn man jetzt die beiden
Startseiten anzeigen, also das Diagramm so modelliert hat, wie es
jetzt hier ist, nur man hat die beiden Startseiten anzeigen als eine
Aktivität.
Wenn man daraufhin den Objektfluss von dort weg richtig modelliert
hat, also dort dann tatsächlich eine Bedingung, eine Verzweigung hat,
ob jetzt auf das HDR-Bild geklickt wurde oder auf Teilen geklickt
wurde, dann ist das natürlich korrekt an der Stelle.
Ich glaube, wir machen jetzt mal weiter, sonst kommen wir mit der
Übung nicht mehr durch.
Fragen gerne nachher noch, aber wir müssen noch ein bisschen was vom
Stoff heute abarbeiten.
Ja, müssen wir.
Genau.
Gut.
Also machen wir mal weiter.
Wir waren jetzt an der Stelle hier Startseite anzeigen.
Wir haben wieder die Bedingung auf neues HDR-Bild wurde geklickt und
dann zeigen wir die Bilderübersicht an.
Hier haben wir jetzt zwei Bedingungen auf einmal.
Das ist eigentlich sogar noch eine Aktivität in der Beschreibung drin.
Das heißt, es ist vollkommen okay, wenn Sie dazwischen noch eine
weitere Aktivität haben, die das... wie hieß es noch mal genau?
Ja, das Wählen der Bilder eigentlich.
Womit dann die Bilder bestätigt werden.
Wobei das passt eigentlich so.
Genau.
Und dann werden die Bilder hochgeladen.
Wir haben jetzt uns hierfür entschieden, das Ganze hier mit einer
Aufteilung und einem Zusammenführen zu bauen.
Sie können aber auch das Warten, was wir eben in der Beschreibung im
Beschreibungstext gesehen haben, natürlich auch mit einer Aktivität
lösen.
Das sind die beiden Möglichkeiten, wie man das Ganze jetzt umsetzen
kann.
Wir haben jetzt hier noch die Aktivität Upload empfangen, zugefügt.
Das ist aber optional.
Das war nicht in dem Szenario drin.
Das ist jetzt einfach nur eine Erweiterung, die wir jetzt hier
hinzugefügt haben.
Und wir haben jetzt hier die HDR Bild erzeugen Aktivität, die mit
diesem kleinen Symbol ausgestattet ist.
Was bedeutet, wir haben gleich noch ein Diagramm, wo die Aktivitäten
drin sind, die das darstellen.
Genau.
Und dann werden die Bilder gespeichert.
In dem Fall, man hätte jetzt auch noch RGB Bild speichern und HDR Bild
speichern daraus machen können.
Wir haben das jetzt hier einfach aus Platzgründen vereinfacht.
Und die Zusammenführung, die dafür sorgt, dass die Applikation so
lange nicht weiterarbeiten kann, bis diese die Aktivität auf dem
Server beendet ist.
Das bedeutet diese Barriere an dieser Stelle.
Das heißt, hier wird erst dann ein Token angelegt und auch zu
Bildempfang weitergereicht, wenn auf beiden Kanten hier auch ein Token
anliegt.
Das ist wichtig an der Stelle zu sehen.
Das heißt, dieses Warten, was man auch als Aktivität modellieren
könnte, wird hier implizit über diese Barriere geregelt.
Die Bildempfangaktivität ist auch optional.
Die haben wir auch hinzugefügt.
Es ist einfach nur, dass wir da eine Aktivität haben.
Man kann aber auch natürlich direkt weiterspringen an der Stelle.
Jetzt haben wir, dass das HDR Bild abholen geklickt wurde.
Das heißt, dann wird das Vorschaubild angezeigt.
Jetzt haben wir tatsächlich auch eine Unterscheidung, ob jetzt ein Abo
schon vorhanden ist oder kein Abo vorhanden ist.
Wenn kein Abo vorhanden ist, dann werden die Kaufoptionen angezeigt.
Wenn dann eine Option gewählt ist, wird direkt das Bild gespeichert.
So stand es im Text.
Wenn ein Abo vorhanden ist, wird die HDR Bild jetzt speichern
Schaltfläche angezeigt von der Applikation.
Auch nur dann wird sie angezeigt.
Und dann kann man auf HDR Bild jetzt speichern klicken.
Und dann wird das Bild gespeichert.
Das ist jetzt der Teil 2 von dem Hauptdiagramm.
Jetzt machen wir noch kurz die HDR Bild erzeugen.
Das Subdiagramm an der Stelle eigentlich.
Wir haben natürlich für ein Subdiagramm auch immer einen Startpunkt.
Wir müssen wieder sehen, wo beginnt dieses Aktivitätsdiagramm und auch
einen Endpunkt, damit man weiß, wenn man sich jetzt hier das anschaut,
wo man hier reingeht und wo man wieder rauskommt.
Das heißt, als erstes wird auf dem Server dann jetzt die Antwortkurve
rekonstruiert.
Und dann soll über alle Pixel des Bildes iteriert werden.
Dann werden
die Einzelfarbwerte kombiniert mit der Antwortkurve und normiert.
Und wenn alle Pixel berechnet sind, dann kann das Bild in den RGB
Farbraum abgebildet werden.
Das ist jetzt stark vereinfacht an der Stelle.
Wenn man das natürlich jetzt vollständig modellieren wollen würde,
wäre das Aktivitätsdiagramm für dieses HDR Bild erzeugen deutlich
größer.
Uns reicht aber diese Minimalform schon aus.
Wenn Sie da natürlich jetzt mehr modelliert haben, das thematisch
korrekt ist, ist das vollkommen in Ordnung an der Stelle.
Gibt es hierzu Fragen?
Ja, wir hatten jetzt auf jeden Fall schon ein paar Fragen.
Machen wir mal weiter mit Aufgabe 5.
Das ist vielleicht ein bisschen bekömmlichere Kost an der Stelle.
Zumindest mal die ersten Aufgaben.
Wir haben dieses wunderschöne Zustandsdiagramm gegeben und diese tolle
Abfolge von Buchstaben.
Ich meine, Sie haben alle die Grundbegriffe schon gehört.
Sie wissen, wie ein Automat funktioniert.
Von daher sollte das nicht so unglaublich schwierig gewesen sein.
Wir gehen das mal schnell durch.
Wenn wir X eingeben, landen wir in U.
Wenn wir Y eingeben, folgen wir der Kante, landen in dem geteilten
Zustand V kreuz W mit den internen Zuständen D und G.
Mit einem weiteren X in E, A.
Mit Y bleibt man in dem W-Teil in H und bei dem V-Teil landet man in
D.
Mit dem Y verändert sich wiederum nur die linke Seite.
Und wenn wir jetzt das Z eingeben, springen wir wieder aus diesem VW
raus und landen in dem C-Zustand.
Wenn wir jetzt B eingeben, verlassen wir wieder den gesamten großen U
-Zustand.
Hinweis hierbei, wir haben hier eine Historie.
Das bedeutet, es wird sich gemerkt, ob man in B, C oder VW ist, in dem
U -Zustand.
Und diese Information bleibt erhalten.
Wenn wir jetzt also wieder von A mit einem X hier reinspringen, landen
wir wieder in C, weil wir wussten, dass wir in diesem Zustand waren.
Das bedeutet, dieses Historien-Symbol hier unten.
Und jetzt machen wir nochmal Y, ein C, um nach E rauszuspringen, ein
Y, um in I zu bleiben und springen wieder mit X rein.
Wir waren aber immer noch vorher in C, das heißt, wir landen in C am
Ende.
Gibt es hierzu Fragen?
Ja.
Die Frage des Kommilitonen war, wenn jetzt in V eine Historie auch
eine Historie wäre.
Wenn nur in V eine Historie wäre, ja.
Wenn wir jetzt hier ein H-Stern hätten, hätten wir in allen intern
wiederum eine tiefe Historie.
Wenn wir ein H hier und ein H, also ein H in V und ein H in W hätten,
hätten wir, naja, dasselbe Spiel, wenn wir ein H-Stern hätten im U.
Genau.
Also es gibt da verschiedene Varianten, wie man das Ganze dann
aufstückelt.
Genau.
Machen wir mal kurz noch weiter mit der B.
Da gibt es ganz, ganz viele X, die man eingeben muss.
Fangen wir mal mit dem ersten X an.
Wir landen wieder in B, mit einem weiteren X in C, mit dem dritten X
wieder in D-Kreuz G, dann in E-Kreuz H, F-Kreuz G, mit dem Z springen
wir heraus, sind wieder in C, mit dem X wieder rein, füllen wir nach F
und mit X in E-Kreuz H, mit noch einem X in F-Kreuz G.
Das ist dann auch das Ergebnis von Aufgabe B.
Hierzu fragen,
ich glaube, ich muss mich noch ein bisschen abheilen, weil wir haben
gleich noch das Sequenzdiagramm, was wir durchbrechen wollen.
Die dritte Aufgabe war dann das Umwandeln dieses Zustandsdiagramms.
Sie sollten es dahingehend umwandeln, dass diese Historie hier unten
nicht mehr vorhanden ist.
Das heißt, wir müssen eine Variante finden, in der sich gemerkt wird,
ob man in B, C oder V, W war.
Denn V, W ist eigentlich nichts anderes als auch ein weiterer Zustand
in diesem U-Gesamten.
Das heißt, er wird genauso behandelt wie die Bs und die Cs bei der
Umwandlung an der Stelle.
Das heißt, wenn wir das Ganze jetzt umwandeln wollen, müssen wir uns
in A und in I immer merken, waren wir in B, C oder in V, W.
Da wir ja keine tiefe Historie haben, müssen wir es nicht auch noch
merken, ob wir jetzt in D, F, E oder G oder H waren.
Das heißt, die Umwandlung ist eigentlich, dass wir... ja, okay, es ist
ein bisschen unübersichtlich, ich sehe es ein.
Ich weiß nicht, ich soll einfach drüber springen?
Nein, genau.
Wir merken uns eigentlich, ob wir in einem A waren, was vorher in V, W
war, in einem A waren, was vorher in B war oder in einem A waren, was
vorher in C war.
Selbes Spiel für die drei Is und bauen dann jeweils die Kanten dazu,
um das Ganze aufzulösen und haben dann ein äquivalenten
Zustandsdiagramm, was das Ganze auflöst.
Eine Frage?
Die Frage war, warum man sich V kreuz W merken muss, weil man ja nicht
aus V kreuz W raus kann, ohne über B oder C zu gehen.
Das ist falsch.
V kreuz W ist genauso ein Zustand, das hatte ich gerade eben, ist
genauso ein Zustand in U, kann also genauso mit B oder C in A oder I
rausspringen.
Genau.
Deswegen hatte ich die Grafik hier so drin.
Verständlich.
Ja, noch eine Frage?
Die Frage, warum man mehrere von den Endpunkten haben kann.
Aus Darstellungsgründen, ja.
Also eigentlich nein, aber es ist okay, wenn sie das machen.
Theoretisch sollte man nur einen haben, aber ich finde in einer
Klausur oder auch in einem Übungsblatt ist es sonst sehr
unübersichtlich, wenn sie da irgendwelche Kanten quer durch das
Diagramm ziehen müssen.
Uns wird klar, was sie damit meinen an der Stelle.
Sonst Fragen zu dem Zustandsdiagramm?
Gut.
Wenn ich es richtig in Erinnerung habe, dürfen Sie auf dem nächsten
Übungsblatt sowieso nochmal ein Zustandsdiagramm bauen.
Dann aber eins, was nicht nur hier so ein abstrakter Automat ist,
sondern tatsächlich auch ein bisschen mehr Inhalt trägt.
So, jetzt.
Aufgabe 6, das Sequenzdiagramm.
Da hatten sie jetzt eine nochmal wieder vereinfachte Darstellung des
Ablaufs in HDRIs gegeben.
Dieser Text hier.
Wir haben das extra vereinfacht, damit sie nicht noch die ganzen
Überprüfungen, die wir noch in dem Quelltext haben, auch noch
modellieren müssen.
Das heißt, sie sollten in diesem Fall auch hier nur genau dieses
Szenario umsetzen.
Genau das, was wir hier beschrieben haben als Sequenzdiagramm.
Wenn sie es natürlich sinnvoll erweitert haben, das ganze semantisch
wieder korrekt dargestellt haben, ist das natürlich auch okay.
Selbe Antwort wie gerade eben.
Aber sie brauchte nur den Ablauf in diesem Szenario darzustellen in
ihrem Sequenzdiagramm.
Schauen wir uns mal kurz die Methode an, um die es ging.
Das ist die CreateRGB in HDRIs.
Vor allem genau die, die die Enhanced Images, die Samples, das Lambda,
die Matrix Calculator und das Tonmapping übernimmt.
Und intern benutzt diese Methode dann wiederum die HDR ImageIO
CreateRGB mit dem CreateHDR auf dem HDRIs.
Und das sollten Sie hier unten sehen.
Und darin werden dann wiederum die CreateCurve und die HDR Combine
aufgerufen.
Das heißt, Sie mussten in der richtigen Reihenfolge hier jetzt die
Aufrufe modellieren.
Genau dafür ist ein Sequenzdiagramm natürlich auch geeignet, weil man
hier Aufrufe auf einzelnen Klassen in ihrer zeitlichen Abfolge
darstellen kann.
Somit die Interaktion dieser Klassen untereinander modelliert.
Schauen wir uns das Ganze mal an.
Wir haben jetzt die App, in die das Ganze aufruft, das heißt die
Kommandanteilen Applikation hier ganz links.
Wir haben jetzt schon mal vorgefertigt eine Instanz der Klasse HDRIs,
anonym.
Das heißt, dieser Doppelpunkt bedeutet, es ist eine Instanz, aber wir
haben ihr keinen Namen gegeben.
Selbes Spiel für HDR Combine.
Auf HDR ImageIO gehe ich gleich noch genauer ein.
So, wir haben jetzt den ersten Aufruf, nämlich eigentlich die Create
RGB von außerhalb.
Kurze Frage, ja?
Danke für die Frage.
Übrigens war, ob in diesem Diagramm nicht auch die Objekte
unterstrichen werden müssen.
Nein, müssen sie nicht.
Seit 2014 im UML-Standard werden die Objekte nicht mehr unterstrichen
an der Stelle.
Hat sich geändert im Standard tatsächlich.
Also, wir hatten vorher auch noch alle Folien mit unterstrichen und
so.
Objekte werden nicht mehr unterstrichen im aktuellen UML-Standard.
Das ist die Antwort an der Stelle.
Ihr habt das nachgeschaut, oder?
Im Klassendiagramm ist es, glaube ich, auch nicht mehr Pflicht.
Also, ja.
Also, die Antwort ist ja, es ist eigentlich in allen Diagrammen muss
es nicht mehr unterschrieben werden.
Es wird ja klar durch den Doppelpunkt, dass es eigentlich eine Instanz
ist an der Stelle.
Das ist... noch eine Frage?
Stimmt.
Also, ihr Kommilitone fragt, warum App jetzt hier eine Instanz ist und
keine statische Klasse, weil ja eigentlich nur die Main-Methode von
der App benutzt wird.
Sie haben recht.
Ich glaube, das ist einfach ein Fehler in unserer Modellierung, weil
es ist an der Stelle keine Instanz, weil die Main-Methode statisch
ist.
Man braucht keine Instanz von der App-Klasse an der Stelle.
Also, es ist vollkommen okay, ob sie das jetzt als Instanz oder als
statische Klasse modelliert.
Genau.
Machen wir mal kurz weiter.
Wir haben jetzt die createRGB-Methode, die auf HDRISE aufgerufen wird.
Wir sehen hier den Balken, der anzeigt, wie lang der Kontrollfluss
quasi bei dieser Methode bleibt.
Wir haben aber natürlich auch überlappende Kontrollflüsse, zum
Beispiel beim direkt beim nächsten Aufruf.
Ich habe übrigens hier aus Platzgründen die Parameter weggelassen.
Ich glaube, das wäre ein bisschen groß geworden, hätte ich die da
jetzt noch hingeschrieben.
Ich glaube, in ihrem Diagramm hätten sie die aber tatsächlich
modellieren müssen.
Genau.
So, jetzt haben wir den nächsten Aufruf, createHDR, der als Nexus
ausgeführt wird.
Auch auf HDRISE.
Das war dieses gerade eben, das createHDR.
Auch mit den jeweiligen Parametern.
Das ist ein Selbstaufruf auf HDRISE.
Das heißt, der Kontrollfluss geht jetzt über auf die createHDR
-Methode, die den Kontrollfluss der anderen Methode überlappt.
In dieser createHDR-Methode wird daraufhin die createCurve-Methode auf
HDRISE aufgerufen, mit jeweiligen Parametern.
In dieser Methode wiederum wird dann eine Kamerakurve erstellt.
Kamerakurven, also Erstellung von Objekten in Sequenzdiagrammen gehen
immer über dieses create.
Eigentlich ist es sogar createCameraCurve usw.
Das hätte hier aber nicht hingepasst und wäre unlaserlich geworden.
Und erst das Wichtige an der Stelle ist, wenn man dieses create macht,
entsteht dieses Objekt auch erst an dieser Stelle.
Das heißt, wir lesen ein Sequenzdiagramm immer von oben nach unten.
Und das bedeutet, diese Objekte existierten schon an der Stelle, als
wir das Diagramm angefangen haben.
Diese Kamerakurve aber erst zu dem Zeitpunkt, wo wir das create
aufrufen.
Das heißt, sie müssen es auch auf dieser Höhe darstellen, damit es
korrekt an dieser Stelle ist.
Genau.
Daraufhin wird die calculate-Methode auf diesem ccCameraCurve-Objekt
aufgerufen.
Die hat keinen Rückgabewert, deswegen haben wir hier keinen
Rückgabefile.
Daraufhin wird die isCalculated aufgerufen.
Es wird also geprüft, ob die Kamerakurve schon kalkuliert wurde und
kriegen einen Bullshit-Wert hier als Rückgabewert, den wir dann in
unserem if hier unten überprüfen können.
Also je nachdem, ob der Wert true war, dann geben wir diese
Kamerakurve zurück.
Andernfalls geben wir null zurück an der Stelle.
So macht man das in einem Sequenzdiagramm.
Man hat diesen Alternative-Block, der dann verschiedene Alternativen
in dem Sequenzdiagramm darstellen kann.
Daraufhin wird die create-HDR-Methode auf dem HDR-Combine-Objekt
aufgerufen mit den jeweiligen Parametern, also mit der Kamerakurve und
den Enhanced Images.
Die gibt dann das HDR-Image zurück an der Stelle.
Und dieses wird dann wiederum von der, wir sind hier gerade in der
create -HDR-Methode an die create-RGB-Methode zurückgegeben.
Diese muss dann jetzt noch das Bild umwandeln.
Jetzt kommen wir hier auch zu der statischen Klasse.
Also wir haben hier HDR-Image-IO, eine statische Klasse, aber es ist
keine instanziierte Variante dieser Klasse, deswegen hat sie keinen
Doppelpunkt davor.
Und wir haben hier den statischen Aufruf, der eigentlich auch mit dem
Stereotyp Static gekennzeichnet wird an der Stelle, auf diesem HDR
-Image -IO-Klassen-Darstellung, der dann das Buffered-Image als RGB
-Bild zurückgibt aus dem HDR-Image, was wir übergeben haben.
Und dieses Buffered-Image wird dann wiederum der Kommandozeile zur
Verfügung gestellt.
Dann haben wir das Szenario auch abgearbeitet.
Gibt es hierzu Fragen?
Ja?
Die Frage des Kommilitons war, ob das CameraCurve-Objekt nicht
eigentlich nach Beendigung Ende der create-Curve-Methode, warte, wird
ja noch genutzt, bis hier unten genutzt wird, ob sie da nicht zerstört
werden müsste.
Naja, da das in Java so ist, dass es der Garbage-Collector ist, kann
man in der Stelle jetzt nicht, solange es nicht explizit entfernt wird
oder explizit gelöscht wird, dieses Objekt, nicht sagen, zu welchem
Zeitpunkt es tatsächlich nicht mehr existiert.
Es kann natürlich sein, dass es genau an der Stelle passiert, muss
aber nicht.
Also wenn sie jetzt konkret null zuweisen würden, dann könnten sie das
so zeichnen, aber sie wissen das hier an der Stelle nicht.
Weitere Fragen?
Da hinten?
Ich habe sie, glaube ich, akustisch nicht verstanden.
Also die Frage des Kommilitons war, ob an der Stelle, wo jetzt hier
das HDR-Image-Objekt und das Buffered-Image-Objekt angelegt werden, in
den jeweiligen Methoden, ob man das hätte auch modellieren sollen.
Richtig?
Also genau in dem Fall haben wir wieder die Geschichte mit, sie
sollten nur das modellieren, was hier in dem Text steht, aber es ist
natürlich vollkommen korrekt, wenn sie das getan haben.
Weil wir haben da sogar drinstehen, dass es erzeugt wird, richtig?
Also wir sagen nur, es wird ein HDR-Image zurückgeliefert und nicht,
ob es erstellt wird in dem Szenario.
Aber es ist natürlich nicht falsch, wenn sie das getan haben.
Vielleicht noch eine Frage hinterher?
Okay, nochmal.
Also Professor Tich hat gesagt, Objekte und Instanzen werden
unterstrichen, richtig?
Ja, die Information könnte outdated sein.
Wir schauen das nochmal nach, kommunizieren das vielleicht auch
nochmal an Professor Tich hier an der Stelle.
Also unseres Wissens auf jeden Fall im Sequenzdiagramm keine
Unterstreichung mehr für statische... Moment, für Objekte.
An der Stelle, statische Methoden werden aber auch nicht mehr
unterstrichen.
Also Objekte immer mit Doppelpunkt, das ist eben wichtig.
Wir werden uns synchronisieren mit unserem Vorgesetzten.
Er macht das mit der Vorlesung schon ein bisschen länger, um genau zu
sein.
29 Jahre.
Von daher, genau.
Es sind mittlerweile schon 30, ich bin mir nicht sicher.
Er weiß es sich selber nicht mehr so genau.
Genau.
Sonst noch Fragen zu dem Sequenzdiagramm?
Auf
den Return-File, ob man da den Typen hätte angeben sollen.
Ist natürlich gut, wenn sie es gemacht haben an der Stelle.
Wir haben das jetzt hier nicht gefordert.
Natürlich deutlich lesbarer, wenn sie da auch hin dazu sagen, welcher
Rückgabetyp das an der Stelle ist.
Genau.
Gut.
Dann würde ich jetzt mal noch zur Aufgabe 7 übergehen.
Kurze Frage, wer hat Aufgabe 7 gemacht?
Wow.
War eine Bonusaufgabe.
So viele.
Dann war es wohl leichte Punkte.
Mist.
Genau.
Also Aufgabe 7 gab drei Bonuspunkte.
Augen auf bei der Bibliothekswahl.
Naja, worum ging es jetzt hier?
Wir hatten dieses Beispiel mit dem Logger und dem Advanced-Logger.
Jeweils diese Set-Layout und Get-Layout-Methoden haben.
Und dazu die Layout und Advanced-Layout-Verabung an der Stelle.
Genau.
Jetzt ist die Frage dazu, was würde Barbara Liskov an der Stelle dazu
sagen?
Was wäre laut ihrem Substitutionsprinzip an dieser Stelle das Problem
oder auch kein Problem?
Hat jemand eine Idee, was das Problem an dieser Modellierung ist?
Vielleicht machen wir erstmal die offensichtlichen Sachen.
Wir schauen uns mal an.
Set-Layout hat Invariante-Parameter.
Das ist also offensichtlich erstmal okay.
Get-Layout hat Kovariante-Rückgabe-Parameter.
Das ist auch okay.
Gut.
Das klingt jetzt erstmal, als wäre alles okay mit dieser Methode.
Hat jemand eine Idee, was das Problem eigentlich an dieser Stelle ist?
Wer war denn jetzt zuerst?
Wir machen mal da hinten.
Okay, ihr Kommiliton sagt, die Set-Layout von Advanced-Logger ist
ungültig.
Was bedeutet ungültig und warum ungültig an der Stelle?
Also, die Aussage war, sie macht nichts.
Also, ja, sie setzt kein Layout an der Stelle.
Aber im Logger wird ein Layout gesetzt, was im Advanced-Logger nicht
mehr gesetzt wird.
Das war ihre Aussage.
Okay.
Ja, das ist das Problem.
Was ist das konkrete Problem an der Stelle?
Was ist da das Problem mit dem Substitutionsprinzip?
Also, ich will nur darauf hinaus, wenn sie das so in der Klausur
schreiben, würden wir das vermutlich so nicht durchgehen lassen, weil
das zu offen ist.
Sie müssen uns genau sagen, was das Problem an der Stelle mit dem
Substitutionsprinzip ist.
Nur so für spätere Aufgaben.
Jemand anders vielleicht?
Die Aussage des Kommilitons war, die Nachbedingung ist schwächer,
müsste aber stärker oder gleich sein.
Also, die Bedingungen sind tatsächlich das Problem an der Stelle.
Schauen wir uns das mal genau an.
Also, Liskov hat gesagt, Provarianz und Kontravarianz für die
Ausgabeparameter und diese Invarianz.
Ja, das ist schön und gut, aber das ist der erste Satz aus ihrer
Veröffentlichung damals.
Man braucht aber immer noch eine stärkere Forderung als diese
Geschichte.
Man muss natürlich auch noch schauen, ob jegliche Form der Unterklasse
genauso funktioniert wie die Oberklasse.
Und genau da kommen diese Nachbedingungen und Vorbedingungen ins Spiel
an der Stelle.
Genau das wird natürlich von dem SetLayout an der Stelle... die
Bedingung wird eigentlich gerissen mit der Substitution.
Denn, wenn ich mir jetzt vorstelle, ich habe ein anderes Layout, nicht
das AdvancedLayout, sondern ein MoreAdvancedLayout, würde das jetzt im
AdvancedLogger benutzen, dann würde es niemals gesetzt werden, weil es
wird immer dieses AdvancedLayout an dieser Stelle hier oben, im
Attribut genutzt.
Denn die SetLayout-Methode macht ja nichts an der Stelle.
Das heißt, das erwartete Verhalten, was ich eigentlich aus dem Logger
kenne, aus der Oberklasse, wird eigentlich in der Unterklasse gar
nicht mehr durchgesetzt.
Und genau das ist das Problem.
Das heißt, genau, es liefert dann halt immer das AdvancedLayout
zurück.
Das heißt, die Nachbedingung an der Stelle ist nicht erfüllt.
Also SetLayout-Nachbedingung, also die Vorbedingung von GetLayout,
wenn man das Zusammenspiel von den beiden an der Stelle sich anschauen
möchte.
Genau an diesem Punkt ist dann das Substitutionsprinzip erfüllt oder
verletzt.
Gibt es dazu Fragen?
Gut.
Ja, das ist das Ganze nochmal für Ihren Ausdruck.
Genau, das Substitutionsprinzip ist halt mehr als nur die Betrachtung
von der Varianz, der Ein- und Ausgabenparameter.
Die zulässigen Varianten stellen halt die notwendigen Bedingungen dar.
Die hinreichende Bedingung ist dann natürlich noch die Vor- und
Nachbedingung zu prüfen.
Und natürlich, ob sich das Exemplar der Unterklasse auch wie das in
allen Kontexten wie das Exemplar der Oberklasse verhält.
Was in dem Fall natürlich nicht der Fall ist.
Das ist übrigens ein Beispiel, ein reales Beispiel aus der C-Sharp
-Logger -Implementierung, glaube ich.
Das heißt, solche Probleme gibt es tatsächlich und sie werden auch
immer wieder auch in realer Software auftreten.
Deswegen wollten wir das Ganze nochmal motivieren, dass Sie sich auch
bewusst sind, dass solche Geschichten zu Problemen führen können.
Gerade dann, wenn Sie Bibliotheken verwenden, wenn Sie das Verhalten
eines gewissen Klasse voraussetzen und dann merken, naja, Sie tut aber
gar nicht das, was die Oberklasse eigentlich angeben würde an der
Stelle.
Das ist wichtig an dieser Stelle.
Gerade dann, wenn Sie große Projekte entwerfen, wenn Sie mit vielen
Leuten an bestimmten Projekten arbeiten.
Genau.
Das war auch schon alles zur Übung.
Wir haben noch eine Viertelstunde Zeit.
Das heißt, wir können gerne noch eine Viertelstunde über das
Aktivitätsdiagramm reden, wenn auch jemand Lust hat.
Aber das wäre es sonst erstmal von uns.
Nächste Woche ist dann tatsächlich Professor Tichy wieder mit der
Vorlesung da.
Montag ist Feiertag, also keiner am Montag kommt.
Aber nächste Woche Freitag geht es dann weiter mit den Entwurfsmustern.