Programmierung im Sommersemester 16, heute werden wir uns
eines Themas widmen, das da heißt Vertragsmodell.
Ich habe den Begriff letzte Woche schon mal kurz genannt,
am Ende dieser Vorlesung werden sie wissen, was das bedeutet.
Wir werden auch so einen kleinen Ausflug machen in Richtung theoretische Informatik. Nicht,
dass ich so behaupten würde,
dass ich mich da besonders gut auskennen würde,
aber sie hören ja auch Lehrveranstaltungen zu diesem Thema und diese Vorlesung ist so eine gewisse,
hat eine Nahtstelle dazu,
dazu dann im Einzelnen
später mehr
So, wo sag mal? Der erste Satz auf
dieser Folie ist ja sowas wie ein Programm.
Also wenn ich jetzt ein Programm im Sinne von einem Java-Programm,
sondern ist so eine Art Aufforderung an Sie.
Also was wir schreiben wollen, sind Wiederverwendbare,
Erweiterbare und änderbare Softwarebausteine, als wäre das nicht schon Herausforderung genug,
der wir nur allzu oft nicht genügen.
Nein, nein, jetzt kommt noch ein zusätzliches Merkmal hinzu,
dass unsere Software erfüllen soll. Sie soll zuverlässig sein.
Würde man eigentlich denken, ob das noch selbstverständlich ist?
Braucht man gar nicht drüber sprechen. Ja,
Software und auch leider Gottes vermutlich die von Ihnen geschriebene,
nicht immer zuverlässig ist, wollen wir uns mal so ein paar Techniken anschauen,
wie man das hinbekommen kann, dass sie eben Software,
auch dieses Qualitätskriterium erfüllt.
Zunächst mal, wir sind ja hier an einer Universität,
da spielen Begriffe eine besondere Rolle, Begriffe wollen definiert sein
und was würden sie denn und wollen wir denn deswegen mal unter Zuverlässigkeit verstehen.
So, der Herr Meier, der dann zitiert wird,
der Throme je für die Frankophilen unter ihnen,
ist so einer unserer großen Altforderen in der Softwaretechnik.
Der hat sich also sehr viel über dieses Thema,
der hat sehr viel über dieses Thema publiziert,
der sagt also Zuverlässigkeit ist durch zwei Eigenschaften,
kann die
hergestellt werden
Da ist zum einen die Frage der Korrektheit von Software und zum anderen die Robustheit.
Korrektheit ist also die Eigenschaft oder die Fähigkeit von Software,
das zu tun, was sie tun soll.
Und das ist immer im Zusammenhang mit einer Spezifikation,
kann Korrektheit betrachtet werden. Also man spezifiziert,
was eine Software tun soll und die Software ist dann korrekt,
wenn die Software genau das tut,
was vorher spezifiziert worden ist.
Die andere Eigenschaft,
die Zuverlässigkeit auszeichnet,
ist Robustheit
Das ist eine interessante Eigenschaft, weil die sind alle interessant,
diese Eigenschaften, aber die ist insofern interessant,
als dass es Zustände, Umstände geben kann,
also die nicht durch die Spezifikation abgedeckt worden sind.
Und in diesen Momenten muss eine Software in der Lage sein,
widerstehen, angemessen darauf zu reagieren.
Angemessenheit bedeutet in der Regel, dass sie nicht einfach abstürzt.
So sollte etwas angemessener, eine an die Software sollte
eine angemessenere Reaktion zeigen
Und jetzt sind diese Begriffe, also Zuverlässigkeit wird jetzt in einen Kontext gebracht mit Korrektheit und Robustheit.
Jetzt müssen wir uns, wenn es um Korrektheit geht,
mal kurz mit dem Konzept der Verifikation auseinandersetzen.
Korrektheit ist also die Frage, die hier im Raum steht,
ist, wie kann ein Zusammenhang zwischen einer Spezifikation hier als Modell A bezeichnet und einem Modell B hergestellt werden? So,
der Vorgang, der dazu gebraucht wird,
ist die sogenannte Verifikation und die Verifikation,
also funktioniert dann besonders gut,
wenn also das Modell A formal definiert ist,
also wenn eine formale Spezifikation im Idealfall eine mathematisch basierte Spezifikation vorliegt,
weil dann kann man einen Zusammenhang zwischen dem Modell A mathematisch definiert und dem Modell B zum Beispiel ein Programm in einer Programmiersprache so herstellen,
dass die Verifikation nachweist,
formal beweist,
dass das Modell B
das Modell A implementiert
Formal korrekt. So, das ist so der Traum,
könnte man sagen, denen, also die Informatik, die Softwaretechnik verfolgt.
Leider Gottes ist es so, dass also die meisten Probleme,
die wir mit Software bearbeiten, dass die sich der mathematischen Spezifikation entziehen.
Mathematisch formulierbar sind, sagen wir mal, so Beispiele wie die Zinsberechnung.
Zinseszinsberechnung oder Dinge dieser Art lassen sich formal spezifizieren.
Ein anderer unserer großen, altvorderen Manni Mayer Lehmann bezeichnet das als sogenannte S-Programme.
Es steht für Spezifikationsprogramme. Und dann überlegen wir mal,
so die interaktiven Programme, die wir heutzutage,
so die Gang und Gäbe sind,
die wir tagtäglich auch selbst benutzen, nicht nur schreiben,
die entziehen sich, also diese Art der mathematischen Spezifikation.
Das sind nämlich sogenannte E-Programme, eingebettete Programme, die sie
wahlweise in menschliche Arbeitszusammenhänge eingebettet sind oder in maschinelle Zusammenhänge.
Da steht eine andere Frage
Im Raum, nämlich die Frage, also der Validation.
Also da nähern wir uns nicht durch mathematische Verfahren,
also der Überprüfung dieser Programme, sondern durch Validation.
Das heißt, also hier spielt also die menschliche Beurteilung eine Rolle.
Man kann sich das an einer Klasse von Programmen,
auch nach Lehmann, kann man sich das ganz gut klarmachen,
nehmen Sie, also alles, was so mit Spielprogrammen,
sagen wir ein Schachprogramm, was damit zu tun hat.
Sie können jetzt wahrscheinlich, kann man das,
also formal beweisen, dass ein Schachprogramm korrekt implementiert ist im Sinne
von,
es gibt keine falschen Züge
Um zu überprüfen, ob das Programm,
das sie da geschrieben haben, ein gutes Schachprogramm ist.
Dazu braucht es also eine menschliche Beurteilung. Weil wenn ich Ihnen ein Schachprogramm implementiere,
dann wird das also, ich traue mir zu,
dass ich das also formal korrekt mache und dass die Spielfiguren alle nur die korrekten Züge machen.
Aber dieses Schachprogramm wird jedes Spiel verlieren. Gegen jeden Dreijährigen.
Weil ich kann keinen Schach spielen. Ich beherrsche zwar,
ich weiß nicht, wie die Figuren zu bewegen sind,
aber das war es dann auch im Großen und Ganzen.
Und das ist so ein Problem, oder diese Art von Problemen,
nämlich, dass so menschliche Beurteilungen hinzukommen muss, weil sich die Probleme,
die durch das Programm gelöst werden, nicht formal beweisen lassen.
Also die Korrektheit der Spezifikation zwar notwendig,
aber nicht hinreichend ist, um ein Problem adäquat zu lösen.
Deswegen müssen wir uns mit anderen Techniken behelfen,
als die der mathematischen Spezifikation und der mathematischen Verifikation,
um valide Software zu entwickeln. Das heißt nicht,
dass das mit der Spezifikation dass man das gleich sein lassen kann.
Das heißt nur, wir müssen die Grenzen dieser Techniken auch
im Auge behalten. So, auf dem Weg dahin,
also das Gedankengut, können wir aber trotzdem verwenden,
das Gedankengut, das gebraucht wird, um S-Programme zu schreiben.
Und da gibt es ein Konzept,
nämlich das Konzept des sogenannten abstrakten Datentyps, das da ziemlich hilfreich ist,
um auf diese Art und Weise robuste Software zu schreiben.
Die Definition des Datentypen,
die haben wir ja sowohl in SE1 als auch in der ersten Vorlesung,
SE2 haben wir die nochmal mal wiederholt und der abstrakte Datentyp erweitert jetzt,
also die ihnen bereits bekannte Definitionen,
nämlich die ganz kurz gefasste Zusammenfassung von Wertebereich und Operationen zu einer Einheit.
Das ist also hier, sehen Sie hier die vier Bestandteile,
die die Definition eines abstrakten Datentypen ausmachen.
Also hier wird definiert Typen, das ist im Sinne von Wertebereich,
was ist die Interessierende Worte, welche Funktionen,
sprich also welche Operationen sind auf diesem Wertebereich erlaubt oder definiert
Und dann gibt es diese zwei Elemente, die jetzt neu hinzukommen.
Das sind die Axiome und Vorbedingungen,
wobei Axiome sind die für alle Elemente dieses Wertebereichs gültigen Aussagen.
Und die Vorbedingungen, das gilt, die werden definiert für
die Funktionen, die nicht total, sondern partiell sind.
Wenn Sie jetzt denken, bin ich hier wirklich bei Softwareentwicklung
und nicht bei Mathe, Grundlagen von irgendwas anderem.
Ich kann sie beruhigen
Ich führe das alles jetzt gleich auf Softwareentwicklung zurück.
Erstmal ein Beispiel für die Spezifikation eines abstrakten Datentypen. Den Keller,
den Stack haben sie ja schon in unterschiedlichen Kontexten kennengelernt und
der dient auch als das Standardbeispiel für abstrakte Datentypen,
so in seinen vier, mit seinen vier Eigenschaften.
Also erstmal, welcher Typ wird hier definiert?
Das ist der Stack und der Stack hat einen,
das zeichnet dich nicht aus, der hat einen generischen Elementtypen Tee.
Das heißt, es ist eigentlich dem Stack, nenne ich das mal,
vermenschlicht sagen darf, dem Stack ist es egal, so was in ihm gesteckt wird.
So, der Stack braucht um, oh Gott,
Gott sei Dank, nicht mein Schreibtisch und wo ist die Maus. Der Stack ist definiert durch folgende Funktionen,
also die Funktion MT, die liefert einen leeren Stack,
wenn man auf ein,
mit der Obfunktion Push etwas auf einen Stack drauftut,
dann kriegt man wieder ein Stack, wenn man von der,
mit der Operation Pop etwas vom Stack herunterholt,
dann kriegt man einen Stack zurück und das hier sagt jetzt,
also dieses Zeichen, sagt er,
die Funktion Top und Top sind partiell,
was bedeutet das?
Nun, man kann die Funktionen Pop und Top
nicht in jedem Zustand eines Texts aufrufen,
von einem leeren Stack holen sie nichts runter, sowohl nachvollziehbar.
Und man kann einen leeren Stack auch nicht auffordern,
gib mir mal
das oberste Element
Das sagt also, das ist die Interpretation dieses,
also dieses Zeichens, diese Funktion, Empty,
Push und Is Empty, die sind total.
Das heißt, man kann sie auf jedem Stack aufrufen.
Also ich meine, das Empty lassen wir mal an der Stelle.
So, was man bis hierhin definiert hat, ist ja ausschließlich Syntax.
Und alles, was ich Ihnen sage, was da,
was ich da hinein interpretiere, in diese Namen von Funktionen,
das sage ich Ihnen, Aber das ist nicht formal definiert.
Es ist völlig bedeutungslos. Bedeutungstragend wird jetzt diese Spezifikation in dem Moment,
wo wir uns um die Axiome bzw. um die Vorbedingungen kümmern.
Weil da steht drin, so die erste Vorbinde,
die erst das erste Aktion liest sich ja so,
also wenn du die Operation pushst,
so wie sie da oben definiert worden ist,
wenn du die aufrufst und du gibst als Parameter ein Stack
und ein Element mit und du schaust dir dann durch anwendende Operationen top,
an welches Element da gerade gepusht worden ist,
dann ist das
genau dieses Element
Und das zweite, können die jetzt da im Einzelnen durchgehen,
brauchen wir aber, glaube ich, nicht.
Wenn man sich diese vier Axiome anschaut, dann ist das genau spezifiziert,
dass genau das Verhalten eines Kellers und nur dieses Verhalten.
Das ist genau das, was wir erreichen wollen.
So, der letzte Punkt, der kümmert sich jetzt um
die und die partiellen Funktionen. Da wird nämlich gesagt,
unter welchen Voraussetzungen können diese partiellen Funktionen aufgerufen werden.
Und das liest sich auf Deutsch. Nun,
du darfst die Operation Pop mit einem Parameter weg,
nur dann aufrufen, wenn gilt, dass dieser Stack nicht leer ist.
Und du darfst auch die Operation top, nur dann aufrufen,
wenn ein nicht leerer Stack gegeben ist, als Parameter übergeben wird.
Vor diesem Hintergrund, denke ich, ist die Frage nach
partiellen und totalen Funktionen, ist die halbwegs nachvollziehbar beantwortet.
So, was wir hiermit haben,
so mit diesem Konzept des abstrakten Datentypen, dass sie,
wie gesagt,
in der theoretischen Informatik noch sehr viel
intensiver kennenlernen werden
So, mit diesem Gedankengut als Ausgangspunkt,
so haben wir erstmal die Möglichkeit,
auf eine etwas formalere Art und Weise zu spezifizieren,
zu definieren, was wir denn eigentlich implementieren wollen.
Weil das ist ja so die Art, so insbesondere hier mit
den Axiomen und den Preconditions, den Vorbedingungen zu arbeiten.
Also macht ja sehr viel besser deutlich, also unter welchen Randbedingungen,
welche Art von Funktionalität implementiert werden soll.
Dieses Gedankengut des abstrakten Datentypen ist also die Grundlage,
oder ist die für das, was jetzt kommt,
nämlich das Vertragsmodell der Softwareentwicklung.
Und die Grundidee dieses Vertragsmodells besteht darin,
dass man das Verhältnis zwischen zwei Klassen als eine Art von Vertrag betrachtet.
Und da sehen Sie jetzt auch unten drunter,
die hier als letzten Satz, die die Formulierung,
die Bertrand Meyer, dafür gewählt haben.
Also eigentlich ist es schon eigentlich, sagt er natürlich nicht.
Er betrachtet so objektorientierte Softwareentwicklung als also die Konstruktion von Softwaresystemen
In dem Sinne, dass Klassen implementiert werden, die untereinander Verträge eingehen.
Und diese Verträge wollen wir spezifizieren können, so,
und dann immer mit dem Ziel, dass so ganz am Anfang,
dass ich ganz am Anfang genannt habe,
dass unsere Software sowohl korrekt als auch robust als Eigenschaften hat.
Korrektheit und Robustheit als Eigenschaften hat. Wenn das ein Vertrag zwischen zwei Parteien ist,
dann haben diese Parteien in dem Kontext, in dem wir uns befinden,
haben die spezifische Namen und Auf- und damit verbundene Aufgaben.
So, wenn Sie hier Klient und Anbieter sehen,
dann stellen Sie sich darunter bitte jeweils Klassen vor und
dann schauen wir uns zunächst mal den Anbieter an.
Also es ist eine Klasse, die bestimmte Dienstleistungen anbietet und die Dienstleistungen,
die ein Anbieter zur Verfügung stellt,
das ist nichts anderes als die Operation,
die einen der öffentlichen Schnittstelle dieser Klasse sichtbar sind.
So, das ist ja für Sie eigentlich,
nicht nur eigentlich, das ist für Sie jetzt bekanntes Terrain.
Der Klient ist in dem Vertrag derjenige,
der diese öffentliche Dienstleistung in Anspruch nimmt
Das ist eigentlich auch nichts anderes, als die Benutztbeziehung zwischen zwei Klassen,
die hier dargestellt wird. Das ist jetzt mit einer etwas anderen Begrifflichkeit,
wird das versehen, aber sie werden im Folgenden sehen, warum,
also diese Begrifflichkeit hilfreich ist und nicht nur eine neue Nebelkerze,
um dasselbe Konzept anders auszudrücken. Das, was hier für,
was also so metaphorisch als Vertragsmodell definiert wird, ist also zusammengefasst,
sicher nochmal, dass die eine Klasse einen Lieferanten darstellt,
einen Anbieter von Dienstleistungen und die andere Klasse,
ist der Klient dieser Dienstleistung.
Und das, was in einem Vertrag zwischen diesen beiden Klassen formuliert wird,
ist, dass der Klient gegebenenfalls Vorbedingungen einhalten muss,
Vorleistungen erbringen muss, um eine Dienstleistung des Lieferanten in Anspruch zu nehmen.
Also kurz mal nachdenken, so ein Beispiel aus der realen Welt.
Wenn Sie in ein Geschäft gehen und etwas kaufen wollen,
ist es eine gute Idee, dass Sie Geld mitbringen.
Das ist sozusagen die Vorbedingung für den Aufruf der Operation
kaufen in dem Geschäft, dass sie gerade betreten haben.
Wenn sie kein Geld mitbringen, was haben sie denn dann?
Also dann erfüllen sie diese Vorbedingungen nicht. Und das heißt also,
der Verkäufer, der Anbieter, der Dienstleistung, braucht sie nicht zu bedienen.
Sagt einfach, nö, mache ich nicht.
Wenn man das noch einen Schritt weiter treiben, diesen Vergleich,
in dem Moment, wo sie die Vorbedingung erfüllen und sagen,
ich kaufe das jetzt,
dann ist der Verkäufer auch verpflichtet,
seine Dienstleistung zu erfüllen,
diesen Vertrag zu erfüllen
Ich, wir vermutlich sie auch nicht, sind ja alle keine Juristen,
aber so versuche ich mir das mal klarzumachen.
Also das klappt in den letzten 50 Jahren eigentlich ganz gut.
Also ich gebe Geld und der andere gib mir Ware,
wenn ich kein Geld habe, gibt er mir keine Ware.
Sodass ist der Vertrag, den wir da eingehen.
So, und das können wir jetzt eben,
also dieses Vertragsverhältnis können wir auch softwaretechnisch interpretieren.
Dann ist, wenn man das politisch unkorrekt bezeichnen will,
dann stehe ich als Käufer ja auch in einer benutzten Beziehung
zu den Verkäufer
So technisch gesprochen, die benutzt Beziehung zwischen zwei Klassen A
und B ist immer dann gegeben, wenn entweder oder,
nein, nicht entweder oder in beiden Fällen,
in Klasse A werden Variablen vom Typ B deklariert.
Das heißt, ich habe Kenntnis von denen,
so und dann ist es ja in der Regel so,
dass ich eklariere nicht eine Variablen von diesem Typ B in meiner Klasse A,
sondern ich rufe auch Operationen an Exemplaren der Klasse B auf.
Das ist die Benutztbeziehung. Und jetzt schauen wir uns an,
also wie das, was ich bisher gesagt habe,
Also Vorformulierung von Vorbedingungen und das Eingehen eines Vertrages,
wie das dann softwaretechnisch interpretiert werden kann.
So, dass der Begriff, der jetzt noch eine Rolle spielt,
das sind die sogenannten Zusicherungen, diese Zusicherung sind eine Art von Operationen,
die sie auch schon kennengelernt haben,
der wir jetzt nur diesen speziellen Namen geben.
Das sind nämlich bulsche Ausdrücke oder auch Prädikate genannt.
Diese Operationen brauchen wir um das, was ich gerade gesagt habe,
nämlich die Vorbedingungen,
die Nachbedingungen
Um die überprüfen zu können, weil die, die liefern einem ja,
das Resultat auf Anfrage, ob eine Zusicherung gilt,
true oder ob sie nicht gilt, ob sie Falls ist.
So, die zwei Arten von Zusicherungen,
die wir hier jetzt zunächst mal unterscheiden werden,
sind Vor- und Nachbedingungen, also die eine Bedingung,
die gelten muss, bevor der Lieferant die Operation ausführt und die Nachbedingung,
die gelten muss, nachdem der Lieferant diese Operation ausgeführt hat.
Und am Ende gehen wir nochmal auf eine Eine dritte Art von Zusicherung,
einen die sogenannten In-Varianten, die stehen in einem Zusammenhang mit dem,
was sie beim abstrakten Datentypen Aksyome genannt wird.
Das sind Aussagen, Zusicherung, die in jedem stabilen Zustand eines Objektes gelten müssen.
Dazu war es später auch noch ein bisschen mehr. So,
auf der Folie wird das jetzt auch nochmal zusammengefasst,
was ich bis jetzt so gesagt habe. Der Klient,
der muss sicherstellen, bevor er eine Operation aufruft beim Lieferanten,
dass er diese Operation auch aufrufen darf
Diese Vorbedingung erfüllt ist, dann ist der Lieferant verpflichtet, die Operation auszuführen.
Und der Lieferant garantiert dann durch das Einhalten der Nachbedingungen,
da kann der Klient ja,
jetzt hat er ja überhaupt keinen Einfluss mehr drauf,
dass auch seine Vertragsrandbedingungen erfüllt ist.
Das heißt, dass die Nachbedingung erfüllt ist.
Oder um es in einem deutschen Satz zu sagen,
wenn der Klient die Vorbedingungen erfüllt,
dann garantiert der Lieferant die Nachbedingungen, die spezifiziert worden sind.
So gucken wir ab jetzt auf Das Verhältnis, die Benutztbeziehung
zwischen zweiten Klassen. Das hat, ich weiß nicht,
wie Ihnen das geht, wenn Sie sich zum Beispiel mal anschauen,
Fred, haben die schon mal so Bibliotheken benutzt?
So unten so. Sie schauen sich also J. Unit an und denken,
aha, da steht jetzt so eine Operation,
die kann ich verwenden,
die soll ich verwenden,
vielleicht müssen Sie die sogar verwenden,
was tut die denn
Hoffen Sie, dass es einen aussagekräftigen Kommentar gibt.
Das können Sie hoffen und manchmal,
es wird diese Hoffnung auch erfüllt, aber dass da steht,
also welche Dienstleistung, welche Voraussetzungen müssen Sie erfüllen,
um diese Operationen auszuüben, auszuführen, aufrufen zu können.
Das ist in der Regel nicht gegeben. Und schon gar nicht,
also was kriege ich denn jetzt eigentlich, wenn ich diese Operation aufrufe?
Was passiert denn zum Beispiel, wenn ich einen falschen Parameter übergebe?
Passiert dann etwas oder nichts. Das ist das typische Verhalten von unserer Bibliothekssoftware.
Man erwartet irgendeine Operation, ein Merkmal, ein Intager-Parameter erwarten.
Oder sagen wir lieb, sagen wir was Besseres.
Sie erwartet ein Geburtsdatum und das so in Form von drei Intagern.
Tag, Monat, ja, sind ja drei Intager.
Jetzt geben Sie als Geburtsdatum, sagen wir,
ich gebe als mein Geburtsdatum, als Parameter übergebe ich,
48.13. 500.
Und was passiert jetzt
Kann man sich ja mal fragen. Und der typische,
die typische Reaktion ist, es passiert nichts.
Also jedenfalls nicht nach außen hin sichtbar.
Und dann verbirgt man das mal mit anderen Daten.
Und dann passiert vielleicht etwas. Dann muss man sich dieses Verhalten,
man muss sich ja so ein Modell darüber entwickeln,
welche Reaktionen zeigt eigentlich jetzt dieser Lieferant,
wenn ich ihn mit falschen Parametern füttere.
Und ab heute sind diese Tage für sie vorbei. Sie können jetzt Software schreiben,
die sagt, als Vorbedingung für diese Operation,
die ein Geburtsdatum erwartet, sage ich, nun,
der Monat muss ein Wert sein zwischen 1 und 12.
Und der Tag sollte zwischen 1 und 31 sein und und so weiter.
Und dann sehen Sie als Klient dieser Klasse, okay,
der Implementator, der Lieferant, erwartet von mir ein korrektes Datum.
Und jetzt machen wir nochmal den Versuch,
wir übergeben den
Als 500, als mein Geburtsdatum. Und was dann passiert,
sollte so aussehen, dieses Programm wird einer Ausnahmebehandlung zugeführt.
Das heißt, das bricht ab zur Laufzeit. Mit der Bemerkung der Parameter
hatte nicht die geforderten Merkmale. Das würde ich jetzt,
das ist kein besonders robustes Verhalten, dazu später mehr.
Es erzeugt jetzt auf jeden Fall erstmal diesen Effekt.
Da ist ein offensichtlich ein Programmierfehler aufgetreten. Und dieser Programmierfehler wird
mit einer Reaktion bearbeitet. Also es wird dieses Datum,
insbesondere wird dieses Datum nicht trotzdem weiterverarbeitet,
was eine ziemlich gute Idee ist, weil es gibt kaum etwas grauenhafteres.
Doch, es gibt viel grauenhafteres. Sagen wir mal,
es gibt leichter zu entdeckende Fehler als falsche Eingabedaten,
die spät in der Verarbeitungskette erst zu einem Effekt führen,
der nicht beabsichtigt worden ist.
Man sollte diese Fehler so früh wie möglich bearbeiten.
Und das Vertragsmodell liefert genau diese Mechanismen.
Wir schauen uns das jetzt nochmal An einem Beispiel,
an einem anderen Beispiel an, so eine Bibliothek.
Sie sind also diejenigen, die die Aufgabe haben,
die fachliche Schnittstelle der Klasse Buch zu entwerfen.
Und jetzt fragen sie, was könnte so ein Buch denn nehmen?
Wie könnte so eine Schnittstelle aussehen? So,
und dann kommen sie auf die Idee, okay,
ich möchte ein Buch ausleihen können und als Parameter übergebe ich dann den Benutzer,
der dieses Buch ausleihen möchte.
Ich möchte dieses, wo ausleihen ist,
da ist Zurückgeben auch nicht weit.
Ich möchte das zurückgeben und zwar sollte das auch ein Benutzer
als Parameter bekommen
Man möchte so ein Buch mahnen können. Das möchte man
auch benutzen. Das braucht auch einen Benutzer als Parameter.
Der Benutzer B möchte dieses Buch auch verlängern können,
um eine Frist oder das Vorbestellen.
Soweit so gut. Und jetzt gucken wir mal noch.
Ja, da stehen jetzt so, genauso wie ich
das am Anfang gesagt habe, da stehen jetzt Namen.
Und diejenigen von ihnen, die einen Umgang mit Bibliotheken,
mit Büchern haben, können sich darunter auch was vorstellen.
Diejenigen, die eher selten mit Büchern zu tun haben,
denken, aha, ist ja interessant,
was man mit Büchern
alles machen kann
Besondere, wenn man so eine Bibliothek toll,
habe ich noch nie gehört, was ist das denn?
Verlängern, ein Buch, was ist das denn,
kann ich da mehr Seiten dran machen?
Oder was man sich halt so fragt,
wenn man keinen Umgang mit Büchern aus Bibliotheken hat.
So, insofern ist es auch ganz hilfreich, wenn wir jetzt
die Bedeutung dieser Operation noch so etwas anreichern können, um Randbedingungen.
Also was so unter welchen Umständen und mit welchen Effekten
ist denn so ein Buch überhaupt so zu bedienen?
Also wie kann man denn damit umgehen
Weil hier steht jetzt, es gelten vermutlich Regeln für die Verwendung der Operationen.
Kann ich ein Buch, das ich nicht ausgeliehen habe, eigentlich zurückgeben?
Kann ich ein Buch ausleihen, das bereits ausgeliehen ist?
Kann ich ein Buch anmahnen, das gar nicht ausgeliehen ist?
So sind da alles so Fragen. Die Leute kommen ja
auf die wundersamsten Ideen bei der Bedienung von Software.
Also, was machen wir jetzt? Wir formulieren Randbedingungen,
die gelten sollen, für den Umgang mit Büchern.
Das hilft also, hilft unter anderem auch uns,
um uns unser Verständnis von dem,
was wir da jetzt eigentlich modelliert haben, um dieses Verständnis zu schärfen.
Also um besser darüber nachdenken zu können,
welche Effekte könnte das denn überhaupt haben,
was wir hier vorhaben, nachher zu implementieren.
So, und jetzt steht hier für das Ausleihen,
ein Buch kann nur ausgeliehen werden, wenn es vorhanden ist.
Das ist also eine Vorbedingung für das Ausleihen. Und dann gilt,
wenn das Buch ausgeliehen ist, dann ist ist es nicht mehr vorhanden.
Aha, dann ist es also weg. Umgekehrt gilt es
für das Zurückgeben. Man kann es nur zurückgeben,
wenn man es ausgeliehen hat. Sonst geht es nicht.
Und nach dem Zurückgeben ist das Buch wieder vorhanden. Das heißt,
es ist am Stellplatz, an dem es vorher war.
Das ist doch so, das scheint so eine Art Sechselspiel zu sein zwischen diesen beiden.
Operationen. So, dieses etwas bessere Verständnis,
das können wir jetzt in Form von Vor- und Nachbedingungen,
können wir das jetzt auch ausdrücken, nämlich für das Ausleihen ist die Vorbedingung,
also das Englisch gesprochen, heißt das Require.
Für die Ausleihe ist die Vorbedingung, dass dieses Prädikat True liefert, nämlich ist vorhanden.
Nur dann darf also die Operation ausgeliehen werden. Wenn diese Vorbedingungen gegeben ist,
dann sichert diese Operation Ausleihen zu, dass nachdurchlaufendes Codes,
also alles, was zwischen Rerequire und Entschuhe,
dann an Code abläuft, dass die Bedingung gilt, ist ausgeliehen.
Und bei dem Zurückgeben ist es genau umgekehrt.
Kann man sich noch fragen, Es ist wirklich notwendig,
also das begrifflich so zu unterscheiden oder kann man das nicht einfacher hinschreiben?
Und jetzt kommt also wieder der Programmierer in ihn, kommt so,
meldet sich zu Wort in ihrem inneren Team und sagt,
naja, wir kennen doch auch die Negation,
also können wir diese, können wir diese Randbedingungen jetzt so formulieren,
für das Ausleihen ist die Voraussetzung,
not ist ausgeliehen und für das Entschuhe des Ausleihens,
also für die Nachbedingung gilt,
es ist eben ausgeliehen und für das Zurückgeben können wir das
so genau andersrum
Können wir das formulieren? So, wenn Sie sich jetzt vorstellen,
Vertragsmodell, wir schauen also jetzt auf eine etwas erweiterte Spezifikation, der Klasse Buch.
Die Klasse Buch hat an Ihrer Exportschnittstelle die Operation ausleihen und
die Operation zurückgeben und die anderen, die ich gerade genannt habe.
Und darüber hinaus sagen also diese Operationen jetzt, weil die nicht total sind,
sagen Sie, unter welchen Vorbedingungen sind die denn eigentlich aufrufbar?
Und das macht jetzt das Verhältnis zwischen dem Lieferanten auf der
einen Seite und dem Klienten auf der anderen Seite,
macht es viel deutlicher, weil jetzt ist insbesondere auch klar,
wenn dieses Programm mal abstürzt mit der mit der Ausnahme.
Es wurde versucht, ein Buch auszuleihen, das bereits ausgeliehen ist.
Dann ist klar, nach dem Vertragsmodell, wer ist schuld an diesem Programmabbruch?
Und an diesem Programmabbruch wäre dann nicht die Klasse Buch.
Dafür ist die nicht verantwortlich, sondern der Klient der Klasse Buch.
Während ohne Verträge, ohne Randbedingung, müsste man jetzt mühselig nachschauen.
Warum ist dieses Programm denn jetzt eigentlich abgebrochen?
Und hier kann man ganz eindeutig den Finger auf denjenigen richten,
obwohl man das nicht tun sollte
Aus anderen Gründen, auf denjenigen, der den Klienten
der Klasse Buch geschrieben hat. Genauso eindeutig ist es,
wenn also nachdurchführendes Codes nach Abarbeitung des Codes von Ausleihen,
wenn diese Randbedingungen, die Nachbedingungen, wenn die scheitert,
dann ist die Fehlerursache in der Implementation der Klasse Buch zu suchen.
Man kann das dann, aber das ist ja der Teil,
Fred Ihnen gleich nahe bringt, wie man das in Java umsetzt.
Dieses Vertragsmodell ist also ursprünglich in die Welt gekommen.
Ende der 80er Jahre des letzten Jahrhunderts von Bertrand Meyer in der Programmiersprache Eifel.
Und da ist es auch vollständig implementiert worden. Und das ist,
es hat seinen Weg in Java noch nicht gefunden, oder?
Aber es ist jetzt für Java 10 ist es,
glaube ich, mindestens angekündigt. Das ist also nach meinem Kenntnisstandard,
dass ich mich mit dieser Frage jetzt intensiv im Alltag beschäftigen würde.
Ich meine, ich hätte mal ein Interview gelesen,
dass der Autor, der ursprüngliche Autor von Java gesagt hat,
sie haben das damals nicht in die Sprache aufgenommen,
weil es zu kompliziert war.
Jetzt nicht, das zu implementieren, sondern weil der typische Programmierer,
also damit nicht umgehen kann, mit diesem Konstrukt.
Das halte ich für einen verdammt schlappes Argument,
weil eine gute Programmiersprache soll es ja leicht machen,
gute Programme zu schreiben, nicht etwa schwer machen, schlechte Programme zu schreiben.
Nun gut, aber Wir geben die Hoffnung nicht auf und ich glaube,
das wird also so in einer der nächsten Fassungen von Java,
wird das Vertragsmodell, wird es möglich sein, Elemente des Vertragsmodells zu verwenden.
So, gucken wir uns das trotzdem nochmal so, was heißt trotzdem,
wir gucken uns das jetzt mal so an einem Beispiel an.
So, es gibt hier also diese zwei Klassen,
den Benutzer und das Buch, soweit waren wir ja schon.
Und wir erzeugen also einen Benutzer hier,
der hat einen Namen und wir zeugen ein Buch
Jetzt wird an dem Buch die Operation ausleihen, aufgerufen,
die erwartet einen Benutzer als Parameter und jetzt gucken wir uns mal an,
wie ist das in der Klasse Buch implementiert.
Nun, die Vorbedingungen des Ausleihens, so wie es hier steht,
ist, not ist ausgeliehen und Nachbedingungen ist ausgeliehen.
Und das sollte beim ersten Aufruf von ein Buch von genau
diesem Buch, sollte das klargehen. Beim zweiten Versuch,
dieses Buch von diesem Benutzer auszuleihen, nicht nur von diesem Benutzer,
sondern überhaupt genau dieses Buch auszuleihen,
da sollte es zu einer Ausnahmebehandlung geben,
eben weil die Vorbedingungen ist ausgeliehen, nicht eingehalten ist.
Das wurde ja gerade das Gegenteil, wurde ja zugesichert als Nachbedingung der Ausleihen-Operation.
Das ist also so dieses Wechselwechselspiel zwischen Rechten und Pflichten des Lieferanten, das hier gespielt wird.
Für die Schnittstellengestaltung ihrer Klassen hat das jetzt eine Folge.
Wir haben uns bisher nur Gedanken gemacht über die funktionale Seite der Schnittstellen,
sagen wir mal, das hier soll stellvertretend für die Operation ausleihen gelten.
Was wir jetzt noch in die Schnittstelle zusätzlich integrieren müssen,
sind die Zusicherungen, hier als Prädikat 1 und 2 gekennzeichnet.
Weil ich möchte ja als Klient dieser Klasse,
so wenn ich jetzt unbedingt diese Operation F aufrufen möchte,
wenn ich diese Operation als Klient aufrufen möchte und ich sehe,
die hat zwei Vorbedingungen, dann muss ich ja in der Lage sein, diese Vorbedingungen zu überprüfen.
Sonst wäre es ja irgendwie Ein bisschen heimtückisch. Also wenn man mir hier sagt,
ja, ja, es gibt vorher Bedingungen,
aber ich sag dir nicht, also wie diese Vorbedingungen heißen,
das würde mich dann in die Lage versetzen,
also ich kann die überhaupt nicht überprüfen,
dann lasse ich das lieber gleich sein mit dem Aufrufen von Effen,
dann suche ich mir halt einen anderen Lieferanten,
der mir vertrauenswürdiger erscheint, weil der mir vorhinein sagt,
welche Randbedingungen mich einhalten muss.
Und das bedeutet jetzt, also dass wir,
dass die Schnittstelle hier wieder ein Beispiel des Buches, dass diese Prädikate,
diese bullschen Funktionen dass die an der Schnittstelle sichtbar sein müssen.
Und für die gilt auch so eine weitere Randbedingung.
Es gilt die Randbedingung, dass sie bedingungslos aufrufbar sein müssen.
Also in jedem Zustand eines Objektes müssen diese Prädikate aufrufbar sein.
Das dürfen keine, also Voraussetzungen gelten. Und das macht
einen Unterschied zu den Operationen, wie jetzt gesehen,
also ein Beispiel ausleihen, das darf man halt nicht immer aufrufen.
Diese Prädikate muss man immer aufrufen können, weil diese Tests
Man weiß ja nicht, zu welchen Situationen diese Tests gebraucht werden.
Also davon dürfen da keine Annahmen über den Objektzustand drin gemacht werden.
Und bei Funktionen, das haben sie ja auch schon kennengelernt,
der Unterschied zu Prozeduren besteht darin, Funktionen haben keinen von außen sichtbaren Effekt.
Also das können sie auch hundertmal hintereinander aufrufen.
Das sind halt Funktionen, die beeinflussen den Objektzustand nicht.
So, jetzt haben wir also insgesamt drei,
nur mal so als Überblick,
drei verschiedene Arten von Operationen,
die wir unterscheiden
Eine Operation, wie das Ausleihen eines Buches ist eine verändernde Operation.
Die haben einen Effekt auf den Objektzustand. Wir haben sondierende
fachliche Operationen, sind Operationen, die einen Rückgabewert liefern.
Aber ansonsten den Objekt zuständig verändern, sowohl die Verändernden als
auch die sondierenden fachlichen Operationen können partiell sein.
Und die dritte Art von Operation,
die jetzt durch die Implementation des Vertragsmodells oder durch die Anwendung des Vertragsmodells dazukommt,
sind sondierende Bulsche-Operationen,
die sind total und haben wie eben wie die anderen Funktionen
keinen Seiteneffekt auf dem oder keinen Effekt auf den Objektzustand,
an dem sie aufgerufen werden.
So, ich wollte noch, ich habe mit Blick auf
die Verspätung, zwei, drei Minuten habe ich noch.
Die dritte Art von Randbedingungen kurz darstellen, die sogenannten Klassenin-Varianten.
Die Klassenin-Varianten sind das Pendant in der objektorientierten Programmierung zu den Aktionen des abstrakten Datentypen,
abstrakten Datentyps, Klassenin-Varianten machen Aussagen darüber,
Welche Aussagen für ein Objekt zu jedem stabilen Zeitpunkt des Objektes gelten?
Fragen Sie sich, aha, stabiler Zeitpunkt, was soll das sein?
Gibt es auch labile Zeitpunkte? Ja, gibt.
Das mache ich am besten an einem Beispiel. Klar,
wir haben uns mit Listen beschäftigt,
unter anderem auch mit sortierten Listen oder Sortieralgorithmen für Listen.
So, jetzt sagen wir mal,
ich schreibe eine Klasse sortierte Liste und das,
was ich zusage,
ist,
diese Liste ist immer sortiert
Es gibt also eine Bullshit-Prädikat, das heißt sortiert und das liefert True.
Und zwar immer. Was ich jetzt zusage, ist,
dass diese Aussage gilt in einem stabilen Zustand.
Der stabile Zustand ist der Zustand,
der für sie als Klienten der sortierten Liste sichtbar ist.
Was das bedeutet, nun jetzt nehmen wir mal an,
sie wollen nicht lange nachdenken und implementieren,
jetzt als Sortier, als Einfüge-Algorithmus, einen Bubble Sword.
Und das bedeutet, in dem Moment,
wo sie ein Element, seinen Platz suchen, suchen lassen.
Also ist ja diese Randbedingung der Sortiertheit verletzt, bis das Ding
seinen Platz gefunden hat, ist die Liste eben unsortiert.
Weil es zwischendurch, wenn sie zwischen A und K mal so ein G einfügen wollen,
dann bubbelt dieses G dann A, B, C,
D, bis es halt seinen Platz gefunden hat.
Und dann ist der Bubble Sword erst fertig. Und das ist der labile Zustand eines Objektes,
der vergleichsweise irrelevant ist, weil in einem Single-Thread-Universum,
also sieht man das ja nie, dass das jetzt gerade,
man kann das Objekt ja nicht fragen,
also wo befindest du dich jetzt gerade bei der Verarbeitung,
dieses Sortieralgorithmus, wenn man kriegt, den Kontrollfluss ja sowieso erst zurück, wenn dieses Element einsortiert worden ist.
Und das heißt also, diese Aussage, die Liste ist immer sortiert,
die kann ich vor Beginn des Codes einer exportierten Operation und nach Beendigung des Codes,
einer exportierten Operation, kann ich die überprüfen.
Und dann muss sie gelten. Das ist die Aussage,
die durch Klasseninvarianten gemacht wird. Eine Invariante für das Buch,
ich mache hier nur das erste Beispiel,
Also das Buch ist entweder ausgeliehen oder es ist ausleihbar.
Was anderes gibt es für das Buch nicht. Das sind die zwei,
das ist so eine Invariante, die man für ein Buch formulieren kann. So,
das habe ich jetzt schon gesagt,
womit wir uns im Weiteren noch beschäftigen werden, ist,
ich habe davon gesprochen, dass wenn Zusicherung,
also Vor- und Nachbedingungen in Varianten, wenn die verletzt werden,
dass es zu einem Programmabbruch führen soll Wir werden uns noch damit beschäftigen,
wie man methodisch mit Programmabbrüchen umgeht.
Das heißt also, wie das so konzeptionell einzusetzen ist. So,
und jetzt hoffe ich,
dass sie schon wieder etwas anders über die Welt nachdenken,
über die Welt der objektorientierten Programmierung,
weil sie jetzt in der Lage sind,
nicht nur wiederverwendbare, änderbare und erweiterbare Software zu schreiben,
sondern auch korrekte,
sagen,
gibt es ein komparativ von korrekt
Eher nicht, oder? Also sie sind nicht in
der Lage, jetzt noch korrektere Software zu schreiben.
Aber robustere Software, das vielleicht.
Ein schönes Wochenende
So, kleiner Stimmtest, eins, zwei,
drei, vier, fünf, sechs,
sieben.
Also ich habe leider zu Java 10 und Vertragsmodell so spontan jetzt nichts gefunden,
aber es wird tatsächlich gerade darüber diskutiert,
ob man das Vertragsmodell nicht an CPlus einbauen sollte.
Fass euch das interessiert, google doch mal nach N 44, 15.
Da wird beschrieben, wie das aussehen soll.
Vielleicht gucken wir es euch noch mal ganz kurz an,
an einem konkreten Beispiel. Finde ich ganz witzig,
dass diese alten Ideen in noch ältere Programmiersprachen jetzt so langsam ihren Einfluss finden.
Also CPlus Plus ist ja schon, weiß ich,
83 oder so, ist, glaube ich, auf die Welt gekommen.
Okay, ich hatte schon mal Eclipse starten sollen,
es dauert ja immer so lang
Also ich habe mir überlegt, was mache ich heute mit euch?
Ich muss euch was über testen erzählen, weil das in der Übung nochmal drankommt,
was über das Vertragsmodell, weil das drankommt.
Und ich wollte auch noch mal irgendwas so machen,
was euch aufs Programmiertekt hat, vielleicht auch mal ein bisschen vorbereitet,
weil das ja auch diese Woche anfängt, also morgen.
Und dann dachte ich, ein gutes Beispiel,
was wir mal zusammen bauen könnten, ist eigentlich die altbekannte Airrealist,
die wir ja letztes Semester schon irgendwann Woche 12 oder so implementiert haben.
Weil man da eigentlich alles sehr gut veranschaulichen kann.
Wie ist jetzt überhaupt das Bild? Ach,
ist wieder genauso wie letzte Woche. Ich kann ja mal
vielleicht hier unten das so schieben
Dass ihr zumindest den Code immer seht. Ach so,
weiter nach unten geht's gar nicht, okay. Okay,
also ihr seht zumindest den Code, das ist ja schon mal gut.
Das seht ihr auch alles, wir machen uns mal ein neues Java-Point.
Ihr seid ja schon Experten in der Kipps,
ihr wisst ja jetzt, wie man Projekte anlegt,
nennen wir das doch mal irgendwie Air-Realist.
Und das ist mir hier alles eigentlich relativ wurscht.
So. Wie? Okay. Nee, will ich nicht.
Gut. Sieht man das denn jetzt? Ja, das sieht man. Gut,
das solltet ihr euch jetzt auch nicht mehr schockieren,
wenn wir einen Source-Ordner,
da klicke ich einmal rauf und sage,
ich will eine neue Java-Klasse da reintun
Vielleicht nenne ich sie nicht Arealyst, weil sie heißt ja
in Java, genauso nenne ich sie Flamme My List.
Dann ist irgendwie völlig klar, dass es meine eigene Liste ist.
So, jetzt dauert es ein bisschen und dann
habe ich jetzt den Code. Kann man alles sehen?
Ja. Gut. Wir machen das jetzt nicht irgendwie generisch,
also dass diese Liste alle möglichen Arten von Typen halten kann,
sondern wir beschränken uns vielleicht mal auf Strings.
Ja, Strings. Vielleicht hätte ich sie dann mal Stringlist nennen sollen.
Jetzt zeige ich euch mal was. Ich kann das hier
nicht einfach so umändern, weil ich will ja wahrscheinlich,
dass sich der Dateinahme auch ändert, oder?
Jetzt zeige ich euch mal zwei Möglichkeiten.
Die erste Möglichkeit ist zu sagen,
Und jetzt kann ich einen neuen Namen eingeben,
sagen wir mal, Stringlist. Ihr könnt das hier wegnehmen.
So. Und jetzt hat sich der Dateiname hier auch geändert.
Das ist ziemlich cool. Also immer, wenn ihr
was umbenennen wollt, nehmt Altshift Air. Dann wird das
nicht nur an der einen Stelle umbenannt, sondern an allen Stellen.
Gut. Okay, wie ist nochmal so eine Liste aufgebaut?
Man hat ja intern so ein RL?
Wie wollen wir es nennen? Ich nenne es mal,
tja, wie nennen wir es denn mal?
Buffer. Ich nenne es einfach Buffer. Ich wollte es
nicht R erinnern, sonst ist es irgendwie immer
ein blöder Name
Okay, dann machen wir doch vielleicht mal einen kleinen Konstruktor.
Ihr wisst ja hoffentlich noch, wie ein Konstruktor aussieht.
Und jetzt brauchen wir irgendwie eine initiale Kapazität.
Ich kann ja einfach mal sagen, vielleicht tausend.
Ich habe nämlich keine Lust, ups,
mit euch heute noch dynamische Vergrößerung von Listen zu implementieren.
Tausend ist hoffentlich groß genug für jeden Anwendungsfall. Okay,
das reicht aber jetzt nicht, denn ich habe jetzt ein RE,
der Länge tausend, das ist quasi jetzt die Kapazität der Liste.
Aber ich muss mir auch noch irgendwie merken,
wie viele Elemente hat der Benutzer den jetzt wirklich abgelegt?
Das nennen wir mal,
um das vielleicht längst nennen
Wie haben wir das immer genannt? Wir haben das Kardinalität
und Kapazität genannt. Ich will das jetzt aber nicht
Cardinality nennen. Das ist ein furchtbarer Name. Okay,
um die Längstung am Anfang auf Null setzen,
das ist sie zwar im Plizit, aber es ist ja nicht so schlimm.
Okay. So. Jetzt vielleicht mal eine Operation, um was einzufügen.
Ein Benutzer oder nennen wir das vielleicht mal Appent.
Es soll irgendwie ganz am Ende eingefügt werden,
dann muss ich mich nicht um Verschiebung kümmern.
Der Benutzer will irgendein neues Element einfügen. Jo,
wie würdet ihr das jetzt schreiben, dass je nachdem,
wie voll das RE quasi schon ist,
an der korrekten Stelle jetzt dieses Element eingefügt wird?
Wie schreibt man da nochmal in eine RE,
was da ein
Also ich sage jetzt mal auf Deutsch, was ich machen will, ja.
Schreibe in das RAE Buffer an die Stelle, ja,
das muss man uns noch überlegen, das Element,
ja, oder ich mache mal das mit kleinem E,
hast du das Element von dir oben?
Wie formuliere ich das denn in Java? Man könnte sich ja wunderbar vorstellen,
dass sowas zum Beispiel vielleicht in einem Polen-Edikt hat,
auftauchen könnte als deutscher Satz.
Irgendjemand eine Idee, wie ich in RAE was reinschreibe im Genre.
Habt ihr das noch nie gemacht, ja?
Ja. Richtig? Richtig
Zuweisen, richtig, ne? Also ich auf der linken Seite
einer Zuweisung kann eben auch so ein RA-Access quasi stehen.
Das sagt tatsächlich diese Zeile. Okay,
und wenn ich das jetzt eingefügt habe,
dann wurde das ja sicherlich länger um einen.
Also muss ich die Länge zum einen erhöhen. Okay.
Gut. Jetzt kommen wir langsam mal in Richtung Vertragsmodell.
Ich will ja sicherlich auch mal einen Stream an einer bestimmten
Stelle mir holen. Das heißt, glaube ich,
immer standardmäßig Getty Operation und ich übergebe einen Index.
So, und jetzt wird es schon spannend.
Vielleicht können wir erst mal auf Deutsch
uns überlegen
Was muss denn jetzt für diesen Index,
den man ja von außen reingesteckt wird,
von dem Klienten, was muss denn von denen gelten?
Kann der Klient da jeden Inch übergeben? Also ist es in Ordnung,
wenn das zum Beispiel minus zehn übergibt oder ist es in Ordnung
in einer Plus-Szene übergibt oder gibt es da irgendwelche Einschränkungen?
Ja. Genau. Also wir könnten vielleicht erst mal abprüfen,
jetzt mache ich es erst mal mit Bordmitteln, die ihr schon kennen würdet.
Man könnte zum Beispiel sagen, wenn der Index kleiner ist
als Null, ich habe noch gar nicht gelernt,
wie man Acceptions wirft, oder?
Nee, das kommt erst noch. Das heißt,
wir können es doch nicht mit Bordmitteln machen.
Also jetzt müsst ihr ja irgendwie stehen, Fehlerbehandlung.
Wisst ihr noch gar nicht, wie das geht?
Okay, dann zeige ich euch gleich,
wie wir es jetzt machen
Wir machen es also in zwei Schritten. Einmal,
wir prüfen das mit einer sogenannten Assort-Anweisung, sagen,
der Index muss mindestens null sein.
Ansonsten haben wir ein Problem. Wenn der Benutzer da
was Negatives übergibt, ist irgendwie nicht so schön.
Also prüfe bitte, dass der Index wirklich größer gleich null ist.
Und wenn er das nicht ist, kann ich mir
jetzt so einen Doppelpunkt getrennt, irgendeine schöne Fehlermeldung eigentlich.
Ich kann zum Beispiel sagen, negative,
aber was ist denn jetzt der Plural?
Indexe oder so? Indizes, danke. Indize,
hups, indizes sind nicht erlaubt oder so.
Irgendwie so
Vielleicht findet ihr da eine schönere Fehlermeldung, okay.
Und dann noch Third Index, kleiner längs. So. Ja
, Index ist zu groß oder irgendwie so, ja.
So. Jetzt kann man sich doch nicht wunderbar streiten.
Ist das größer gleich an der Stelle richtig?
Ist das kleiner an der Stelle richtig und so?
Könnt ihr euch in Ruhe überlegen? Vielleicht habe ich das
auch falsch gemacht. Mal gucken. Okay. Wie liefere
ich denn jetzt das Element an der Stelle,
die durch den Index angegeben wird?
Also ich formuliere es mal auf Deutsch,
liefere das Element in dem RE an der Stelle Index an den Klienten zurück oder so.
Ja, das ist auch ein toller deutscher Satz.
Könnt ihr den in Java übersetzen, wenn ich das hinkriege zu typen,
auf meiner tollen englischen Tastatur.
So. Ja. Lefts, sagst du? Dann wurde ja
quasi der Index, den der Benutzer hier ignoriert,
den er benutzt hat, er übergibt völlig ignoriert werden.
Richtig. Okay. Jetzt ist, das sieht schon mal
ganz gut aus, so als erste Näherung.
Jetzt haben wir allerdings ein riesiges Problem
Wenn man sich mal die Schnittstelle anguckt,
die sieht man jetzt ja nicht so schön wie in Blue
Jay und ich will sie jetzt auch nicht im Hintergrund generieren.
Aber stellt euch einfach mal vor,
der Benutzer schaut sich diese Operation von außen an.
Was sieht er denn so alles? Er sieht, okay,
sie ist öffentlich, sonst würde er sie nicht sehen,
okay, er sieht, was zurückkommt, er sieht,
wie sie heißt und er sieht, was er reinstecken soll.
Aber er sieht ja an der Schnittstelle nirgendwo, dass es
diese Einschränkung gibt, die ich hier im Code überprüfe.
Das ist ja im Prinzip ein Implementationsdetail. Ich will ja
nicht von jedem Klienten erwarten, dass er sich erstmal den
ganzen Code ansieht einer Methode, die er benutzen will.
Also, nehmen wir mal ein Beispiel,
als ihr eine Air-Alist benutzt habt,
wer von euch hat schon mal in den Quelltext von der
Java-Air-Alist reingeguckt?
Einfach mal Hand hoch
Ach, doch, so ein paar Leute, einfach,
weil es euch interessiert hat. Aber ihr konntet es ja tatsächlich benutzen,
ohne in den Quelltext einzugucken. Die Hoffnung ist ja immer,
man schaut sich die Schnittstelle an als Klient und versteht,
was von einem erwartet wird. Okay, das heißt,
wir müssen irgendwie auch in diesen Schnittstellen-Kommentar reinschreiben, dass da gewisse,
ja, Vorbedingungen gelten, die eingehalten werden müssen.
Okay, ihr seht in den Clips, das finde ich
ganz nett, vielleicht ging das gerade ein bisschen schnell.
Wenn ich hier so einen Java-Doc-Kommentar anfange,
der fängt ja mal so an, ne,
slash Sternsterne, wenn ich dann Inter drücke,
dann wird schon einiges für euch generiert.
Ich weiß gar nicht, ob ihr das kennt,
deswegen erzähle ich da kurz was zu.
Also man kann hier erst mal reinschreiben,
liefert das Element an der Stelle Index oder so.
Also irgendwie einen deutschen Satz oder mehrere deutsche Sätze,
gern noch Englisch oder andere Sprachen
Und wenn ihr jetzt den Eindruck habt,
man müsste diesen Parameter-Index nochmal genauer spezifizieren,
was der genau ist oder was er sein darf oder so,
dann könnte man das hier direkt hinterschreiben.
Das erspare ich mir jetzt mal. Und wenn ihr den Eindruck habt,
dass der Returnwert auch nicht so offensichtlich ist,
dann könnte man das hier noch großartig erklären,
was der denn bedeutet.
Aber ich lösche das jetzt erstmal, das ist jetzt erstmal nicht so wichtig.
Da findet ihr auch Beispiele in unseren Systemen. Was jetzt
für uns wichtig ist, ist diese Vorbedingungen zu formulieren.
Also quasi, ja, diese Bedingungen,
dass die irgendwie an der Schnittstelle auftaucht.
Und wir machen das folgendermaßen, wir sagen Require.
Require und dann im Prinzip dasselbe wie unten,
Index größer gleich null.
Und Require,
Index,
kleiner Banks
Gut, wenn Klient also sowas sieht,
schaut er sich mal diese Zeile an und denkt so,
ach, das ist ja klar, das verstehe ich.
Ich darf keine negativen Zahlen übergeben, hast du das auf Deutsch?
Gut, was heißt denn die nächste Vorbedingung?
Require, Index, kleiner Lenks. Klar,
das Index kenne ich, das übergebe ich ja selber,
ist irgendwie klar, was das sein soll.
Und dann schaut er sich an längs,
das sehe ich irgendwie zum ersten Mal,
schaue ich mir immer die Schnittstelle an, wo dieses längs beschrieben ist.
Schaut doch mal an, ist irgendwo, also hier haben wir Get,
Appent, dann haben wir hier einen Konstruktor.
Nö, längs taucht nicht an der Schnittstelle auf.
Was machen wir denn jetzt? Ich will ja,
dass dieser Kommentar für jeden Benutzer meiner Klasse verstärkt endlich ist.
Da dürfen sozusagen nur Vokabeln drin auftauchen, die woanders an
der Schnittstelle definiert sind und längs gehört ja nicht zur Schnittstelle.
Soll ich jetzt einfach mal eine Exemplarvariable Public machen?
Kann ich auch sagen, wäre nicht so eine gute Idee.
Was macht man jetzt, wenn man als Klient lesen,
darauf zugreifen will in Jarla? Ihr habt eine Exemplarvarie,
ihr wollt den Wert irgendwie an den Klienten liefern können.
Genau, wir machen einfach eine sondierende Methode.
Wo tue ich sie mal hin? Die ist so simpel,
dass ich sie mal vielleicht als erste Methode oben hinschreibe.
Public and Lenks Returnling. Und ihr seid jetzt vielleicht
ein bisschen, ja weiß ich nicht, erstaunt.
Es ist tatsächlich möglich, dass eine Methode genauso heißt wie ein Zustandsfeld.
Das Problem habt ihr in SE2 natürlich nicht,
weil hier eigentlich diese Unterstriche hingehören.
Was könnte ich jetzt machen? Ich könnte jetzt hier
diesen Unterstrich hin machen und anschließend gehe ich mit dem Causa
Hielen und mache da den Unterstrich hin und hier auch.
Aber wir haben ja schon gelernt, wenn ich etwas umbenennen
will, nehme ich einfach Altshift Air.
Altshift Air. Einmal unterstrich, zack, überall geändert.
Bei längst mache ich es genauso. Altshift Air, unterstrich
, zack. Und ihr seht, er hat tatsächlich nur
das Läng viel geändert, dieses Längst hat er nicht geändert.
Das System hat also verstanden, das heißt,
es war gleich,
sind aber
verschiedene Dinge
Okay. Gut, das heißt,
jetzt kann ich dieses Links hier für meine Vorbedingungen verwenden.
Und dann sollte man es der Konsistenzhalber vielleicht hier unten auch verwenden.
Ja, ups, wieso ist das jetzt nicht möglich?
Was habe ich da falsch gemacht?
Deswegen habe ich nicht gespeichert, ist das das Problem.
Ach, Dankeschön. Den sehe ich nicht,
weil der Unterstrich von diesen roten Kringel überdeckt ist.
Ja. Okay, das ist etwas,
was man gerne falsch macht als Programmieranfänger oder als SO2-Neuling,
dass man hier irgendwelche privaten Exemplarvariablen reinschreibt.
Macht das bitte nicht ein Klient, muss für den einen
Vertrag, muss für den Klienten verständlich sein.
Wollen wir angucken, ob das im Mediatheksystem so ähnlich gemacht wird?
Schauen wir noch mal ganz kurz, dass ich euch nicht komplett
einen Blödsinn erzähle. Wir nehmen mal eine ganz einfache Klasse,
wie zum Beispiel die Klasse CD. Und schauen mal,
ob wir hier irgendwas finden, was mit dem Vertragsmodell zu tun hat.
Okay, wir haben ja erst mal so ein paar Zustandsfelder,
Interpret-Spiellänge, Kommentatitel, bla bla bla.
Jetzt kommt hier ein Konstrukt da. Ich glaube, jetzt
wird es langsam interessant. Also, ja, ihr seht schon,
hier wird dieses Adparam verwendet, um zu sagen,
ja, der Titelparameter, der hier unten definiert ist.
Falls nicht klar sein sollte, was es ist,
das ist der Titel der CD,
sehr hilfreicher Kommentar
Gut, dann haben wir hier so ein paar Requires.
Das ist so ein bisschen, ich sag mal, das sind sehr technische Requires.
In Java hat man ja das Problem, sagt man schon,
heutzutage, dass jede Referenzvariable den Wert nall haben kann.
Und in vielen Fällen will man das nicht haben. Und man sagt also,
mit diesen Vorbedingungen, lieber Klient, die Referenz,
die du mir hier reinsteckst, sowohl für Titel,
Kommentar als auch Interpret, die darf bitte nicht nahe sein.
Ja, ich will also schon, dass du über eine Referenz übergibst,
die wirklich auf ein Stringen zeigt und nicht die Nallreferenz.
Okay, werde ich zum Beispiel diese Vorbedingungen schon spannender finde,
fachlich, dass ich also sage,
es gibt keine CDs,
die eine negative Lauflänge haben oder eine Lauflänge Null
Es sei denn, das ist vielleicht ein Holing,
wo noch nichts drauf ist oder so,
aber wir verleihen keine Holing in der Mediathek.
Okay, also das sind jetzt nicht wahnsinnig spannende Vorbedingungen.
Dafür finde ich zum Beispiel die Nachbedingungen recht spannend.
Über die habe ich noch gar nicht geredet, zumindest nicht im Java-Code.
Ihr seht also hier mit diesem Entschuhe, dokumentieren wir,
worauf der Klient sich verlassen kann, nachdem dieser Konstruktor durchgelaufen ist.
Das sieht vielleicht erstmal recht trickreich aus,
was sagen wir denn hier? Wir versprechen also dem Klienten,
nachdem der Konstruktor durchgelaufen ist,
wenn du dann auf dem Objekt die Get-Titel-Methode aufrufst,
dann kommt da das Objekt zurück,
was du
mir als Titel reingesteckt hast
Ja, das, was du mich hier reinsteckst,
das ist ja hier dieses Titel.
Ich glaube, es ist sogar so schlau, das hervorzuheben.
Das ist genau das, was das Get-Titel zurückliefern wird.
Du musst also keine Angst haben, dass ich dir irgendwas anderes
zurückliefere oder den irgendwie noch verändere oder vielleicht leertasten abschneide oder so.
Ja, und es ist sogar dasselbe Objekt.
Ihr wisst ja noch, wenn ich Strings mit Gleichgleich vergleiche,
dann wird auf Identität geprüft und nicht auf Inhaltsgleichheit oder Zeichengleichheit.
Okay. Und man sieht hier auch, ja,
die entsprechenden Assort-Anweisungen zu diesen Requires, also hier,
wenn diese 3-Night-Checks durchgeführt und hier wird geguckt,
dass die Spielende größer ist als null.
Diese Entschuhes, die werden nicht durch entsprechende Assort-Anweisungen überprüft
Da gibt es also so ein,
das ist einer dieser vielen heiligen Kriege,
von denen erzähle ich ja gerne heilige Kriege in der Informatik,
wo gehören geschweifte Klammern hin und so und ist E-Mails oder Wim der bessere Eletor.
Das ist auch so einer,
sollte man die Nachbedingungen mit Assort-Anweisungen überprüfen und wir haben uns dazu entschieden,
dass ein SE2 nichts zu tun,
habe ich vor zwei Jahren irgendwie eine Viertelstunde drauf investiert,
warum wir das nicht machen.
Ihr könnt euch das vielleicht einfach ganz einfach erklären. Wenn man sowas sieht,
ja, also ich rufe einen Konstruktor auf und dann sollte man davon ausgehen,
dass der entsprechende Ghetter genau das zurückliefert,
was sich in den Konstruktor reingesteckt habe und das entsprechend auch für diese Eigenschaften.
Dafür schreiben wir ja normalerweise schon Tests in unseren Systemen.
Es gibt hier sicherlich einen Test in diesem System.
Ich will jetzt nicht meine Seele darauf verwetten,
aber hier ist er, der genau das testet,
dass die Dinge, die ich in den Konstruktor reinstecke,
hoffen wir doch mal, dass das tatsächlich so ist.
Hier. Genau hier ist der Test. Also, wo
wird die CD erzeugt? CD1, hier oben ist sie,
Gerd Medium, okay, ich weiß jetzt nicht, was dieses Gate-Medium macht.
Wahrscheinlich generiert sich das oder holt sich aus einer Datenbank und
so ein Medium, ist ja auch egal.
Auf jeden Fall wird hier getestet, dass genau die Informationen zurückkommen,
die ich da irgendwann mal reingesteckt habe,
wo uns das Gate-Medium einmal angucken,
dann ist es nicht so
Nicht so unsicher. Ja, guck mal hier. Hier
wird also der Konstruktor aufgerufen. Es werden diese vier Konstanten
übergeben. Wenn ich jetzt mit Alt-Pfeil links wieder zurückgehe,
wird hier sichergestellt, dass die Dinge,
die ich reingesteckt habe, auch tatsächlich wieder rauskommen.
Also, immer wenn ja eine Nachbedingung seht, die garantiert,
hey, nachdem diese Methode durchgelaufen ist, müsste eigentlich Folgendes gelten.
Könnt ihr euch ein bestehendes System eigentlich fast immer darauf verlassen,
dass es einen entsprechenden Test dazu gibt.
Und für euch selber heißt es,
ihr solltet solche Testlassen dann entsprechend schreiben oder solche Testfälle.
Ja. Okay. Vielleicht muss ich auch nochmal,
das wirkt vielleicht sonst ein bisschen vom Himmel gefallen
Also, warum wir das an dieser Stelle machen, ist einfach folgendes.
Es gibt diese klasse CD. Ja, die haben wieder
irgendwann mal geschrieben, das ist schon ein paar Jahre her.
Und als wir diese klasse CD geschrieben haben,
haben wir uns überlegt, naja,
irgendwann in ferner Zukunft werden wir mal benutzt werden von irgendwelchen Klienten,
die wir heutzutage noch gar nicht kennen.
Wie können wir sicherstellen, dass die uns nicht falsch benutzen?
Dann ist es sicherlich sinnvoll, dass wir das einmal prüfen.
Wer weiß, was uns alles kaputt geht in unserer Klasse.
Während zum Beispiel diese vier Zuweisungen, die ja quasi einen Effekt hervorrufen,
die dann diese vier Nachbedingungen nach sich ziehen,
da können wir ziemlich sicher sein, dass die funktionieren.
Einmal, weil wir die Tests haben und weil es hier
einfach so steht. Also hier habe ich die vier Zuweisungen,
hier habe ich die vier Nachbedingungen.
Auf derselben Seite Code sozusagen. Ja, wir sind
der Autor dieser Zuwart
Und wir sind auch der Autor dieser Nachbedingungen. Ja,
wir haben zum Beispiel die Klienten der Klasse CD,
haben wir keine Ahnung, wer den Code geschrieben hat.
Die könnten den größten Unsinn programmieren,
weil die vielleicht ein ganz anderes Modell davon haben,
was für eine CD ist oder wie man CDs zu benutzen hat.
Das vielleicht so als kleiner Ausflug. Warum es deutlich sinnvoller
ist oder lohnender, Vorbedingungen zu prüfen als Nachbedingungen.
Okay, und ich glaube, mittlerweile sollten auch,
sollte das überall konsistent auf unseren Aufgabenblättern so draufstehen.
Okay, ja, hier sieht man ja eigentlich sehr schön
Vorbedingungen, Nachbedingungen, Asshört. Gibt es dazu erstmal noch
irgendwelche Fragen? Ist das irgendwie klar? Ja,
das ist, glaube ich, so das trivialste Beispiel,
was man sich vorstellen kann
Dann gehen wir doch mit Flammen wieder zurück in unsere String-Liste.
Haben wir jetzt hier irgendwas vergessen? Ja, ist jetzt
die Frage, kann man hier irgendwelche sinnvolle Nachbedingungen hinschreiben?
An der Stelle glaube ich nicht, aber vielleicht kann man
das ja hier machen. Wir haben ja eben schon gesehen,
es gibt gerne diese Nachbedingungen, die sagen, das,
was du mir reinsteckst, kommt dann auch später wieder raus,
kann man das hier irgendwie auch machen?
Kann ich irgendwie sagen, das Element,
was du hinten an die Liste einfügst,
wirst du zurückbekommen, wenn du folgende Operationen aufrufst,
anschließend auf der Liste
Wir fügen ja hier in dieser Apent-Methode, fügen wir ja immer ganz hinten an.
Vielleicht kann man das ja erstmal auf Deutsch sagen.
Also ich würde gerne sagen, das Element,
was du mir übergibst, bekommst du zurück.
Wenn du dir das letzte Element in der Liste anschaust oder so,
wenn du dir anschließend... Ist das auf Deutsch erstmal verständlich?
Das Element, was ich hinten anfüge,
wird mir zurückgeliefert, wenn ich dann schon frage,
was ist denn das letzte Element?
Das ist doch
irgendwie klar, oder
Ja, und jetzt hat man halt hinter so einem Entschuh gerne ja einen Java-Ausdruck,
weil der weniger missverständlich ist als so ein deutscher oder englischer Satz.
Wie könnte man das denn in Java formulieren?
Was ist denn diese magische Operation, die es mir erlaubt,
das letzte Element mir anzugucken? Gibt es dafür überhaupt eine
Operation oder können wir das irgendwie zusammenbauen aus anderen Operationen?
Ja. Okay, also du hast gesagt,
Entschuhe,
Buffer an der Stelle
Minus eins ist das Element. Das ist erstmal aus Implementationssicht korrekt,
weil klar, wir wissen ja, was dieser Buffer ist.
Wir wissen, was dieses längst bedeutet. Ich hatte euch
ja schon eben gesagt, man muss immer vorsichtig sein,
dass dieser Vertrag sich ja an den Klienten richtet,
der diese Implementationsdetails gar nicht kennt.
Ja, das heißt, so direkt ist das ein bisschen blöd.
Gibt es irgendeine Operation, mit der ich mein Element liefern lassen kann,
ohne direkt auf den Buffer zuzugreifen als Klient?
Get, genau. Wie formuliere ich das denn jetzt?
Also quasi Get, ups. Und da brauche ich natürlich
die Methodenklammern, nicht die Ehre, Klammern.
Kann ich das so machen oder ist noch irgendwas nicht ganz koscher
Genau. Zack. Ups. Klammer auf, fehlt.
Ja? Also nachdem ich das Element an die Liste eingefügt habe,
kannst du die Get-Methode aufrufen, übergibst als Parameter Länge minus eins.
Also zum Beispiel, wenn zehn Elemente drin sind,
ist ja der erste Index 0, der letzte Index ist neun.
Also müssen wir noch einen abziehen. Und dann kommt genau
das Element zurück, was du mir hier reingesteckt hast.
Und dieses Entschuhe ist jetzt natürlich für uns das gelbe Lämmchen,
zu sagen, wir müssen einen Testfall dafür schreiben.
Warum nicht? In der Übung müsst ihr ja auch Testpferde schreiben.
Vielleicht wisst ihr gar nicht mehr, wie das geht.
Deswegen, ich mal die Mediathek wieder zu und sage mal
hier, ich möchte eine Testplasse hinzufügen.
J. Unit. Nennen wir das doch mal Stringlist-Test.
Ja, und J. Unit 4 soll dazu zum Projekt.
So. Meine Güte, wie sieht denn nochmal eine Testklasse aus?
Habt ihr doch euch bestimmt ewig nicht mehr angeguckt, oder?
Meistens ist es ja so, man hat irgendwie ein
privates Feld von dem Typ, den man testet.
Ich nenne das jetzt mal ganz einfach List,
dann erzeuge ich das jetzt auch einfach mal.
Dann brauche ich dafür kein Konstrukt beschreiben. Okay. Und
jetzt kann ich in diesen Methoden, die mit dieser Annotation
Test markiert sind, kann ich halt beliebige Tests reinschreiben.
Ich könnte zum Beispiel hier testen, Ja,
hinzugefügtes Element ist oder befindet sich am Ende.
So, dann kann ich jetzt schon zum Beispiel sagen,
Liste fügelt doch mal hinzu, hallo.
Und vielleicht fügen wir dann auch nochmal hin zu Welt,
einfach weil es Spaß macht. So. Wie sage ich denn
jetzt in J. Unit und da muss man höllisch aufpassen,
dass man es nicht verwechselt?
Wie sage ich denn jetzt in J. Unit?
Ja, oder wie kann ich das jetzt prüfen?
Wir gehen mal wieder zurück in unserer Stranger-Liste.
Ich mache die mal kurz zu, die stören jetzt eher.
Wie kann ich denn jetzt aus dieser Nachbedingung mich inspirieren lassen
und einen Testfall entsprechend schreiben.
Denn das hier ist ja sehr abstrakt und allgemein formuliert.
Das Element an der letzten Stelle ist das, was ich reingesteckt habe.
Und jetzt will ich das ja ganz konkret hierauf anwenden.
Ja. Ah. Ja. Richtig? Ja,
nehmen wir mal Welt,
Man könnte tatsächlich sagen,
längst minus eins, aber das ist sehr abstrakt formuliert.
Wir wissen ja, dass es die Länge zwei ist.
Und was ist zwei minus eins? Genau. So,
und ich könnte das jetzt im Prinzip,
ich kopiere mir diese Zahl mal nach hier und könnte hier auch zum Beispiel sagen,
hallo, ist dann sicherlich an der Stelle neu oder so.
So, okay. Wie führe ich das denn jetzt aus?
Da gibt es mehrere Möglichkeiten. Ich muss immer vorsichtig sein,
dass ich nicht Eclipse mit einer anderen IDE verwechsel.
Also es gibt IDEs, da kann man sagen,
ich will nur diesen einen Testfall ausführen,
geht das hier auch
Run as, ach guck mal, das geht tatsächlich. Also wenn ihr sagt,
ich will diesen einen Testfall nur ausführen, keine anderen,
dann seht ihr, hart geklappt, Balken ist grün.
Was ihr auch machen könnt, ist, ihr könnt hier
auf die Testklasse gehen mit der rechten Maustaste und sagen, oh
Gott, wo ist Ron er ist? Hier. Run as
J. Unitest. Dann werden alle Testfälle ausgeführt, nur nicht der eine.
Ich meine, momentan ist es ja nur der eine.
Aber wenn da jetzt noch mehr drin wären,
dann würden die auch alle ausgeführt werden.
Ich glaube, es reicht auch aus,
wenn die einfach hier oben auf diesen Käfer drückt.
Ach, den seht ihr nicht. Nee, das ist debugging.
Sorry, das ist was anderes. Es gibt auch einen
Shortcut dafür, den kann ich mir aber nie merken.
Steht ja zufällig dahinter hinter diesem Run erst.
Nee, steht ja leider nicht. Könnt ihr vielleicht herausfinden
, wie der Shortcut ist dafür
Okay. Ach, das ist doch schon mal ganz nett.
So. Gut. Wollen wir vielleicht auch noch die Operation einbauen,
dass ich an einer bestimmten oder an einer beliebigen Position was einfügen kann.
Also dieses Appent ist jetzt ja momentan so,
dass es mir immer ganz am Ende einfügt.
Das macht die Implementation recht leicht, weil ich keine Elemente verschieben muss.
Vielleicht will ich auch noch mal was an irgendeine bestimmte Stelle schieben.
Ich glaube, ich schiebe erst mal den Code nach oben.
Der gehört konzeptionell für mich nach oben. Wenn ihr
die Alttaste gedrückt habt, könnt ihr mit den Cursortasten einfach
Code durch die Gegend schieben.
Dann macht ihr euch nicht
eure Zwischenablage kaputt
Okay, das heißt,
ich wähle im Prinzip sowas ähnliches wie das Ependern,
könnt ihr den Code noch sehen, ja, oh,
das ist aber knapp, dann mache ich doch vielleicht mal lieber,
mache ich doch vielleicht mal lieber so,
dann ist es schön weit oben.
Also, ich will jetzt eine Operation bauen,
nennen wir sie mal Ad,
wo ich erst einen Index übergebe und dann das Element.
So, einfach, dass wir nochmal so ein bisschen mit Anays gearbeitet haben,
könnte eventuell in den nächsten sieben Tagen relevant sein.
Okay. Gut, was ist denn jetzt die Herausforderung bei
dieser Methode? Wenn wir uns nochmal vielleicht grafisch klar machen,
wie sieht denn unser Ära intern aus
Also ich male das Ehre jetzt mal irgendwie, vielleicht haben wir eins,
zwei, drei, vier, fünf, sechs,
sieben Elemente schon eingefügt und es ist noch Platz für drei Elemente.
Das soll sozusagen dieser Kommentar aussagen. Und bei der Pent
war es so unglaublich einfach, das zu implementieren,
weil wir einfach gesagt haben, naja gut, diese Nahlreferenz,
die überschreibe ich jetzt einfach mit dieser Elementreferenz.
Das war ja einfach. Vielleicht sollte ich ja nicht
X hinschreiben, sondern konkrete Buchstaben. Eins, zwei,
drei, vier, fünf, sechs, sieben.
Okay. Und dann könnte man hier einfach ein Haar hinschreiben,
dann wäre die Sache erledigt.
Das ist eine einzige Zuweisung. Wenn ich jetzt sage,
ich will an beliebigen Positionen was einfügen können,
dann erinnert euch vielleicht noch, dann hatten wir ja diesen lustigen Effekt,
ich kann jetzt nicht einfach hier mein Haar reinschreiben,
dann wäre das C ja weg.
Und die Liste wäre auch
gar nicht größer geworden
Ja, ich hatte gar keine Frage gestellt, weil du darfst trotzdem antworten.
Ah, wir müssen verschieben und wir müssen hinten anfangen.
Sehr gut. Sehr gut. Und da hatten wir irgendwelche komplizierten Vorschlafen geschrieben.
Vielleicht könnt ihr das ja auch nochmal machen. Das Tolle ist,
es gibt in Java eine Methode, die heißt System Array Copy.
Die ist extrem nützlich. Da übergibt man also fünf Argumente,
die ich hier besonders toll benannt sind. Ich glaube,
ich mache nochmal kurz rückgängig, dass ihr seht,
welchen Sündimethoden und die Argumente haben,
kann ich das nicht nochmal schön sehen.
Das war doch gerade so ein schöner Kommentar, den will ich nochmal sehen.
Liebes Eclipse-System, bitte lass mich nicht im Stich.
Also ich sage jetzt System A, da ist es.
Guck mal, hier sind die Parameter komischerweise besser benannt
Ich muss also erst mal sagen, von welchem Eric soll ich denn auskopieren?
Also ich kann auch theoretisch von dem einen erinnern, ein anderes Eric kopieren.
Von wo soll kopiert werden und wo soll es losgehen,
an welcher Position? Was ist das erste Element,
was ich kopieren soll, von links aus gesehen?
Die Reihenfolge müssen wir nicht besonders berücksichtigen. In welches Eric
soll reinkopiert werden und wo soll da das entsprechende Element hinkopiert werden?
Also wo ist dann im Ziel erregt, das linke Statement quasi?
Und wie viele Elemente sollen kopiert werden?
Toll, dann brauchen wir keine eigene Schleife schreiben.
Okay, ja, das will ich jetzt haben.
Ach guck mal, jetzt heißen sie auf einmal anders.
Stand da nicht eben arg 081 und so weiter?
Oder habe ich mir das eingebildet? Ja, Magie,
keine Ahnung, warum das so ist.
Hat er im Hintergrund vielleicht irgendwas nachgeschaut
Okay, aus welchem Ära wollen wir kopieren? Das ist ja
unsere Buffer Air. Ein anderes gibt es ja gar nicht,
ne? Wo müssen wir denn jetzt anfangen zu kopieren?
Vielleicht mache ich mal Folgendes als kleine Hilfe. Machen wir
mal hier die Indizes drüber. Das sind ja die Indizes
der Elemente, ne? Und nehmen wir mal an,
ich will jetzt anstelle zwei einfügen, also quasi hier.
Da will ich jetzt einfügen. Wie soll das Ära dann
anschließend aussehen? Das A und das B sollen immer noch
an derselben Stelle stehen und dann ist hier irgendwie,
man weiß es noch nicht genau, was hier stehen wird.
Und dann C, D, E, F,
G und hier dann das, was da vorher auch stand, ne?
Gut. Und dann mache ich vielleicht mal der Übersichtlichkeit halber,
oder wenn ihr nicht so gute Augen habt,
die Indizis nochmal darunter
Jetzt ist also meine Frage an euch, in dem Quell-RAL.
Was ist das linkeste Element, was ich kopieren muss?
Welchen Index hat das? In unserem konkreten Beispiel.
Ja. Der Intager Index, richtig. Sehr gut.
Du hast also direkt von der Zwei abstrahiert,
dass die ja von dem Index herkommt.
Gut. In welches RAL will ich kopieren?
Das ist dasselbe. Und wo muss jetzt das Element,
was an der Position Index steht,
wo soll das jetzt landen
Genau, in Expos 1,
also soll ja nach einem nach rechts verschoben werden, ne?
Sehr gut. Und wie viele Elemente müssen wir insgesamt verschieden?
Das ist ja eine spannende Frage. Da müssen wir uns
vielleicht erst mal ganz kurz überlegen. Wir hatten ja hier die Länge,
hier war die, ich kann nicht Englisch schreiben.
Hier war die Länge 7, richtig? Länge 7 und
Index war 2. Wie viele Elemente müssen wir verschieben?
Wir müssen 1, 2, 3, 4, 5 Elemente verschieben.
Kommt die 5 jetzt, fällt die vom Himmel oder hat
die 5 irgendwas mit der 7 und der 2 zu tun?
Richtig. Links,
minus minnex
So. Ach so, habe ich jetzt für mich,
ach so, der Unterstrich fehlt. Gut. Dass höre
ich nochmal so ein bisschen in diese Erry-Strukturen reindenkt und wo
fängt das an und wo hört das auf und so,
das ist, glaube ich, auch nicht schlecht.
Okay, dann nehme ich das mal wieder weg. Das ist ja so etwas,
wie ich oft an solche Probleme rangehe, dass ich mir sage,
ich kann das nicht von vornherein abstrakt lösen.
Ich mache mir erstmal ein konkretes Beispiel mit möglichst krummen Zahlen. Ja,
ich nehme immer gerne sieben und zwei und drei und so und auch,
dass das Erry zum Beispiel nicht genau in der Mitte,
also macht es zum Beispiel nicht,
dass irgendwie fünf Elemente benutzen und fünf sind noch nicht benutzt,
dann kommt ja manchmal auf falsche Formen wahrscheinlich.
Und wenn ich mir das dann für einen Fall klargemacht habe,
sage ich, naja,
die fünf wieder nicht vom Himmel,
das kann ja eigentlich
nur sieben minus zwei sein
Okay, dann lösche ich das jetzt mal wieder.
Und dann können wir uns ja überlegen, ob man dann
dafür jetzt auch gute Vor- und Nachbedingungen formulieren kann.
Also diese Parameter nehme ich jetzt mal wieder weg.
Entschuldigung? Oh, sehr gut. Plus plus längs
haben wir vergessen. Jetzt haben wir in der Übung auch
den Fall, dass euch ein Fehler im Programm auffällt.
Schaut euch das Programm an und sagt, oh,
hier ist ja ein Fehler.
Und was man dann gerne macht, ist folgendes.
Man schreibt einen Test, der diesen Fehler aufdeckt.
Den kann ich einmal ganz kurz mit euch zusammenschreiben.
Also, Test, nehmen wir das doch mal
Hinzufügen an Position, vergrößert Liste. Gut,
dann sage ich jetzt also an meine Liste,
füge ich doch mal,
ich darf ja nur an Position 0 was einfügen,
das habe ich doch noch gar nicht getestet,
aber ist klar, tue ich da auch mal Fred rein.
Und dann gehe ich davon aus,
dass anschließend die Liste, die Länge eins hat.
Das ist so ein sinnvoller Test, oder?
Dann schauen wir doch mal, ob das funktioniert.
Ich klicke jetzt hier rauf und sage Run as J. Jungtest.
Und es klappt nicht. Es sagt mir also,
hey, du hast eins erwartet,
aber es kam tatsächlich null zurück
Gut, jetzt haben wir also, also erster Schritt,
wir haben den Fehler gefunden erstmal, so,
oder wir hatten eine Vermutung, dass da ein Fehler ist,
dann haben wir den Jay-Unit-Test geschrieben, der den Fehler aufdeckt,
der Balken ist so rot, sehr gut,
dann können wir doch jetzt den Fehler beheben.
Was muss ich denn jetzt tun, um den Fehler zu beheben?
Hat eine Idee. Ja. Genau. Die Länge muss
um einen mehr werden, ne?
Dann schauen wir doch mal,
ob der Test jetzt durchläuft
Ja, jetzt läuft er durch. Sehr gut. Das
finde ich ganz witzig. Also ich habe den Fehler nicht
absichtlich eingebaut. Ich war so fasziniert von dieser Methode,
dass ich ganz vergessen habe, dass ich ja noch die Länge anpassen muss.
Okay, dann kommen wir wieder zum... Kann man das eigentlich
auch in dem Vertragsmodell ausdrücken, dass ich irgendwie sage,
längs liefert anschließend einen um eins größeren Wert.
Das ist ja etwas, was man gerne irgendwie ausdrücken können würde.
Also man kann das in Java so direkt leider nicht ausdrücken.
Also wenn ich jetzt sowas hier als Code reinschreiben müsste sowieso nicht.
Was in Eifel geht, ist zu sagen,
Ich schreibe das einfach mal hin und dann diskutiere ich drüber.
So, das wird tatsächlich von Eifel unterstützt.
Also wenn ihr das in Eifel programmieren würdet,
dann würde das auch tatsächlich zur Laufzeit überprüft werden.
Das Eifelsystem sieht also, oh,
hier interessiert sich jemand für den alten Wert von längst plus eins,
dann merke ich mir den mal.
Und nachdem der Code durchgelaufen ist, gucke ich mal,
ob das jetzt gleich ist mit dem neuen Wert von längs.
Und da wir ja in Java die Nachbedingungen nicht überprüfen,
ist es auch in Ordnung, das so als Kommentar einfach so hier reinzuschreiben.
Wenn man einfach weiß, was dieses Old bedeuten soll,
dann versteht man das, glaube ich, ganz gut.
Das finde ich irgendwie ganz nett. Also die Länge,
die da zurückkommt, ist die alte Länge plus eins
Okay. Was man zum Beispiel auch noch sagen könnte,
ist, jetzt habe ich leider diese Grafik wieder gehört.
Man hat ja gesehen, A und B haben ja ihre Position gar nicht verändert.
Ihr könntet das also wahrscheinlich noch irgendwie auf Deutsch,
kriegt ihr das gerade noch hin,
die Elemente mit Index kleiner als Index,
behalten ihre Position bei und alle danach verschieben sich um eine Position nach Hels.
Ihr könnt ja mal überlegen, ob ihr irgendwelche Hilfsmethoden schreibt,
die erlauben das irgendwie schön als Java-Ausdruck da auszudrücken.
Okay. Kann ich auch noch was requiren, was irgendwie spannend ist?
Ich glaube, hier kann ich nur dasselbe requiren,
was ich oben auch required habe, oder?
Also ich würde mir jetzt quasi das hier irgendwie nehmen und
darunter kopieren
So irgendwie. Ups, was habe ich da gemacht?
Nein, das ist hört, wollte ich kopieren,
nicht den Vertrag ab in dem Kommentar hier.
Natürlich müsste ich mir die Requires auch entsprechend kopieren. Also man sieht schon,
man wird immer sehr verleitet dazu, Dinge zu kopieren.
Das ist irgendwie nicht so schön, ja.
Stimmt, diese ganzen Nahüberprüfungen könnte man auch mal machen.
Wenn du mir keinen Livestream reingesteckt hast,
dann kann ich auch garantieren, dass keiner zurückkommt und so.
Das finde ich immer fachlich nicht so interessant,
aber das müsste eine Übung tatsächlich auch machen, ja.
Ja. Nein, sehr gut. Nächster Testfall. Wir haben
das Element ja noch gar nicht in den Buffer reingeschrieben.
Also würde ich jetzt testen,
ich kopiere mir das jetzt einmal ganz kurz,
weil das schnell gehen muss, sagen wir mal,
hinzufügen an Positionen, schreibt Element in Liste.
Also würde ich doch sagen, Fred sollte an Position null
dann auch stehen. Wenn ich an Position null einfüge,
dann sollte er da auch stehen.
Also ihr könnt die Tests nochmal ausfüllen mit diesem tollen Button
, kann man den sehen, ja?
Das wird jetzt fehlschlagen. Ja, ich will immer speichern,
Dankeschön, liebes Eclipse. Tja, hat nicht funktioniert.
Ich finde das toll, dass ihr alle meine Fehler seht.
Ich habe diesen Fehler auch nicht absichtlich eingebaut. Gut,
dann machen wir das doch einmal ganz kurz. Also,
Buffer an der Stelle Index, soll das Element sein.
Haben wir den Fehler behoben, jetzt führe ich
den Test aus
Oh, jetzt geht's. Tja, das ist doch sehr schön.
Okay, ich muss auch noch zwei Dinge zeigen. Diese Asserd-Anweisung,
die ihr hier seht, die ihr zur Laufzeit ausgeführt werden sollen,
die werden nur unter bestimmten Bedingungen ausgeführt.
Wir haben euch das auf dem Aufgabenblatt schön gezeigt.
Jetzt zeige ich euch mal ganz kurz, wenn ihr hier
bei den Preferences eingebt, was muss man denn da eingeben?
Nee, ich weiß auswendig, wo ich hin muss.
Ich muss sagen, Java, Installs, RIs, genau.
Richtig. Also immer dann,
wenn ihr den Rechner wechselt unten in den Laboren,
müsst ihr das wieder neu einstellen.
Also versucht das irgendwie im Hinterkopf
zu behalten
Ihr müsst dann sagen, minus-e-a. Das kann man sich
, glaube ich, nicht besonders gut merken, oder?
Ich will euch einmal ganz kurz zeigen, wie wir damit umgehen.
Wir haben in der Mediathek einen Spezialtest eingebaut,
der testet, ob ihr diese Einstellung vorgenommen habt.
Ich kann ja einfach mal hier alle Tests durchlaufen lassen.
Run as Jere Unitches und dann werdet ihr sehen,
dass ein Test nicht durchläuft.
Seht ihr, einer ist fehlgeschlagen, as hird test?
Den gucken wir uns einmal ganz kurz an. Das ist
so ein kleiner, schöner Brainteaser. Dieser Test testet also,
ob man diese Einstellung vorgenommen hat, was macht denn dieser Test?
Das sieht ja eigentlich ganz einfach aus, ne?
Also wir haben erstmal eine lokale Variable,
setzen sie auf Fouls.
Und was macht jetzt Zalo 19
Es hat, es hört es enabled gleich true.
Es sieht irgendwie komisch aus, oder? Ich habe die
doch gerade auf False gesetzt. Warum sollte sie denn jetzt true sein?
Ja. Ja. Zugewiesen, das ist der spannende Punkt.
Du hast genau die beiden spannenden Punkte hervorgehoben. Also Zeil
und 19 wird nur ausgeführt, wenn du Sessions aktiviert sind.
Und das, was hier gemacht wird,
ist ja kein Vergleich, sondern eine Zuweisung.
Ein Gleichheitszeichen. Java heißt ja,
ich will einer Variable einen neuen Wert zuweisen
Das heißt also, diese Zuweisung,
das ist jetzt true an die Variable, das 40 Nable,
passiert nur, wenn die Asserts enabled sind.
Und dann kann ich anschließend prüfen, ob diese Zuweisung stattgefunden hat.
Das ist so ein kleiner, kriegt man so einen kleinen Verränker im Gehirn,
weil es sieht irgendwie so aus, als würde hier ein Vergleich stehen,
aber es ist in echten Zuweisungen.
Okay, und dann steht hier eben,
wie man es machen muss, ich mache das nochmal ganz kurz,
dass ihr live gesehen habt, wie es geht.
Genau, da habe ich mich nicht hingeklickt,
dann sagt man hier, edit.
Und dann sagt man hier minus EA.
Heißt also nicht Electronic Arts, sondern Assessions Enabled und jetzt
führe ich den Test nochmal aus
Ja, und dann haben wir es. Ja,
und eure Aufgaben werden dann bestehen,
mal das Vertragsmodell anzuschauen, wie es momentan so ist,
das so ein bisschen zu beschreiben, wie das aussieht,
was es bedeutet.
Und dann vielleicht auch mal den einen oder anderen Vertrag sich selber auszudenken.
Okay, meine Zeit ist leider schon wieder um.
Bis nächste Woche