Guten Morgen, herzlich willkommen zur SWT 1 Übung, heute zum dritten
Übungsblatt.
Was Sie hier sehen ist hoffentlich nicht das, was in Ihrem Kopf
passiert nach dem Uni-Fest, obwohl das bei dem einen oder anderen
vielleicht auch so sein könnte.
Nein, das ist eine Atombombe, für alle, die das noch nie gesehen
haben.
Und in unserem heutigen Riz to the Public geht es um den Kalten Krieg.
Wer kann sich noch an den Kalten Krieg erinnern?
War jemand dabei?
Keiner, gut.
Umso besser, trotzdem hoffentlich alle im Geschichtsunterricht
aufgepasst.
Kalten Krieg gab es mal und im Kalten Krieg, insbesondere in der
Anfangsphase, in den 60er Jahren, gab es ein extremes Atomwettrüsten
zwischen den USA und der Sowjetunion.
In den USA war es so, wir hatten am Ende der 60er Jahre so um die 1000
sogenannte Middleman-Raketen, das sind Raketen mit Atomsprengköpfen,
die stehen in unterirdischen Silos und können dann schön jederzeit
abgefeuert werden auf den sozialistischen Klassenfeind.
Was ist da wichtig, wenn man so einen Atomkrieg gewinnen will oder
zumindest mal nicht verlieren?
Was schwierig ist bei einem Atomkrieg, weil da verlieren meistens
alle, naja, man möchte schnell reagieren können.
Also wenn nachts oder am frühen Morgen Russland auf die Idee gekommen
wäre, jetzt mal einen Atomkrieg anzufangen, dann wollte man wenigstens
in der Lage sein, noch zurück zu feuern, bevor man selber das Licht
ausmacht.
Das heißt, man wollte diese Raketen möglichst schnell starten können.
Auf der anderen Seite sollte das natürlich nur von autorisierten
Personen getan werden können.
Das heißt, die Führungsriege in den USA, vorneweg der Präsident,
wollte eben, dass das möglichst sicher passiert.
Dass nur autorisierte Personen, heißt also er, Zugriff haben auf
dieses Raketensystem.
So, wie macht man sowas?
Man baut sowas sicher, indem man so eine Art Zahlenschloss in Form von
diesem Laptop davor schaltet.
Dieser wiederum ist auch atombetrieben.
Warum?
Naja, damit eben die Akkulaufzeit nicht irgendwie nach acht Stunden
vorbei ist und man auch möglichst noch mitten in der Nacht und zu
jeder Zeit auch noch Zugriff drauf hat.
Und dort muss man eben einen achtstelligen Code, so war das damals,
eingeben, um Zugriff auf das Atomsystem zu bekommen.
Soweit, so gut.
Aber naja, sagen wir mal so, das Militär, das arbeitet ja in den USA
nicht unbedingt immer so, wie die Regierung das möchte, hat gerne
selber noch eigene Kompetenzen und war dann der Meinung, ja, mit dem
Schnellreagieren ist halt blöd.
Wer weiß, was passiert, wenn der Präsident gerade schläft, während der
Russe anfängt zu feuern.
Da wollen wir ja auch reagieren können.
Das heißt, wir haben gesagt, wir müssen diese Sicherheitscodes
irgendwie so vorbereiten, dass wir trotzdem noch schnell Zugriff
haben.
Was machen wir also?
Naja, wir setzen halt achtmal die Null als Sicherheitscode.
Und nicht nur das, sondern man hat auch noch Checklisten verfasst,
sodass immer zu Dienstbeginn geprüft wurde, ob denn auch diese
Sicherheitscodes noch genauso waren.
Also man hat nicht nur gesagt, achtmal die Null ist unser Code, nein,
man hat das auch noch auf dem Zettel nebendran geschrieben, damit auch
jeder checken kann, ob das auch immer noch genauso ist.
Und schon hat man ganz schnell Zugriff auf dieses Atomsystem.
Wunderbar, wann wurde das eingeführt?
1962 von Kennedy.
Und lief da genau in dieser Art und Weise viele, viele Jahre.
Und irgendwann 1974, als ein Offizier in den Ruhestand gegangen ist,
der genau das wusste, hat er angefangen, seinem Senator Briefe zu
schreiben.
Dass das ja so irgendwie vielleicht nicht so eine richtig gute Idee
ist.
Und das Ganze hat er drei Jahre lang gemacht, deshalb steht hier 74
bis 77, weil es drei Jahre lang einfach mal keinen interessiert hat.
Und dann hat er irgendwann angefangen, das mal ein bisschen anders zu
machen und hat eine Veröffentlichung draus gemacht mit einem Kollegen,
in der er darlegt, wie man zu 14 Raketensilo übernehmen kann, wenn man
weiß, wie.
Und wenn man dann einmal vor dem Sprengkopf steht, ist es ja einfach,
weil man weiß ja den Code.
Und daraufhin wurde dann doch mal reagiert.
Dann wurden mal tatsächlich diese Codes umgestellt, ab 1977,
hoffentlich sinnvoll.
Hoffentlich hängt jetzt kein Bild mehr daneben, wo der Code
tatsächlich draufsteht.
Also irgendwann wurde es dann doch getan.
So, was ist jetzt die Lehre daraus?
So diese erste persönliche Bitte von mir an Sie, wenn möglich,
brauchen Sie einfach keine Atomraketen.
Und auch nichts ähnliches.
Ich denke, die Welt kommt auch ohne gut klar.
Aber die zweite Lehre ist, wenn Sie das jetzt mal auf Software
übertragen, dieses Problem, da gibt es ja auch genug
sicherheitskritische Dinge.
Das heißt, wenn Sie ein sicherheitskritisches System entwickeln und
dort ein Sicherheitssystem davor stellen möchten, dann bauen Sie das
auch so, dass das eben nicht einfach umgangen werden kann, dass das so
funktioniert, wie es soll.
Und bauen Sie was ein, was vielleicht darauf hinweist, dass man das so
nicht benutzen sollte oder was irgendjemanden darauf hinweist, dass
die Benutzung des Sicherheitssystems hier gerade umgangen wird.
Das würde schon enorm helfen.
Gut, wunderbar.
Das war Risk to the Public für heute.
Jetzt geht es tatsächlich los mit der Übung.
Und Tobias beginnt mit den ersten zwei Aufgaben.
Ja, genau.
Also hoffentlich, das mit den Atomraketen machen wir jetzt mal nicht
weiter.
Unser Übungsblatt war hoffentlich auch nicht so ganz so einschlagend
wie so eine Atomrakete.
Aber beginnen wir erstmal mit Aufgabe 1.
Da ging es darum, die Vorbereitung für die Plugin-Architektur
durchzuführen.
Sie sollten also zunächst in dem vorgegebenen...
Also wir haben Ihnen vorgegeben, die Klassen, die Sie in Jam.JST
einfügen sollten.
Und in denen sollten Sie ein bisschen Funktionalität hinzufügen.
Zum einen sollten Sie die Funktionalität hinzufügen, wie man die
Plugins ausliest über den Service Loader.
Das ist genau das, was wir jetzt hier sehen.
Man holt sich also den Service Loader und übergibt dem die Klasse, die
man quasi laden will.
Also alle Exemplare, die man vorher annotiert hat.
Das sehen wir gleich noch genauer bei der zweiten Aufgabe.
Werden dann über den Service Loader zur Verfügung gestellt und man
erhält genau diese Klassen oder Instanzen dieser Klassen über diesen
Aufruf hier oben.
Eine weitere Aufgabe war dann jetzt in diesem Fall noch, Sie sollten
das Ganze sortiert anhand der Priorität durchführen.
Das heißt, Sie sollen die Liste, die Sie dort jetzt zurück erhalten,
auch noch sortieren und das Ganze dann zurückgeben.
Hier kommt jetzt die Funktion zum Sortieren.
Das war dann in dem Jam.JST Plugin.
Das Ganze ist einfach ein CompareTo, weil das Ganze halt das
Comparable Interface oder die Comparable Schnittstelle implementiert.
Und Sie sollten dabei noch darauf achten, dass falls eine Priorität
von den verglichenen Prioritäten null ist, dass dann diese immer als
niedrigst eingeordnet zurückgegeben wird.
Also immer kleiner ist als alle anderen.
Das ist genau das, was Sie hier mit diesen beiden If-Schleifen sehen.
Und hier unten ist eigentlich ganz einfach der eigentliche
Sortieraufruf für eine Enumeration.
Die Sortierung ist in Java ziemlich einfach.
Sie können auch nicht den Comparator von Enum überschreiben, einfach
so, weil der ist final.
Aber Enums sind immer so sortiert, dass sie das ausgeben, was die
Reihenfolge ausgeben, die auch in dem Enum spezifiziert ist, was in
unserem Fall low, mid und high war.
Das heißt, das reicht erstmal für die Sortierung und die Sortierung
anzubieten.
Was Sie aber ja dann gleich noch in der Implementierung des Menüs
machen sollten, war das ganze genau umgekehrt anzeigen.
Und das sehen wir gleich noch.
Jetzt kommen wir nämlich auch schon zur Darstellung.
Sie sollten also das Menü von JMJST erweitern, um genau zu sein, das
Dateimenü, was bereits schon vorhanden ist, welches in der Klasse Menü
im Constructor angelegt wird.
Und Sie sollten Ihren neuen Eintrag, also Ihren neuen Plugins, als
weiteren Menüpunkt bzw.
Untermenü dieses Menüs einfügen.
Das machen Sie, indem Sie ein weiteres JMenu erstellen und dieses dem
Ganzen hinzufügen.
Natürlich sollten Sie das nur machen, wenn es überhaupt was gibt, was
angezeigt wird.
Es gibt noch die Behandlung, was passieren soll, wenn es keine Plugins
gibt, aber das sehen wir gleich noch.
Sie sollten das Ganze oberhalb des Separators, das ist die Linie, die
in dem Menü ist, durchführen, aber unterhalb der anderen Punkte, die
darüber sind.
Ich glaube, das ist aber auch relativ klar gewesen.
Hier diese CreateSVT1PluginMenu-Methode schauen wir uns jetzt gleich
noch genauer an, in der wird das Ganze dann wirklich erstellt, das
Menü, was wir anzeigen wollen.
Hier sieht man jetzt diese CreateSVT1PluginMenu-Methode.
Was sehen wir da jetzt nun?
Klar, wir erstellen erstmal ein neues JMenu und fügen diesem dann
einzelne Einträge hinzu.
Das funktioniert jetzt hier in dieser Schleife.
Das Wichtige ist hier, diese Schleife läuft rückwärts, genau das, was
ich eben schon beschrieben habe.
Wir haben ja durch das Collection.Sort das Ganze erstmal von niedrig
nach hoch sortiert.
Wir haben also die Liste genau andersrum, als wir sie eigentlich
anzeigen wollen.
Denn wenn wir etwas in ein JMenu einbügen, ist immer das, was zuerst
eingefügt wird, auch als oberstes in diesem Menü vorhanden.
Das heißt, wir müssen das Ganze genau andersrum machen.
Und hier unten ist auch noch das mit der Fehlernachricht, wenn keine
gefunden werden.
So, jetzt schauen wir uns mal den Schleifenrumpf an.
Was machen wir da?
Wir holen uns jedes Plugin jeweils mit dem GetE auf der Liste, die wir
da iterieren und initialisieren das zunächst.
Das erfüllt die Schnittstelle, die wir dort angegeben haben.
Daraufhin wird ein neues Menü-Item erzeugt und dieses dann
hinzugefügt.
Und außerdem wollten wir noch schauen, dass wir auch noch einen
zweiten Menü-Eintrag hinzufügen, sofern das Plugin, was wir gerade
geladen haben, auch konfigurierbar ist.
Das überprüfen wir einfach mit dem IsConfigurable, auch von der
Schnittstelle angeboten, der Plugins.
Und wenn das der Fall ist, fügen wir halt auch noch einen
Konfigurationseintrag hinzu.
Die beiden Methoden Create und schauen wir uns jetzt noch genauer an.
Was passiert da jetzt im Create Menü-Item?
Eigentlich nichts anderes, als dass dieses Menü-Item erstellt wird und
der ActionListener definiert wird.
Was dieser ActionListener in diesem Fall macht, ist immer dann, wenn
auf diesen Eintrag geklickt wird, soll in dem Fall die Run-Methode
aufgerufen werden.
Sind wir aber im Fall von dem Anpassungseintrag, also dem
Konfigurationseintrag, dann ist das Ganze natürlich, was hier
aufgerufen wird, die Configure-Methode.
Gibt es dazu zunächst erstmal Fragen?
Ich glaube, das war relativ einfach umzusetzen, weil man einmal weiß,
wie das Ganze mit Swing funktioniert und die ganzen Einträge
ineinander geschaffelt werden und so ein bisschen sich damit
beschäftigt hat, wie das mit Beobachtern und Events funktioniert.
Fragt doch mal, wer es schwer fand.
Wer fand es schwer?
Wer fand es schwer, genau.
Siehste?
Ja, nur einer.
Ja, also alles gut.
Wer fand es denn leicht?
Ja, okay.
Und der ganze Rest schläft noch, das ist auch okay.
Also eigentlich nicht, aber gut.
Ja genau, jetzt noch die Bonusaufgabe.
Wir hatten noch eine Bonusaufgabe in der ersten Aufgabe.
Da ging es darum, immer dann, wenn keine Menüeinträge vorhanden sind,
also keine Plugins vorhanden sind, sollte so ein ausgegrauter
Menüeintrag angezeigt werden in dem Menü.
Das heißt hier, sollte ein No Plugins Available als neuer Menüeintrag
gesetzt werden.
Und eine Möglichkeit, um das Ganze auszugrauen, ist einfach diesen
Wert auf Enabled Faults zu setzen.
Also, dass es halt nicht enabled ist.
Das graut das Ganze aus und man kann nicht mehr draufklicken.
Ja, eine Frage?
Okay, die Frage war, ob man das Ganze nicht jetzt besser in dem
Messages Properties File macht.
Ja, wenn man das Ganze sauber machen möchte, ist es natürlich schön,
wenn man es in Deutsch und in Englisch umsetzt und das Ganze wirklich
mit den Message Properties macht.
Wir haben aber das nicht gefordert auf dem Übungsblatt.
Wenn Sie es gemacht haben, ist es schön.
Und auf unserer Folie wäre das jetzt auch ein bisschen länger
geworden, wenn wir das Ganze noch gemacht hätten.
Aber wir haben es explizit nicht gefordert.
Es ist aber schön, dass Sie sich damit beschäftigt haben.
Für alle, die es interessiert, ist das natürlich auch die saubere
Variante.
Wenn man eine Applikation hat, die mehrere Sprachen hat, dann sollte
man das natürlich immer so machen, anstatt irgendwelche Strings hart
zu codieren, lieber irgendwelche Property-Dateien zu benutzen.
Da die Aufgabe auch nur drei oder vier Punkte gegeben hat, haben wir
das jetzt erstmal nicht gefordert.
Aber ja, vielen Dank.
Es ist einfach schön, dass jemand in der Vorlesung aufgepasst hat,
weil das war ja so ein typisches Beispiel von Dingen, die man
wegkapseln soll.
Also insofern freut mich das jetzt persönlich.
Aber wir haben es nicht gefordert, wie Tobias schon sagt.
Machen wir nächstes Jahr.
Gut, das war es soweit zur Aufgabe 1 auch schon.
Wie gesagt, relativ kurz.
Aufgabe 2 ist, glaube ich, sogar noch kürzer.
Wobei nicht von den Folien her, aber zumindest von dem, was getan
werden musste.
Was sollten Sie dort nun tun?
Sie sollten ein neues Plugin, das Prism-Plugin, erstellen, welches die
Schnittstelle JMJST-Plugin erweitert.
Und hier sieht man jetzt auch schon den wichtigen Eintrag für den
Service -Loader.
Denn dieses Metainf-Services hier oben, mit der Angabe der Klasse,
gibt uns die Information, dass diese Metainformationsdatei erstellt
werden soll.
Die wird dann in die JAR unter Metainf-Services und dann den Full
Qualified Name der JMJST, also der Klasse, die wir suchen, angelegt.
Und in dieser stehen dann alle Plugins oder alle Klassen, die diese
Schnittstelle mit dieser Annotation enthalten oder überhaupt anbieten.
Das heißt in diesem Fall vor allen Dingen unser Plugin, was wir jetzt
gerade hinzugefügt haben, das Prism-Plugin, was jetzt dann da mit
seinem Full Qualified Name drinsteht und dann dementsprechend auch
aufgerufen werden kann vom Service-Loader.
Gibt es dazu Fragen?
Gut, dann gehe ich mal davon aus, dass es bei den meisten geklappt
hat.
Ich wollte gerade fragen, hat es bei irgendjemandem nicht
funktioniert?
Okay.
Ihr Kommilitone sagt, aus unerfindlichen Gründen ist der Service
-Eintrag ab und zu verschwunden.
Das kann ich bestätigen.
Das Problem habe ich auch schon ein paar Mal gehabt und weiß auch noch
nicht so ganz genau warum.
Ich habe das Gefühl, es wird besser, wenn man den Scope ändert.
Den Tipp habe ich auch letzte Woche schon jemandem gegeben, der
gefragt hat.
Aber warum das genau passiert, weiß ich bis heute nicht.
Man muss dann einfach versuchen, nochmal zu bauen, lean und nochmal
ein Package zu machen und dann funktioniert es in den meisten Fällen.
Du hattest das Problem, glaube ich, gestern noch.
Das passiert jedem.
Ich konnte es auch nicht reproduzieren.
Mal funktioniert es, mal nicht.
Ich vermute, es liegt an der Implementierung, die dahinter hängt.
Aber wenn wir irgendwann mal einen zuverlässigen Workflow haben, wie
das verhindert wird, dann lassen wir Sie es wissen.
Gut, soviel zu der Service-Loader-Geschichte.
Was sollten Sie jetzt nun noch in dieser Aufgabe tun?
Zunächst einmal noch ein paar Informationen dem Plugin hinzufügen.
Natürlich den Namen des Plugins, Prism Plugin in dem Fall.
Den Menü-Eintrag, der angezeigt werden soll, in dem Menü, was wir eben
erstellt haben, falls es geladen wird.
Außerdem sollten Sie noch die Run-Methode und die Init-Methode
implementieren.
Bei der Run-Methode war es so, Sie sollten das momentane Datum
ausgeben.
Sie mussten das jetzt nicht unbedingt genau in diesem Format hier
darstellen.
Sie sollten aber zumindest Datum und Uhrzeit irgendwie dargestellt
haben.
Das Ganze haben Sie ja schon mal gesehen bei den Testfällen, wie wir
die abgespeichert haben.
Ich denke, es sollte relativ klar sein, wie das funktioniert mit dem
Date -Format.
Und die Überwachung läuft dann seit dem momentanen Zeitpunkt, seit das
Ding gerade angezeigt wird.
Die Init-Methode war ein bisschen einfacher.
Sie sollten einfach nur auf Standard-Ausgabe IMAGE, Ihr freundlicher
Nutzer -Datensammler, seit 2016 ausgeben.
Weil, Sie werden auch gleich schon sehen, wir hatten auch schon
letztes Jahr IMAGE.
Und seit da funktioniert das Ganze schon.
Hoffentlich.
Unsere Daten?
Ich weiß nicht.
Was sagst du zu den Daten vom letzten Jahr?
Gründliche Daten von allen Studenten vom letzten Jahr.
Insofern kann ich bestätigen.
Alles wunderbar.
Alles klar.
Was sollten Sie noch tun?
Konfigurierbar sollte unser Plugin auch sein.
Und die Konfigurier-Methode ist jetzt ein bisschen komplizierter hier.
Was sollte da gemacht werden?
Sie sollten zum einen den Username auslesen.
Das geht über system.getPropertyUsername.
Funktioniert recht einfach, wenn man danach googelt, findet man diesen
Eintrag, glaube ich, als erstes.
Und Sie sollten den Titel, oder Sie sollten irgendetwas anzeigen.
Es ist nicht genau spezifiziert, was Sie dort anzeigen sollten.
Ich habe das Ganze jetzt mit einer JObson-Pane in einem Information
-Message -Zustand genommen.
Das heißt, es ist eine Information-Message, die hier angezeigt wird.
Die hat einen Titel und die hat ein OK und so ein Ausrufezeichen auf
der linken Seite.
Und einen Text, der angezeigt wird.
Der Text ist in diesem Fall, also überwache Nutzer XY.
Und der Titel dieses Fensters ist in meinem Fall jetzt Prism.
Und je nachdem, ob die Priority gesetzt war, No Priority oder nur
Priority.
Das ist hier, was hier in diesem Titel steht.
Bisschen kryptisch, aber die If-Abfrage hätte nicht mehr auf die Folie
gepasst.
Ich hoffe, das ist einigermaßen verständlich.
Ansonsten schreiben Sie das Ganze mal als If-Bedingung aus, dann
verstehen Sie, was da passiert.
Genau.
Ansonsten mussten Sie noch...
Es gibt eine Frage.
Eine Frage, okay.
Die Frage war, was ist dieses JMJST, was hier übergeben wird?
Das ist das JMJST, was in der Init-Methode...
Also Sie übergeben dort das Objekt, auf dem das Ganze übergeben wird.
Und JMJST ist in dem Fall, glaube ich, das hier gesetzte JMJST.
Sie übergeben in der Init-Methode JMJST, damit Sie Dinge in der GUI
anzeigen können von JMJST.
Sonst funktioniert das nicht, sonst hat das Plugin keinen Zugriff auf
die GUI und kann nichts anzeigen.
Das ist auch der Grund, warum diese Init-Methode hier die Main von
JMJST übergeben bekommt.
Das habe ich gerade noch vergessen.
Vielen Dank.
Genau, und das ist das, was hier jetzt übergeben wird.
Gut.
Ansonsten brauchten wir noch die Getter und Setter für die Priority,
die gesetzt werden sollte.
Und ich glaube, das war auch schon alles für Aufgabe 2.
Und ich kann wieder an Sebastian übergeben.
Wunderbar.
Dann mache ich mit Aufgabe 3 weiter, dem Wandel, auf das es auch nur
zwei Punkte gab.
Das liegt einfach daran, dass das eigentlich inhaltlich jetzt nicht so
eine super spannende Aufgabe ist.
Wer das gemacht hat, der hat auch gesehen, es ist relativ einfach.
Aber es ist ziemlich nützlich.
Und das ist genau der Grund, warum jetzt hier diese Folie so erstmal
dasteht.
Ich würde jetzt gerne mal von Ihnen wissen, warum haben wir denn
überhaupt dieses Wandel gebaut?
Ist das irgendjemandem klar oder machen Sie einfach alle nur die
Übungsaufgaben, weil es halt dasteht?
Warum ist es sinnvoll, so ein Wandel zu haben?
Was macht das in unserer Projektumgebung?
Vorsicht Lattenzaun, der Name sagt es schon.
Ich fasse das mal ein bisschen kürzer zusammen, was der Kommilitone da
gerade gesagt hat.
Er sagte, naja, wir brauchen doch irgendwie ein Projekt, was die
ganzen bisher erstellten Projekte zusammenfasst, damit man sie eben
gemeinsam ausführt.
Und dazu muss man eben in einem Projekt, und das ist hier das Bundle,
alle Abhängigkeiten auf die bisher erstellten Projekte angeben.
Und dann hat man eben so eine Zusammenbündelung aller Projekte.
Ja, das ist richtig, aber kann man das nicht einfacher machen?
Haben wir das nicht vielleicht sogar schon mit unserem IMAGE
-Überprojekt?
Warum geht das damit nicht?
Ihr Kommilitone sagt, was sehr richtig ist, nämlich, dass wir
vielleicht trennen wollen, Entwicklung und Deployment, und das können
wir genau damit erreichen.
In unserem Überprojekt IMAGE haben wir dann eben das Komplette, was
wir gerade entwickeln, und in dem Bundle haben wir eben das
zusammengeschnürt, was wir vielleicht rausgeben wollen.
Wir haben aber noch einen ganz einfachen weiteren technischen Grund.
Wir können einfach in dem Überprojekt nichts bauen.
Das erzeugt keine JAR.
Das ist der einfache technische Grund.
Aber wie wäre es denn, wenn wir das anders machen?
Warum ziehen wir denn nicht diese ganze Funktionalität aus dem Bundle
einfach in das JAR-ST-Projekt?
Würde doch auch tun.
Das benutzen wir doch irgendwie immer.
Warum machen wir das nicht da?
Kann sich da jemand was denken?
Ja.
Können Sie das bitte nochmal wiederholen?
Ich habe Sie akustisch nicht verstanden.
Ja, Sie wollen mit Ihrer Antwort im Grunde auch etwas Ähnliches raus
wie Ihr Kommilitone zuvor.
Man wäre dann im Grunde festgelegt, was die Bündelung betrifft.
Man hat dann immer bei JMJST alle Plugins dabei und will das
vielleicht gar nicht haben, sondern möchte nur ein Teil ausliefern.
Und das kann man über das Bundle gut erreichen.
Ja, könnte sein, aber das ist tatsächlich nicht der Hauptgrund.
Fällt noch jemand was anderes ein?
Denken Sie mal an die letzte Vorlesung.
Benutzt Relation.
Jetzt vielleicht?
Fällt der Groschen?
Ah ja, unser Kollege, der sich über sowas Gedanken macht, wie man gut
kapselt.
Ja, bitte.
Ihr Kommilitone sagt, man möchte das nicht so stark koppeln.
Das ist genau die richtige Antwort und tatsächlich ginge diese
Kopplung auch gar nicht.
Wenn Sie das bauen würden, würde Ihre IDI meckern und spätestens wenn
Sie Maven ausführen, gäbe es ein großes Gemecker, weil wir plötzlich
eine zyklische Abhängigkeit hätten.
Unsere Plugins sind alle abhängig von jame-jrst.
Wenn wir jetzt eine Abhängigkeit von jame-jrst auf die Plugins
definieren, haben wir einen Zyklus.
Und das geht einfach nicht.
Und ich habe Ihnen jetzt mal hier eine Übungsaufgabe vom letzten Jahr
mitgebracht.
Da hatten wir im Grunde ein ähnliches Projekt-Design.
Da hatten wir auch schon Image und wir hatten auch so ein Bundle.
Und da sieht man das ganz gut.
Das hier unten können Sie ignorieren.
Das sind im Grunde die GUI-Entwicklungen, die Sie jetzt machen.
Und wir hatten letztes Jahr Kantendetektoren, deshalb gibt es hier
einen Sobelfilter.
Aber von der Struktur her ist es genau das gleiche, was wir dieses
Jahr machen.
Nur die Plugins sind halt inhaltlich komplett anders.
Und wir haben letztes Jahr die Studenten auf dem vierten Übungsblatt
mal so eine benutzte Relation zeichnen lassen.
Und da sehen Sie sehr schön, dass unser Hallo-Plugin, was jetzt das
Prism -Plugin ist, von Jam.jsT abhängt.
Wenn wir das jetzt umkehren würden und Jam.jsT zum Bundle machen
würden, dann hätten wir ja eine Abhängigkeit nach hier oben.
Und schon haben wir einen Zyklus drin, was nicht zulässig ist.
Und deshalb gibt es eben dieses Bundle, was eben alles zusammen
schnürt.
Gut, alles klar soweit?
Oder gibt es da noch Fragen dazu, warum wir das Ganze machen?
Wenn nicht, dann zeige ich Ihnen kurz, wie die Aufgabe zu lösen wäre.
Ich glaube, die erste Aufgabe war, sorgen Sie dafür, dass man Jam.jsT
starten kann über das Bundle.
Was soll ich sagen, das ist alles, was man dafür tun muss.
Nicht so besonders schwierig und für die restlichen Aufgaben gilt so
ungefähr das gleiche.
Im Wesentlichen müssen Sie Ihre POM genauso anpassen, wie Sie das auch
schon getan haben, als Sie das Kommandozeilen-Werkzeug gebaut haben.
Und ich glaube, das stand sogar wörtlich so in der Aufgabenstellung.
Das heißt, ich gehe da jetzt einfach mal ein bisschen schneller
drüber, weil wir das alles schon mal gesehen haben auf dem letzten
Übungsblatt.
Sie müssen wieder dafür sorgen, dass die Abhängigkeiten kopiert
werden.
Und Sie müssen natürlich wieder dafür sorgen, dass die Struktur
erhalten wird.
Ansonsten bekommen Sie Probleme, weil Sie ja mitunter Ihre einzelnen
Artefakte gleich benennen.
Dementsprechend müssen Sie auch das tun.
Aktuelle Versionen immer vorhalten, das ist noch etwas, was man tun
sollte.
Ich weiß nicht, ob das neu war.
Ich glaube, das war tatsächlich etwas, was jetzt erst kam.
Das ist also die Option, die Sie setzen müssen in dem Copy
-Dependencies, damit Sie immer die aktuellste Version dann tatsächlich
bekommen von Ihren Einzel-Artefakten.
Das heißt also, wenn Sie etwas bauen würden an Ihrem Prison-Plugin und
würden da etwas ändern und dann bauen Sie Ihr Bundle und das Bundle
stellt fest, dass Sie sagen, ich habe diese Abhängigkeit schon bei mir
liegen, dann passiert halt nichts.
Und deshalb müssen Sie noch zusätzlich diese Option setzen, dass da
immer die aktuellste Version tatsächlich kopiert wird.
Macht das Ganze ein bisschen langsamer, aber Sie sind sicher, dass Sie
am Ende etwas funktionierendes da haben.
Gut, das hatten wir auch schon, den ClassPathPrefix.
Und das haben wir, glaube ich, auch schon gesehen, dass wir alle
Abhängigkeiten nur haben wollen, die tatsächlich zur Ausführung auch
nötig sind.
Das heißt nicht die ganzen Test-Abhängigkeiten zum Beispiel mit drin
haben wollen.
Genau.
Oh, ich bin schon durch.
Wunderbar.
Gibt es noch Fragen zur Aufgabe 3 zum Bundle?
Irgendwas unklar geblieben?
Ja.
Ihr Kommilitone fragt, wie frei man ist hinsichtlich, ich gehe mal
davon aus, wie mein Maven-Plugins, die man benutzt, um Packages zu
stellen.
Ich nehme mal an, Sie machen das in Anspielung auf einen Forum-Post,
der gestellt wurde zu dem Thema.
Dann kann ich die Frage trotzdem beantworten in der Richtung.
Es wurde gefragt, ob man denn nicht einfach auch alles in die JAR
reinpacken könnte an Abhängigkeiten.
Das wäre doch viel einfacher, dann müsste man sich nicht Gedanken
darüber machen, wo man die JARs hinlegt und der Haupt-JAR nicht sagen,
wo sie im Grunde ihre Abhängigkeiten findet.
Das kann man natürlich tun, ist aber eigentlich keine gute Idee, weil
Sie bekommen dann sehr, sehr große JARs und es ist ziemlich
wahrscheinlich, dass Sie in unterschiedlichen JARs die gleichen
Bibliotheken verwenden.
Das heißt, die kopieren Sie dann mehrfach in JARs mit rein, kriegen
mehrfach sehr große JARs.
Das ist einfach unnötig.
Also Sie machen dann einfach Ihr ganzes Projekt größer, als es sein
müsste.
Ich weiß nicht, ob das das war, worauf Sie hinaus wollten oder ob Sie
noch ein anderes Package verwenden wollten, eine andere Option zum
Packagen verwenden wollten.
Also ja, das kann man tun.
Wir hätten das gerne nicht so, weil es wie gesagt eigentlich keine
gute Idee ist.
Gut, dann übergebe ich jetzt, wenn es keine weiteren Fragen mehr gibt,
wieder an Tobias.
Der darf sich um das Aktivitätsdiagramm kümmern.
Der hat die Aufgabe verbrochen, also darf es auch selber auslöffeln.
Ja, Wahnsinn.
Und darf Ihnen erklären, was er sich denn da vorgestellt hat, was man
denn hätte tun sollen.
Genau, gut.
Dann kommen wir zum Aktivitätsdiagramm.
Die Aufgabe war ein bisschen größer diesmal.
Ich glaube, eine der größten Aktivitätsdiagramm-Aufgaben, die wir
bisher hatten, so in den letzten Jahren.
Tobias ist ein Freund von Aktivitätsdiagrammen und er meinte, dieses
Jahr müssen wir mal ein richtiges machen.
Ich finde die toll, ich weiß nicht.
Diese Kindergarten-Diagramme.
Eben, also mal was Richtiges.
Vor allen Dingen auch nochmal ein bisschen aufarbeiten, was wir da
eigentlich in Geometricify gemacht haben.
Auch wenn es ein bisschen abstrahiert und ein bisschen einfacher ist,
was wir dort jetzt gemacht haben.
Es gibt mehrere Möglichkeiten, das Hauptdiagramm darzustellen.
Wir haben ja gefordert, dass Sie die beiden Unteroptionen, einmal
Dreieck berechnen und Differenz berechnen in anderen Diagrammen
machen.
Das ist jetzt erstmal das Hauptdiagramm.
Es ist eine Variante, denn man kann die Geschichte mit GUI und
Geometricify auch mit Partitionen lösen.
Da wir aber gefordert haben, dass Sie Eingabe, also Objekteingaben für
Geometricify haben, ist das hier die schönere Variante.
Denn Geometricify ausführen ist letztendlich auch eine Aktivität, die
man beobachten kann.
Ich hoffe, die zünden keine Atombombe.
Was war die Aufgabe?
Was sollte denn modelliert werden?
Na gut, der Text fängt eigentlich so an.
Nach Auswahl eines mit Geometricify zu bearbeitenden Bildes und
Festlegens der Iterations- und Beispielanzahl.
Ich glaube, das ist in etwa genau das, was hier oben dargestellt ist.
Das heißt, jede dieser Aktivitäten bildet einfach eine von den Sachen
ab, die wir hier im Text gesehen haben.
Dann haben wir auch schon danach den Übergang in Geometricify.
Also Geometricify wird danach ausgeführt.
Und wir übergeben dem Ganzen...
Ja, schade.
Wenn eine Atombombe drin ist, dann wollen sie nicht, dass du da
reingehst.
Was haben wir jetzt als Eingabe?
Wir haben hier natürlich das Bild, was wir eben eingelesen und
ausgewählt haben.
Und die beiden Parameter.
Einmal die Iterationsanzahl und einmal die Beispielanzahl, die
generiert werden soll.
Die Beispiele sind eigentlich nichts anderes als die Dreiecke, die wir
hier unten berechnen.
Wir haben nicht gefordert, dass Sie weiteren Objektfluss modellieren,
weil das Ganze sonst noch viel größer geworden wäre.
Natürlich, wenn man dieses Aktivitätsdiagramm sinnvoll umsetzen möchte
und alles abdecken möchte, müsste man jetzt diese Objektflüsse auch
noch weiter durchziehen durch das gesamte Diagramm.
Aber gehen wir erstmal den Kontrollfluss weiter durch.
Was haben wir dann jetzt, sobald wir in Geometrify sind?
Gut, wir erstellen erstmal ein leeres Ergebnisbild, was diese
Aktivität hier darstellt.
Und gehen dann über diese beiden Zusammenführungsknoten in die erste
Iteration.
In jeder Iteration wird jetzt eine bestimmte Anzahl von Dreiecken
berechnet.
Und auch für jedes dieser Dreiecke die Differenz berechnet.
Wenn noch weitere Dreiecke zu berechnen sind, machen wir weiter.
Und am Ende, wenn keine weiteren Dreiecke zu berechnen sind, wählen
wir das Dreieck mit der geringsten Differenz aus.
Haben wir dieses ausgewählt, fügen wir dieses dem Ergebnisbild hinzu
und überprüfen, ob noch weitere Iterationen auszuführen sind.
Ist dies der Fall, gehen wir wieder hier vorne rein, machen das Ganze
noch einmal.
Und ansonsten sind wir fertig mit der Ausführung von Geometrify.
Das heißt aber auch laut der Beschreibung, die wir hier hatten, ist es
nötig, dass man diese Schleifen hat.
Denn hier steht so etwas wie für jedes Dreieck wird die Differenz
berechnet.
Und in jedem Iterationsschritt.
Wenn man jetzt diese Schleifen hier nicht modelliert hat, dann ist es
keine korrekte Abbildung von dem, was man in diesem Aktivitätsdiagramm
darstellen möchte.
Als Ausgabe haben wir jetzt natürlich das Ergebnisbild und können dann
dieses Bild auch noch im Endeffekt anzeigen.
Gibt es hierzu erstmal Fragen?
Wer fand die Aufgabe schwer?
Ja, es ist schon relativ viel Arbeit gewesen und auch viel, wenn man
das erste Mal ein Aktivitätsdiagramm macht.
Darf ich dich kurz unterbrechen?
Ich habe da draußen auf dem Flur was gefunden.
Einen Martin.
Und noch viel besser, unser Martin, der hat auch noch die Ewaldbögen
dabei.
Wollen wir das vielleicht einfach nach dem Aktivitätsdiagramm machen?
Genau, wir würden nach dem Aktivitätsdiagramm dann mit der Ewald
beginnen.
Martin, du kannst ja vielleicht trotzdem schon mal rumgehen und schon
mal ausgeben.
Aber bitte noch kurz warten, bevor Sie anfangen.
Wenn ihr jetzt ausgibt, dann hört mir keiner mehr zu.
Doch, ich werde schon dafür sorgen.
Ich stelle mich mal da oben hin und gucke böse, so wie in der Klausur
immer.
Alles klar, viel Spaß.
Martin gibt jetzt schon mal die Ewaldbögen aus, aber bitte fangen Sie
noch nicht an, sondern hören Sie sich an, was Tobias zu sagen hat zum
Aktivitätsdiagramm, damit Sie, wenn Sie es schon vielleicht nicht
gemacht haben, dann wenigstens verstanden haben, wie es hätte gehen
sollen.
Denn das könnte auch für die Klausur mal wichtig sein.
Vermutlich, ja.
Gut, das ist jetzt das Hauptdiagramm gewesen.
Diese beiden komischen Symbole hier unten deuten jetzt darauf hin,
dass wir noch weitere Diagramme haben, die diese einzelnen Aktivitäten
weiter verfeinern.
Das war genau das, was Sie auch tun sollten auf dem Übungsblatt.
Fangen wir einmal mit Dreieck berechnen an.
Wenn Sie jetzt so eine neue Aktivität modellieren, müssen Sie auch
dort wieder Start- und Endknoten haben, denn man muss ja wissen, wo
das Ganze anfängt.
Je nachdem können Sie dort natürlich auch wieder Objekteingänge und
Objektausgänge haben.
Das haben wir jetzt aber in diesem Fall nicht gefordert.
Können Sie versuchen, trotzdem dabei leise zu bleiben?
Danke.
Was muss jetzt in Dreieck berechnen und durchgeführt werden?
Natürlich müssten erst einmal die drei Koordinaten für das Dreieck
berechnet werden und daraus das Dreieck zusammengesetzt werden.
Ob Sie das jetzt so genannt haben, wie ich das hier habe, oder
irgendeine andere äquivalente Aktivitätsbeschreibung, ist natürlich
für das gesamte Aktivitätsdiagramm...
Das Ganze ist nur ein Beispiel, wie man das Ganze lösen kann.
Es gibt verschiedene Varianten.
Das wird Ihnen Ihr Tutor dann aber auch noch mitteilen, wenn er es
korrigiert hat.
Auch hier haben wir jetzt wieder eine Schleife, denn wir iterieren
über die Pixel des Bildes und für jeden Pixel entscheiden wir, ob er
im Dreieck ist oder nicht.
Wenn er im Dreieck liegt, dann summieren wir die Farbwerte auf und
schauen dann halt, ob es noch einen weiteren Pixel gibt, den wir noch
nicht betrachtet haben.
Wir fangen wieder von vorne an.
Ist dies nicht der Fall, teilen wir die Summe der addierten Farbwerte
durch die Anzahl der Dreiecke und erhalten somit den
Durchschnittsfarbwert für dieses Dreieck.
Gibt es dazu Fragen?
Die Frage war, ob es auch gereicht hätte, die Schleife nicht
pixelweise, sondern blockweise zu machen.
Wie wollten Sie die Blockblöcke machen?
Sie hätten also jetzt hier nur eine Aktivität, die sagt, addiere alle
Farbwerte pixelweise auf.
Ich muss mal kurz den Text vorlesen, aber ich glaube, es ist relativ
klar, dass man das hätte nicht machen sollen.
Denn für jedes Pixel im Originalbild wird geprüft, ob sich das
aktuelle Pixel im Dreieck befindet.
Wie wollten Sie das dann modellieren in diesem Fall?
Das ist richtig, aber Sie sollten das abbilden, was hier in dem Text
steht.
Die Frage ist, wie hätten Sie diese Aussage, die ich gerade vorgelesen
habe, dann modelliert, wenn Sie das nicht in der Schleife gemacht
hätten?
Da hinten ist noch eine Frage.
Hast du es verstanden?
Magst du mal hochgehen?
Du bist doch gerade so schön am Laufen.
Also der Kommeditone fragt, ist es ein Problem, wenn man
Farbwertbestimmungen nochmal als extra kleines Unteraktivitätsdiagramm
macht, ich beantworte das mal kurz und schmerzlos, ich würde sagen
nein, wenn es dann richtig ist.
Grundsätzlich gilt, wenn Sie sich mehr Arbeit machen und es dann
trotzdem richtig ist, ist das völlig okay.
Wenn Sie meinen, dass die Darstellung dann besser wird, wenn Sie da
nochmal ein Unterdiagramm bauen, völlig okay.
Wie gesagt, das ist nur eine mögliche Modellierung.
Man kann auch sicherlich andere sinnvolle Aktivitätsdiagramme aus
dieser Beschreibung bauen.
Unsere Tutoren sind da auch angewiesen darauf zu achten, auf ihre
Sinnhaftigkeit überprüfen und nicht einfach nur die Musterlösung
abgleichen.
Noch eine Frage?
Ja.
Also die Frage war, die Schleife funktioniert jetzt so, dass erst die
Iteration durchgeführt wird und dann die Bedingung geprüft wird.
Ja, man kann das durchaus auch andersherum modellieren und es wäre
wahrscheinlich sogar sinnvoller.
Ja, also es geht beides auf jeden Fall.
Es ist im Aktivitätsdiagramm jetzt aber auch nicht so kritisch, wie
man das Ganze jetzt durchführt.
Denn du hast trotzdem ja beide Aktivitäten.
Es geht jetzt nicht darum zu modellieren, wie das möglichst performant
umgesetzt wird.
Aber eigentlich haben Sie recht, eigentlich wäre es andersherum.
Wäre dann halt eine andere Schleife.
Also dann hätten wir eine Wild-Schleife und so haben wir halt eine
Dual -Schleife.
Funktionieren würde in dem Beispiel, denke ich mal, beides.
Es gibt, glaube ich, keine Möglichkeit, dass man da sofort rauskommt,
oder?
Übersehe ich was?
Kann man jetzt darüber diskutieren, was sauberer ist?
Also wir lassen definitiv beides zu.
Gut.
Sonst noch Fragen zum Dreieck berechnen?
Okay, dann mache ich mal noch mit dem dritten Diagramm weiter.
Das ist tatsächlich gar nicht mal so unterschiedlich zu dem
vorherigen.
Differenz berechnen.
Was wird dort jetzt durchgeführt?
Zunächst werden die Farbwerte gemittelt zwischen dem alten Bild, also
dem momentanen Result-Bild, oder Ergebnis-Bild, und dem Dreieck, was
wir hinzufügen wollen.
Und erzeugen dann so ein Probeergebnis von diesem hinzugefügten Bild.
Das ist auch genau das, wie unsere Musterlösung auch von Geometryfile
funktioniert.
Funktioniert sie nicht, aber wie man es auch hätte machen können.
Gut, und dann iteriert man jetzt wieder über die Pixel und berechnet
die absoluten Differenzen.
Diesmal halt auf dem gesamten Bild.
Deswegen haben wir nicht mehr diese Verzweigung, die wir eben hatten.
Und addieren die Differenzen dann auch wieder auf und haben dann eine
absolute Summe im Endeffekt, die halt dann zurückgegeben wird.
Ist dazu Fragen?
Gut.
Allgemein noch Fragen zu Aktivitätsdiagrammen?
Irgendwas, was nicht klar ist mit der Darstellung, wie man das Ganze
aufbaut oder sonstiges?
Jetzt haben Sie die Chance noch zu fragen.
Ihren Tutor können Sie natürlich auch fragen, aber jetzt haben Sie
auch von uns noch ein bisschen Feedback.
Die Möglichkeit zumindest.
Ja, hier vorne.
Die Frage ist, ob sowas wie Summe initialisieren zum Objektfluss
gehört.
Naja, es ist eine Aktivität, das Initialisieren.
Dass die Summe dann danach auf einen Wert gesetzt ist, ist dann im
Objektfluss, aber das Initialisieren selbst ist eine Aktivität.
Das ist natürlich dann schon sehr feingranular, wenn Sie das gemacht
haben, aber das konnten Sie auf jeden Fall modellieren und das wäre
auch korrekt.
Gut, dann würde ich sagen, machen wir jetzt die Eval fertig.
Und danach darf Sebastian seine Lieblingsaufgabe noch vorstellen.
Das Sequenzdiagramm.
So, ich würde sagen, 10 Minuten zum Ausfüllen des Eval-Bogens.
Da gibt es noch eine Frage.
Wir haben noch keine Bögen.
Ah, da war unsere Eval-Fee wohl nicht so wirklich...
Ich glaube aber, jetzt sind welche angekommen.
Aber schön, dass du gelaufen bist, Martin.
Du hast wieder die Leute am Rande der Gesellschaft vergessen, Martin.
Nee, da am Rande.
Nochmal als Hinweis an Sie alle.
Sie können ruhig weiterschreiben, ich erzähle nur so nebenher.
Bitte evaluieren Sie nur die Übung.
Die Vorlesung wird extra evaluiert.
Also wenn Sie jetzt sagen, Übungsleiter doof, Professor Tischi toll,
dann hat das hier nichts zu suchen.
Dann schreiben Sie nur Übungsleiter doof und machen das Lob für
Professor Tischi dann in der Vorlesungseval.
Das gleiche gilt eigentlich auch für die Tutorien.
Da gibt es auch andere Möglichkeiten, das zu evaluieren, eben über die
Sternchenbewertung.
Also versuchen Sie sich tatsächlich hier auf den Übungsbetrieb zu
beschränken, wenn Sie evaluieren.
Gut, ich würde dann weitermachen mit der Übung, während hier noch die
letzten Blätter eingesammelt werden.
Zeitpunkt der EWAL war jetzt gar nicht schlecht.
Direkt vor der Sequenzdiagrammaufgabe.
Da kommt das große Stöhnen jetzt erst nach der EWAL, das ist auch gut.
Sonst hätten Sie jetzt gleich noch draufgeschrieben, diese
Sequenzdiagrammaufgabe, die war ja furchtbar.
Wer hat sich denn mit der Sequenzdiagrammaufgabe beschäftigt?
Wer hat die denn gelöst?
Oh ja, sehr schön.
Erstaunlich viele.
Finde ich sehr gut von Ihnen.
War auch tatsächlich nicht wirklich schwierig.
Aber ich gebe zu, man musste relativ viel zeichnen.
Aber es war eigentlich alles nach Schema F.
Was wir uns überlegt haben, was man ja mal machen könnte für so ein
Sequenzdiagramm, nicht immer diese, naja, sehr synthetischen Beispiele
mit irgendwie Nachrichten, die zwischen Mitarbeitern ausgetauscht
werden oder Sonstiges in Firmen, sondern wir haben uns gedacht, naja,
machen wir doch einfach unser Kommandozeilenwerkzeug, was wir eh
haben, da kann man doch bestimmt auch ein Sequenzdiagramm draus
zeichnen und haben eben diese Main-Methode mal hergenommen und haben
gesagt, bitte jetzt einmal Sequenzdiagramm dazu zeichnen.
Und naja, wir haben es ein bisschen vereinfacht, haben ein paar
Aufrufe rausgenommen, haben die Try-Catch-Blöcke rausgenommen, weil es
das ein bisschen schwieriger macht und haben dann gesagt, jetzt dürfen
Sie mal hier modellieren.
Und der Großteil ist eigentlich relativ einfach, es gab ein paar
kleinere Diskussionen darüber, wie machen wir denn jetzt statische
Aufrufe.
Naja, die sinnvollste Variante ist, man macht das einfach
unterstrichen, den Aufruf.
Eine andere Variante ist, bei der Klasse anzugeben, dass sie statisch
ist.
Wir lassen da alles zu, auch wenn Sie einfach die statischen Aufrufe
genauso modelliert haben, wie die nicht-statischen, ist das in dem
Fall okay.
Das schauen wir uns jetzt aber mal an.
Die zweite Schwierigkeit war, sich mal zu überlegen, was macht man
denn eigentlich bei solchen verschachtelten Aufrufen, wie wir sie hier
sehen, bei dem Create zum Beispiel für die Source-File.
Wie macht man das denn, wenn man dann hier plötzlich im Konstruktor
noch einen Methoden-Aufruf hat.
Aber auch dafür gibt es eine relativ einfache Lösung, schauen wir uns
das jetzt mal an.
Das ist so, wie wir uns das gedacht haben.
Wir haben tatsächlich noch die JVM als Extra-Klasse modelliert.
Muss man aber nicht machen, man kann auch hier einsteigen, bei der App
direkt, und im Grunde hier diesen Aufruf von Unbekannt, den kann man
auch da dran setzen, das wäre auch okay.
So haben wir das modelliert und jetzt kommt der erste Aufruf.
Das Vergleich, eine erste kleine Klippe, nämlich der Selbstaufruf, das
Do -Command-Line-Parsing, ruft eben auf der App sich selber auf und
erzeugt dann irgendwie dieses cmd-Objekt.
Das muss irgendwie passieren, weil hinterher ist es da, also müssen
sie es dort auch irgendwie erstellen.
Wir haben ja gesagt, sie müssen das Do-Command-Line-Parsing selber
nicht modellieren, aber sicher ist ja, hinterher ist dieses cmd-Objekt
da, das heißt es muss hier auch irgendwie auftauchen und vorher war es
noch nicht da.
Gut, jetzt kommt genau der Punkt, wie machen wir das denn jetzt mit
diesen geschachtelten Aufrufen?
Die Antwort ist, wir entschachteln sie.
Das haben wir teilweise schon gemacht, als wir den Spelltext angepasst
haben.
Ein paar von diesen Stellen haben wir aber für sie dagelassen und so
hier geschehen bei dem Aufruf an die Command-Line mit der Option, die
ausgelesen werden sollte, wo denn die Input-Datei zu finden ist.
Das heißt, man macht einen Aufruf an dieses cmd-Objekt und bekommt
dann eine temporäre Variable zurück, die man dann später weiter
benutzen kann und damit erstellt man dann die Quelldatei.
Hier sehen sie auch, wie man denn den Konstruktor aufruft, das sollte
aber auch klar sein, das haben wir glaube ich sogar auch gezeigt, als
wir das Sequenzdiagramm besprochen haben.
Dann benutzt man eben diesen StereotypeCreate.
Wir haben hier noch mit angegeben, wie der Konstruktoraufruf aussehen
soll, einfach deshalb, weil wir hier die temporäre Variable mit
benutzen.
Wenn jetzt jemand sagt, das habe ich so aber nirgendwo im Internet
gesehen, ja, mag sein.
Die Beispiele, die man so findet, sind aber immer nur einfache
Konstruktoren ohne irgendwelche Parameter.
Und um L lässt es zu, auch sowas zu bauen, einen Stereotyp anzugeben
und dann eben auch noch den Konstruktoraufruf hintendran zu schreiben.
Wenn sie das nicht getan haben sollten, sind wir sicherlich da auch
großzügig und das wird, wenn überhaupt, dann einmal zu einem kleinen
Abzug führen, aber sicherlich nicht an jeder Stelle.
Gut, jetzt gleich der nächste spannende Punkt.
Wie machen wir das jetzt mit diesem Read in dem ImageIO, um das Bild
auszulesen?
Wir machen diesen statischen Aufruf, sehen wir jetzt gleich hier,
statisch, daher unterstrichen.
Das ist also eine Möglichkeit, um das zu modellieren.
Wie gesagt, wenn Sie es nicht getan haben, auch völlig okay.
Aber so wäre eigentlich die oder eine der richtigen
Modellierungsmöglichkeiten für statische Aufrufe an unsere Klasse
ImageIO und die wiederum erzeugt das Bild.
Das heißt, der Create-Aufruf kommt in dem Fall von ImageIO und erzeugt
das Bild und am Ende dieses Aufrufs wird das Bild an unsere
Hauptmethode zurückgegeben.
Gut, dann die Iteration holen.
Das funktioniert nach dem gleichen Prinzip wie hier oben mit dem...
Es gibt eine Frage.
Warum ist main.of.app kein Static-Aufruf?
Gute Frage.
Müsste es sein, ne?
Also, ihr Kommilitone fragt, müsste das hier oben nicht eigentlich ein
Static -Aufruf sein und müsste das hier nicht eigentlich dann auch
einfach die Klasse sein?
Ja, könnte man so modellieren.
Ich bin mir nicht sicher, ob man es sollte, sage ich mal so.
Also ja, der statische Aufruf sollte man dann auf jeden Fall so
machen.
Die App würde ich persönlich trotzdem als anonymes Objekt modellieren.
Das ist auch der Grund, warum mir die Variante mit den statischen
expliziten Aufrufen besser gefällt als Aufrufe an statische Klassen,
weil eine ganze Klasse muss ja nicht alles statisch sein.
Das heißt, wir wollen ja eigentlich genau das unterscheiden können,
dass wir einmal statische Aufrufe haben und einmal nicht-statische
Aufrufe.
Dementsprechend würde ich es eigentlich so modellieren, wie es hier
steht, bloß dass eben das main noch zusätzlich unterstrichen ist.
Gut.
Sonst noch Fragen bis hierher?
Gut.
Wie gesagt, das Auslesen der Iterationen funktioniert nach dem
gleichen Prinzip wie das der Eingabe-Datei.
Wir haben hier wieder einen statischen Aufruf auf der Integer-Klasse
und das Ganze machen wir noch für die Samples.
Und da sind wir dann auch schon mit dem ersten Teil durch.
Relativ viel zu modellieren bis hierher, aber eigentlich nicht
kompliziert, denke ich.
Und das Gute ist, auf der zweiten Seite wird es noch einfacher.
Irgendjemand hat nicht aufgeräumt, sehe ich hier gerade.
Nicht die aktuelle Version.
Jetzt funktionieren meine Einbindungen nicht.
Wer rät denn mal, wofür denn da unten dieser Pfeil da ist?
Welcher Aufruf ist das?
Jemand eine Meinung?
Ne, ich weiß es auch nicht.
Gut.
Schauen wir einfach mal, wo uns das Ganze hinführt.
Also, wir haben bisher so weit uns durchgearbeitet, dass wir uns die
Iterationen und die Samples geholt haben.
Was kommt als nächstes?
Naja, Höhe und Weite des Bildes holen.
Das machen wir eben auf unserem Eingabe-Bild.
Ich glaube, das ist ganz einfach.
Und dann erzeugen wir einen Random Point Generator.
Auch hier haben wir wieder unseren Konstruktoraufruf so modelliert,
dass wir eben etwas übergeben können.
Für den Filter geht das gleiche.
Da übergeben wir den Random Point Generator mit.
Wem ist denn hier was aufgefallen?
Wir haben in der Aufgabe ein kleines Osterei versteckt.
Zur falschen Jahreszeit.
Keine?
Keine einer?
Gibt man das Gefühl, dass da irgendwas falsch ist?
Da meldet sich jemand.
Ah, ihr Kommilitone sagt, da steht Rectangle Picture Filter.
Wir hatten doch bisher nur Triangle Picture Filter.
Das ist genau das, was in der Aufgabe falsch ist oder anders ist.
Das ist der Hinweis für Sie, was als nächstes auf Sie zukommt.
Wir werden uns im nächsten Übungsblatt noch mit anderen Formen
beschäftigen.
Es wird dann noch Rectangles geben und Kreise usw.
Insofern haben Sie jetzt schon mal den Hinweis, was noch so kommt.
Das haben wir hier schon mal drin gehabt.
Schade, dass es keiner gefunden hat.
Aber jetzt haben wir es wenigstens in der Übung geklärt.
Was müssen wir noch machen?
Wir müssen jetzt noch unseren Filter ausführen mit der Apply Methode.
Die Apply Methode erzeugt wiederum das Ausgabebild.
Ah, hier gehört also der Pfeil dazu.
Wir müssen uns ja noch holen, wo wir den eigentlich speichern wollen.
Und das machen wir wieder genauso wie schon gesehen.
Indem wir uns eben diese Option, diese temporäre Variable erstellen,
die Outfile heißt.
Und dann das zu speichernde Bild bzw.
die Datei dafür anlegen.
Und ganz am Ende müssen wir es eben noch an Image.io weiterreichen,
was dann wiederum die Zieldatei schreibt.
Gut.
So einfach war das Ganze.
Gibt es noch Fragen bis hierher?
Ah, Tobias meint, da fehlt noch ein Pfeil.
Irgendwas habe ich vergessen.
Ja, da unten.
Also wir müssen ja auch irgendwie noch wieder zurückkehren.
Gut, da gibt es eine Frage.
Mal kurz gucken.
Wir haben recht, die Sourcefile wird nie benutzt.
Also ihr Kommilitone fragt, was ist denn mit Objekten, die nie benutzt
werden im Sequenzdiagramm?
Also ich von meiner Seite würde das auch zulassen, wenn sie das nur
als quasi temporäre Variable modelliert hätten.
Eigentlich macht man das nur für komplexe Datentypen eher nicht.
Das ist der Grund, warum wir das so gemacht haben.
Aber sie haben recht, es ist ja eigentlich an der Stelle witzlos, das
zu tun, weil es gibt ja eh keinen Aufruf dahin.
Insofern würden wir das auch zulassen, ja.
Müssen wir aber trotzdem das Create irgendwie modellieren?
Das ist natürlich wahr.
Das Create muss natürlich trotzdem da sein.
Dann wird es schwierig darzustellen.
Ja, das ist wahr.
Da wüsste ich jetzt auch nicht, wie man das dann tun sollte, ehrlich
gesagt.
Selbstaufruf, da müsste ich mal drüber nachdenken, ob das Sinn macht,
ehrlich gesagt.
Also ja, sie müssen ja die Datei, das Objekt auf jeden Fall erstellen
mit einem Selbstaufruf.
Aufruf ist ja nicht korrekt, weil es ist kein Aufruf auf der Klasse.
Der Create-Aufruf ist ja auf der Klasse, die du erstellst.
Ja, das ist eigentlich ein guter Grund, das dann doch nicht zu tun,
ja.
Okay, sonst noch Fragen?
Hier ist noch eine Frage.
Ihr Kommilitone fragt, wo wird denn eigentlich diese ominöse Integer
-Klasse verwendet?
Naja, die brauchen wir, um unsere Eingabe zu parsen.
Ihr Kommilitone fragt, wir müssen nicht am Ende alles explizit
zerstören, weil der Garbage-Collector wird das schon für uns tun.
Das ist genau die richtige Antwort.
Man würde das im Diagramm nur tun, wenn man das explizit irgendwo
tatsächlich tut.
Wir wissen ja auch nicht an welcher Stelle das wann wie passiert, wann
der Garbage-Collector aktiv wird.
Insofern würden wir das hier nicht modellieren.
Gut, sonst noch Fragen?
Keine mehr?
Ah, da kommt ja noch eine Aufgabe, die habe ich ja ganz vergessen.
Verrückt.
Wunderbar, jetzt kommt ja tatsächlich meine Lieblingsaufgabe.
Substitutionsprinzip.
Kurze Frage, wer hat die Aufgabe gemacht?
Drei leicht verdiente Punkte?
Ja, sehr schön.
So wollte ich das, damit Sie sich alle mal damit beschäftigen.
Gut, das war die Aufgabenstellung.
Ich habe das einfach mal genauso vom Übungsblatt hier in die Folien
gezogen.
Es ging darum, dass wir vier Klassen haben, jeweils wieder die
voneinander erben.
Wir haben eine Rockband und wir haben eine Grungeband, die voneinander
erben.
Also die Grungeband ist in dem Fall die Spezialisierung.
Und wir haben hier einen Radiosender und die Spezialisierung
Rocksender.
Das sieht so ein bisschen aus wie unser Schwaben-Spätzle-Beispiel aus
der Vorlesung.
Und das ist durchaus gewollt.
Das sollte eine gewisse Ähnlichkeit haben, damit Sie sich ein bisschen
daran orientieren können.
Was wir jetzt gefragt haben, waren drei Fragen.
Nämlich A, erfüllt das hier, was Sie hier sehen, das
Substitutionsprinzip?
Die zweite Frage war, können wir das umsetzen in JavaCode?
Und die dritte Frage war, ob die Methode Spiele in dem Rocksender die
Radiosender -Methode überlädt oder überschreibt?
Gut, das waren die drei Fragen.
Ich sage es mal so, die erste ist die spannendste davon, nämlich die
zum Substitutionsprinzip.
Mal eine kurze Meinungsumfrage.
Wer ist denn der Meinung, dass das Substitutionsprinzip hier erfüllt
ist?
Ich habe gestern mal ein paar Lösungen angeguckt, das waren ziemlich
viele, die der Meinung sind.
Kann jetzt nicht so ganz so stimmen.
Wer ist denn der Meinung, dass es verletzt wird?
Und der Rest hat keine Meinung.
Ja genau.
Wer ist sich denn nicht so sicher?
Das sind auch ein paar.
Das ist okay bei der Aufgabe, es ist tatsächlich nicht so auf den
ersten Blick zu sehen, was das Problem sein könnte.
Aber vielleicht ist es ja auch einfach erfüllt, vielleicht haben ja
auch die wenigen recht.
Schauen wir uns das mal im Detail an.
Was müssen wir denn anschauen?
Wir müssen uns zunächst mal anschauen, wie ist das denn mit der
Kontravarianz bei den Eingabeparameter und der Kovarianz bei den
Ausgabeparameter.
Sie erinnern sich, Schwaben können mal Nudeln essen, wenn die
Württemberger dafür Spätzle essen.
Kontravarianz bei den Eingabevergabeln.
Und bei den Rückgabevergabeln war es gerade genau umgekehrt.
Da ist die Kovarianz das, was passiert.
Man kann von einem Württemberger verlangen, dass er Nudeln zurückgibt
und vom Schwaben dann, dass er Spätzle zurückgibt.
Für alle, die es nicht sehen, Martin schüttelt gerade unglaublich den
Kopf.
Ich muss hier die Schwaben-Ähre hochhalten und sagen, Spätzle sind
einfach keine Nudeln.
War bei uns aber so, Martin, da musst du jetzt mit leben und du hast
kein Mikro, also kannst du dich nicht wehren.
Jetzt schauen wir nochmal zurück.
Wie ist das denn hier?
Wir haben hier bei dem Radiosender, hier haben wir ja offensichtlich
keine Methoden, wir haben aber hier beim Radiosender als
Eingabevariable die Crunchband und beim Rocksender die Eingabe
Rockband in der Spiele-Methode.
Ist das okay?
Kommilitone, möchtest du was sagen?
Kommilitone sagt Kontravarianz, also okay.
Stimmt.
Wie sieht das denn bei den Ausgabetypen aus?
Gehen wir nochmal zurück.
Ausgabe wäre hier beim Rocksender Crunchband und hier beim Radiosender
Rockband.
Ist das okay?
Einer nickt, den nehme ich jetzt mal.
Ja, auch das ist okay.
Und das verleitet vielleicht den einen oder anderen zu sagen, da ist
das Substitutionsprinzip auf jeden Fall schon erfüllt.
So ganz so einfach war es aber nicht.
Wir müssen uns auch noch ein bisschen um das Verhalten kümmern.
Und das ist jetzt der spannende Teil, den wir uns jetzt mal im Detail
anschauen, denn das ist vielleicht nicht auf den ersten Blick klar.
Und weil es uns immer in der Vorlesung so viel Spaß macht, habe ich
gedacht, bringe ich mal einen kleinen Passer dazu mit.
Wir haben einfach mal genau dieses Beispiel in Java hingeschrieben.
In Klammern, das beantwortet gleich Aufgabe B.
Ja, man kann das einfach genauso in Java hinschreiben.
Ich hoffe, das hat vielleicht sogar der eine oder andere ausprobiert,
weil man sieht, das ist nicht besonders viel.
Was wir jetzt noch getan haben, um den Effekt zu zeigen, ist, wir
haben hier in die Grungeband und in die Rockband noch eine Playsender
-Methode eingefügt, die nichts anderes macht, als auf dem Sender das
Spiel aufzurufen.
Und Sie sehen, die sind exakt gleich implementiert, also die machen
schon mal nichts kaputt.
Hoffentlich glauben Sie mir jetzt einfach mal.
Das ist nur dabei, damit man sieht, was passiert.
Auf der rechten Seite haben wir noch zu den Methoden gesagt, naja,
gebt halt aus, was ihr seid.
Wenn du ein Rockband spielst, dann sag halt hier, wenn du ein
Radiosender bist, dann sag, ich spiele Radio, oder wenn du ein
Rocksender bist, dann sag, ich spiele Rock.
Das ist das, was hier passiert.
Dazu haben wir noch eine Main-Methode in dem Rocksender gebaut, hätten
wir auch überall anders tun können.
Und was jetzt hier passiert ist, wir bauen uns eine Rockband und
initialisieren die als eben diese Rockband.
Und übergeben wir ihr dann einen Rocksender und spielen es ab.
Und dann machen wir aus dieser Rockband eine Grungeband und setzen
wieder den Rocksender und spielen den wieder ab.
Das ist also genau das, was man eigentlich erwarten sollte, was laut
Substitutionsprinzip funktionieren sollte.
Wenn denn die Klassen, die wir gerade gesehen haben, dem
Substitutionsprinzip genügen, sollte genau sowas möglich sein, dass
wir im Grunde erst das Ganze einmal mit der Rockband durchtanzen und
dann nochmal mit der Grungeband durchtanzen.
Das ist genau das Gleiche, was wir schon gesehen haben bei den
Schwaben und den Baden-Württembergern.
So, jetzt ist die Frage, was passiert jetzt?
Also die Varianten da oben sind eigentlich Rock, Rock und ja, wir
brauchen eigentlich nur die eine davon.
Wir haben das ein bisschen umgestellt und vergessen, das anzupassen.
Die Frage ist, was wird jetzt ausgegeben?
Wird jetzt zweimal Radio ausgegeben?
Wird das ausgegeben, was man erwarten würde, nämlich Radio, Radio,
Rock?
Oder wird etwas völlig anderes ausgegeben?
Oder gibt es vielleicht sogar einen Laufzeitfehler?
Was könnte denn hier passieren?
Ah ja, Tobias gibt mir gerade den richtigen Hinweis.
Wir haben natürlich hier zwei Rocksender und die Rocksender, die
spielen halt nur Rock, so wie sich das für Rocksender gehört.
Das heißt, hier müsste dann Rock, Rock stehen.
Also falls Ihnen das bei der Entscheidungsfindung hilft, da sollte
Rock, Rock stehen.
Gut, wer hat denn die Meinung, dass hier oben Rock, Rock ausgegeben
wird?
Keiner?
Wer ist denn der Meinung, dass Radio Rock ausgegeben wird?
Auch keiner?
Doch, da oben ist einer, sehr schön.
Wer ist denn noch einer?
Wer ist denn der Meinung, dass etwas komplett anderes passiert?
Also irgendwas anderes ausgegeben wird, vor allen Dingen.
Okay, wer ist denn der Meinung, dass es einen Laufzeitfehler gibt?
Auch keiner, gut.
Doch vier, das ist die Mehrzahl.
Also wir haben jetzt hier unter geschätzten 150 Leuten ein Ergebnis
von 4 zu 1 zu 1.
Bitte?
137?
Ah, Martin hat gezählt, sehr gut.
Also Sie sind heute 137, wenn Sie es genau wissen wollten.
Das brauchen wir nämlich für die E-Wahlbögen.
Gut, einer von den vier Leuten, die sich gemeldet haben beim
Laufzeitfehler.
Hat jemand eine Ahnung von Ihnen warum?
Was ist hier kaputt?
Wunderbar.
Ihr Kommilitone gibt die vollkommen richtige Antwort, die ich jetzt
nochmal ein bisschen ausführlicher wiederhole.
Was passiert?
Wir haben hier die Grungeband, die die Klasse Rockband erweitert.
Und was die macht ist, sie hat hier ein eigenes Senderattribut.
Das heißt, wir haben hier Verdeckung.
Und das ist auch etwas, auf was Sie achten müssen, wenn Sie sich um
das Substitutionsprinzip kümmern.
Habe ich irgendwo verdeckte Variablen oder verdeckende Variablen?
Und das ist genau das, was hier kaputt ist.
Also verdenken hier Radiosender und hier Rocksender überdeckt den
Sender hier oben.
Und was jetzt passiert hier in der Main ist, wenn Sie hier die neue...
Also hier oben funktioniert alles wunderbar bis hierhin.
Wir legen uns eine Rockband an, wir legen uns einen neuen Rocksender
an, setzen den in der Rockband und spielen den Sender ab.
Das heißt, was wir zuerst ausgegeben bekommen ist einmal Rock.
Und was dann passiert ist, wir setzen dann unsere Rockband auf die
Grungeband.
Und wenn wir dann hier zugreifen auf den Sender, greifen wir
eigentlich wieder auf den Sender in der Rockband zu.
Weil wir ja hier ursprünglich ein Rockband angelegt hatten.
Das einfach daran liegt, dass die Attribute statisch gebunden werden.
Und jetzt haben wir genau das Problem, das Attribut ist statisch
gebunden, ist also immer noch auf Null.
Aber jetzt führe ich Playsender aus, dynamische Polymorphie.
Jetzt führen Sie die Playsender-Methode in der Grungeband aus.
Und das hat zur Folge, dass die auf Ihren Sender zugreifen möchte,
aber der ist Null.
Also ein ganz gemeines Beispiel für Substitutionsprinzip.
Und dass man eben auf mehr achten muss, als nur auf Ho- und
Kontravarianz bei Ein- und Ausgabe-Parametern.
Allen klar, was hier passiert?
Oder habe ich Sie jetzt alle völlig überfahren mit der Aufgabe?
Wer hat es denn genau so gelöst und richtig begründet?
Bei einem weiß ich es.
Noch jemand, der es genau so aufgeschrieben hat, wie ich das jetzt
gerade erklärt habe?
Bloß vielleicht ein bisschen kürzer, weil ich zum Schwafeln neige.
Keiner?
Schauen wir mal, was die Ergebnisse des Übungsblatts sagen.
Gut, das war also der spannende Teil.
Hier ist eine mögliche Behebung, wie man noch zugreifen könnte auf das
Attribut in der Unterklasse, indem wir einfach einen Cast machen auf
Grungeband und dann können wir das natürlich setzen.
Aber man kann es auch einfach gleich richtig machen.
Nämlich den Sender private machen und Getter und Setter dazu und dann
hat man das Problem nicht mehr.
Also hier wieder aufgepasst.
Schon wieder der nächste Hinweis.
Geheimnisprinzip hilft an der Stelle auch, um das Substitutionsprinzip
zu erfüllen.
Gut, wunderbar.
Ah ja, genau, wir hatten noch eine Aufgabe C.
Wir haben ja gesagt, B haben wir jetzt schon mitgelöst, weil
offensichtlich können wir das auch hinschreiben in Java.
Aufgabe C war jetzt noch, wird denn jetzt in Java überschrieben oder
überladen?
Und es ging um die Spiele-Methode in dem Rock-Sender.
Wer ist denn der Meinung, dass hier überladen wird?
Okay, wer sagt, nee, ist doch Vererbung, ist überschrieben?
Okay, einer.
Gut, die richtige Antwort ist tatsächlich überladen, weil wir in
diesem Fall eine, vielleicht sage ich das noch vorneweg, wäre es
alleine um die objektorientierte Modellierung gegangen, dann wäre hier
überschreiben die richtige Antwort gewesen.
Also in dem Diagramm, ja, ist das einfach eine überschreibende
Methode, aber wenn wir das in Java machen, eben nicht.
In Java ist das Überladung und das liegt daran, dass Java sagt, wenn
wir etwas an der Signatur ändern und das tun wir, wenn wir
Kontravariante -Eingabe-Parameter benutzen, dann führt das zu einer
Änderung der Methodensignatur und dann sagt Java, Methodensignatur
geändert, wir haben hier Überladung.
Das heißt, Sie können die Methode ganz genau so hinschreiben in Java
und wenn Sie dann Override drüber schreiben, dann meckert Ihre IDE und
sagt, da wird doch gar nichts überschrieben und dann machen Sie es weg
und stellen fest, okay, dann ist es halt Überladen.
Gut, das war die Aufgabe 6c, damit sind wir durch mit dem Übungsblatt.
Gibt es noch Fragen zur Übung, sonst würde es jetzt noch ein bisschen
Vorlesung geben.
Vielleicht auch noch hier hinten noch der Hinweis, das Ganze gilt
nicht für die Ausgabe-Parameter.
Also Sie erinnern sich, Kovarianz bei Ausgabe-Parametern ist ja
zulässig und auch in Java führt es nicht dazu, dass die Methode
plötzlich nicht mehr überschrieben ist, sondern überladen.
Das ist völlig okay, das kann man also tun.
Gut, noch Fragen bisher?
Ich habe, glaube ich, eine Wortmeldung gesehen.
Ja.
Ich bin mir relativ sicher, dass das Java dabei stand.
Vielleicht dann erstmal, okay, also Comeditone sagt, steht drin,
Tobias ist leider langsamer, aber der hat auch eine alte Version vom
Blatt, der braucht gar nicht gucken.
Also Comeditone sagt, am Ende steht in Java.
Ich glaube auch, das extra genau deshalb noch hinzugefügt zu haben.
Ich wiederhole jetzt mal ausnahmsweise nicht, was ihr Comeditone
gesagt hat.
Gut, also haben wir das auch geklärt.
Es war tatsächlich nach Java gefragt.
Gut, noch eine Frage?
Ja.
Ihr Comeditone sagt, wenn wir Setter bauen, dann hätten wir covariante
Eingabe -Typen in der Grunge-Band.
Richtig.
Genau, und das wäre nicht zulässig.
Hat er damit recht?
Ich vermute, das hat er.
Nein, haben wir nicht.
Wir können doch beides mal den Rock-Sender verwenden, so wie wir das
hier auch getan haben.
Das heißt, wir haben einfach invariante Eingabe-Typen in dem Fall.
Glück gehabt.
Gut.
Hinten ist noch eine Frage.
Noch eine Frage?
Ja.
Ihr Comeditone sagt, wir haben, wenn wir Getter und Setter haben,
sowohl Contra- als auch Kovarianz für dieses Attribut.
Da muss ich gerade mal drüber nachdenken.
Ich muss mal kurz schauen, wie unsere ursprüngliche Modellierung war,
ob das ein Problem gibt.
Wir haben hier den... Ah ja, in der ursprünglichen Implementierung
haben Sie sogar recht.
Dann ist auch der Hinweis von Ihrem Comeditonen vorher schon richtig.
So wie es hier steht, würde es dann mit Gettern und Settern nicht
funktionieren.
Wir müssten uns dann halt also darauf einigen, ob wir entweder einen
Radiosender oder einen Rock-Sender haben.
Dann hätten wir Invarianz, dann ist es unproblematisch.
Genau.
Gut.
Sonst noch Fragen zu der Aufgabe?
Oder insgesamt Fragen.
Hat sich schon jemand das neue Übungsblatt angeschaut?
Gibt es dazu vielleicht schon Fragen?
Ich glaube, mit der Vorlesung anfangen...
Ich wollte gerade sagen, Sie haben jetzt so erfolgreich Fragen
gestellt, dass wir nicht mehr mit der Vorlesung weitermachen können.
Sehr, sehr kluge Strategie.
Deshalb jetzt die Möglichkeit, vielleicht noch weitere Fragen zu
stellen.
Sonst stelle ich die Frage, wer hat denn schon das neue Übungsblatt
angeschaut?
Gibt es einen Zusammenhang zwischen weiter vorne sitzen und früher das
Übungsblatt anschauen?
Kann das sein?
Irgendwie schon, ja.
Sie kriegen es früher.
Ach ja, stimmt.
Wir geben das ja immer von vorne nach hinten durch.
Okay.
Hat jemand dazu eine Frage?
Also wie Sie vielleicht gesehen haben, geht es jetzt daran, dass Sie
noch ein bisschen mehr mit Swing und GUI-Elementen rumbasteln müssen.
Das heißt, Sie bauen jetzt eine grafische Benutzeroberfläche für unser
Geometrify.
Das heißt, Sie werden sich ein bisschen in Swing befassen müssen, um
das Ganze durchzuführen.
Du bist ein bisschen leise.
Okay, dann spreche ich weiter.
Also was Tobias sagen wollte, war, Sie müssen sich ein bisschen mit
Swing beschäftigen, damit Sie das Übungsblatt lösen können.
Von mir vielleicht noch der Hinweis, es lohnt sich dieses Mal die
Bonusaufgaben anzuschauen, weil es gibt ziemlich viele Punkte dafür.
Und insbesondere die Bonusaufgabe mit den fünf Punkten, die ist, sagen
wir mal, interessant.
Also wer sich gerne austobt mit, ich möchte mal was effizient
implementieren, der kann das da tun.
Jetzt gibt es tatsächlich zwei Fragen.
Bitte?
Ja.
Einmal mit einem L und einmal mit zwei L.
Ich glaube mit...
Die LEZ merkt das gar nicht.
Insofern, aber...
Also wer das Übungsblatt geschafft hat, gestern innerhalb der ersten
fünf Minuten runterzuladen, es gibt eine neue Version mit einem
zweiten Hinweis, wie man denn diese Bonusaufgabe lösen kann.
Wie gesagt, ich glaube nicht, dass das passiert ist, weil die erste
Version war nur fünf Minuten online.
Und dann ist uns aufgefallen, dass es vielleicht ein bisschen
schwierig wird für Sie, das sinnvoll zu lösen, wenn Sie diesen Hinweis
nicht bekommen und deshalb haben wir den noch dazu geschrieben.
Ah ja, noch was Schönes.
Die, die jetzt gerade gehen, die haben es richtig gemacht.
Die können nämlich von mir nicht mehr verknackt werden.
Ja, schön, tschau.
Die anderen, wer war denn schon mal bei der Evaluationsstelle?
Keiner.
Ah doch, ja wunderbar.
Nein, die Sache ist, wir brauchen für die Evaluationen jemanden, der
die Bögen abgibt, weil wir dürfen das nicht machen, weil sonst suche
ich mir nachher wieder den geknitterten Bogen raus und lese mal durch,
was der Kommilitone über mich geschrieben hat.
Deshalb muss das jemand von Ihnen machen.
Wer würde sich denn da freiwillig anbieten?
Zwei aus der gleichen Ecke?
Wer möchte, einigen Sie sich drauf?
Sie möchten, okay.
Das ist sehr nett von Ihnen, vielen Dank.
Gut, sonst noch Fragen, Anmerkungen, Wünsche?
Auch gut.
Dann, schönes Wochenende.