Ja, hi, wie ihr bestimmt schon mitbekommen habt,
wird es diese Woche ums Vertragsmodell und ums Testen gehen.
Ich werde dazu auch wieder zwei Videos machen in dem ersten,
werde ich mit euch ein ganz kleines Beispielprojekt anlegen und über die erste Hälfte des Vertragsmodells,
nämlich über die Vorbedingungen reden und im zweiten Video werde ich
ein bisschen was zu den Nachbedingungen und zum Testen erzählen als Projekt,
hatte ich mir etwas überlegt, was wir schon aus SE1 kennen,
nämlich die Implementation einer Arrailist nicht erschrecken.
Wir machen da nichts Großartiges, keine Indexverdopplung oder ähnliches.
Das Ganze soll uns nur als Grundlage, als Beispiel dienen,
anhand derer wir dann über das Vertragsmodell reden können.
Ich lege jetzt also quasi ein neues Projekt an,
gehe hier oben auf Pfeil, New, Yava Project,
gebe dem ganzen Namen, wir wollen eine Raillist machen,
also nenne ich es mal Raillist und sagt Finish und da ist es schon und dann werde ich hier in dem Source Folder
Eine neue Klasse erstellen, rechte Maustaste, New Klaas.
Dann geht da so ein kleines Fensterchen auf.
Wir werden jetzt der Klasse auch einen Namen geben.
Ich möchte jetzt nicht wieder Arailist nehmen,
weil es ja schon eine Java-Klasse gibt, die Arailist heißt.
Aber ich mache mit euch eine Arailist, in die Strings dürfen,
also nennen wir das Ganze Stringlist. Und ein weiteres,
ganz cooles Feature, was ich euch zeigen möchte,
ist, wenn man hier unten bei Constructors from Superclass
einen Haken setzt und dann auf Finish geht
Dann macht einem die IDE nicht nur die Klasse,
sondern auch gleich ein Konstrukt dazu.
Konstrukte wissen wir ja, heißt, wie die Klasse,
hat keinen Rückgabetyp, nicht mal Volt.
So eine Arrailist beruht ja auf dem Prinzip der wachsenden Arrays.
Das heißt, es liegt eine Ray unter der Haube.
Deswegen deklarieren wir uns jetzt mal eine private Exemplarvariable vom Typ
String Array. Und weil wir Dinge reintun wollen,
nennen wir Storage
Wir wissen ja, oder wir erinnern uns,
wie so eine Ray-Variable deklariert wird.
Vorne steht immer der Element-Typ. Danach die eckigen Klammern,
dann der Name. Jetzt müssen wir diese Variable noch initialisieren
und wie sich das gehört, machen wir das im Konstruktor.
Schreiben also wieder Storage und weisen jetzt ein neues Element der
Klasse String Array zu und müssen jetzt in die eckigen Klammern schreiben,
wie groß denn diese Ray werden soll.
Das machen wir nicht variabel
Das brauchen wir heute eigentlich gar nicht. Wir schreiben einfach
nur eine 1000 rein. Das sollte für alles,
was wir heute so vorhaben, ausreichen.
Und wenn wir uns dann weiter an SE1 erinnern,
wissen wir ja, es gibt zwei Kennzahlen für so ein Array.
Das eine ist die Kardinalität und das andere ist die Kapazität,
Kapazität heißt, wie viel passt rein.
Das sind unsere 1000 hier. Kardinalität sagt,
wie viele Elemente sind gerade drin. Das brauchen wir,
also legen wir uns eine private Exemplare euriable vom Typ Int
an und nennen sie Kart
Diese Variable ist, weil sie vom Typ Int ist,
default-mäßig bereits mit einer Null belegt.
Ich finde es aber besser lesbar, wenn man es nochmal explizit zuweist.
Das mache ich hier im Konstruktor und weiß dieser Variablen,
den wäre null zu. Wie gesagt, eigentlich überflüssig,
weil das der Default wert ist, aber es dient dann schon der Lesbarkeit.
Jetzt können wir uns ja eine Methode überlegen, die unsere Stringlist haben soll.
Ich habe daran gedacht, dass wir ein Element,
also ein String entgegennehmen, und einfach hinten anhängen.
Also machen wir uns eine öffentliche Methode, die nichts zurückgibt
und nennen die Appent, wo ja was angehängt werden soll.
Die Methode nimmt einen formalen Parameter vom Typ String,
entgegen und den nennen wir einfach mal Element.
Und ihr im Rumpf passiert dann die Funktionalität Wir wollen ja ein,
dieses Element, das wir übergeben, hinten an die Liste anhängen.
Also brauchen wir wieder Storage. Wir müssen hier sagen,
an welche Stelle, das ist die Stelle Kart.
Das liegt daran, dass Kardinalität ja die Anzahl der Elemente
angibt, die in der Liste gerade drin sind.
Wir fangen aber bei null an zu indizieren Also es gibt Card
uns auch immer die erste Stelle in dem Array an,
an der noch ein freier Platz ist.
Und wir weisen hier halt das zu, was wir oben
als Parameter übergeben haben und haben dann das Element in die Liste eingefügt.
Jetzt haben wir allerdings auch ein Element mehr,
also müssen wir auch Card inkrementieren.
Und haben jetzt also quasi eine Methode gemacht,
mit der wir hinten an die Liste einen String,
den wir übergeben,
anhängen können
Und als zweites würde ich mit euch gerne eine Methode machen,
die uns das Element an einer bestimmten Innenexposition zurückgibt,
die ist wieder public.
Hat diesmal einen Rückwerbetyp, nämlich String.
Heißt Get Element. Übernimmt einen formalen Parameter vom Typ Int
, weil wir wollen ihn in Exposition angeben können.
Deswegen nennen wir den Parameter
auch Index
Und im Rumpf wieder die Funktionalität. Hier wird uns das
Ganze deswegen rot unterkringelt, weil wir hier ja einen Rückgabetyp
ungleich void haben und wir noch gar keine Return-Anweisung haben.
Wenn ich jetzt hier mit der Maus also drüber gehe,
dann wird gesagt, this method mast return a result of type string.
Und das machen wir jetzt auch mal,
indem wir sagen Return. Etwas, was in unserem Storage
drin ist
Und zwar genau das, was an der Indexposition Index ist.
Das ist also im Prinzip die Basis-Implementation für unser Beispiel.
Und jetzt können wir uns ja mal überlegen, welches Voraussetzungen sind,
damit wir hier diese Methode jeweils letztes geschrieben haben, sinnvoll benutzen können.
Die hängen ganz sicher mit dem übergebenen Parameter,
also mit Index zusammen. Als allererstes wissen wir ja,
dass so ein Index nicht negativ werden kann,
Deswegen ist unsere erste Voraussetzung, dass der Index größer gleich null sein muss.
Und weiterhin macht es keinen Sinn, ergibt es keinen Sinn,
wenn ich richtiges Deutsch sprechen möchte.
Eine Indexposition zu haben, die größer, der gleich Card ist,
weil an der Position schlicht und einfach nichts steht.
Solche Voraussetzungen werden mit Assoirsions überprüft. Die sind immer auf
die gleiche Art und Weise aufgebaut, als allererstes das Schlüsselwort Assert.
Dann ein Bulsha-Ausdruck,
hier Index
Größer, gleich. Null. Damit könnten wir
schon fertig sein. Allerdings ist es üblich, danach noch
eine sinnvolle Fehlermeldung zu schreiben. Sowas wie Index kann nicht...
Negativ sein. So eine Fehlermeldung wird immer dann ausgegeben,
wenn der bulsche Ausdruck da vorne Falls ergibt.
Und die zweite Voraussetzung hatten wir ja gesagt,
dass der Index kleiner als Card ist.
Und auch hier schreiben wir einfach rein, Index.
Muss. Kleiner. Kein Doppelpunkt, sondern Card sein.
Im Kolon ans Ende. Und schon haben wir
sinnvolle Voraussetzungen für das richtige Benutzen
Unsere Methode geschrieben und überprüft. Allerdings haben wir hier noch ein Problem.
Und zwar sind diese Assurtions ja an der Schnittstelle nicht sichtbar.
Jetzt wollen wir es einem Klienten dieser Klasse auch nicht zumuten,
dass er in den Code geht und da überall nach Asserd-Anweisungen sucht.
Außerdem soll der Klient dieser Klasse auch nicht in den Code
gehen.
Das Ganze nennt man Geheimnisprinzip
Das besagt, dass der Klient einer Klasse nur so viel
über diese Klasse wissen soll, wie er unbedingt braucht.
Und diese Klasse sinnvoll benutzen zu können, insbesondere soll er keine Implementationsdetails kennen.
Das Ganze möchte ich an einem kleinen Beispiel verdeutlichen,
stellen wir uns mal vor, wir haben einen Programmierer,
der schreibt eine Klasse, die soll Dinge in Listen tun.
Und weil es ein ordentlicher Programmierer ist,
wird nach jedem Einfügen in die Liste
diese Liste alphabetisch sortiert
Jetzt haben wir einen anderen Programmierer, der soll eine Klasse schreiben, die diese eben beschriebene Klasse benutzen soll. Der kennt die Implementationsdetails, weiß,
dass immer alles alphabetisch sortiert ist und weiß auch ganz genau,
wenn ich was an Indexpositionen in Exposition null mir raushole,
dann kriege ich immer was mit einem A. Jetzt ist es so,
dass der erste Programmierer,
der diese Klasse mit der Liste geschrieben hat,
50 Millionen Euro im Lotto gewinnt, sagt,
hey Leute, es war schön mit euch,
sich seine eigene Insel kauft und sich für den Rest
seiner Tage die Sonne auf den Bauch scheinen lässt,
das gönnen wir ihm auch
Allerdings brauchen wir logischerweise einen Ersatz. Also kommt ein neuer
Kollege in die Firma, der diese Klasse dann betreut.
Der denkt sich, Moment mal, in den Anforderungen für
diese Klasse steht überhaupt gar nichts drin von Elphabetisch sortieren.
Wieso sollte ich das machen? Sortieren ist teuer,
teuer im Sinne von Rechenzeit, sortier Algorithmen, Kosten,
richtig viel Rechenzeit. Also baut er, weil es in
den Anforderungen gar nicht gefordert ist, diese Sortierung aus Und die Klasse,
die diese Klasse mit der Liste benutzen soll, fliegt auf einmal auseinander,
weil an Indexposition null jetzt kein Arm mehr ist, sondern meinetwegen V.
Ja, das ist ein ganz kleines,
sehr banales Beispiel, weil es zeigt ein bisschen,
warum man nicht als Klient einer Klasse über Implementationsdetails dieser Klasse Bescheid wissen sollte.
Okay, was ist die Lösung? Wir schreiben Schnittstellenkommentaren.
Machen wir hiermit slash Stern, Stern,
vielleicht machen wir aus den Sternen noch Sterne.
Ente, steht hier schon mal ein bisschen was,
was wir jetzt hier heute nicht brauchen.
Das sehen wir gleich mal weg. Und wollen jetzt hier
sagen, was sind denn die Vorbedingungen? Die werden immer
mit Ed Require gekennzeichnet und dann schreiben wir halt hin Index.
Größer gleich. Null. Und die zweite Vorbedingung war ja Index Kleiner Kart.
So, jetzt sind die Vorbedingungen im Prinzip an der Schnittstelle sichtbar.
Wir haben nur noch ein ganz kleines weiteres Problem.
Und zwar beziehen wir uns hier ja an dieser Stelle
auf das Exemplar war, ja, Blickcard.
Die haben wir aber private gemacht. Das heißt,
diese Exemplarvariable ist an der Schnittstelle eben nicht sichtbar.
Was tun wir dann? Wir könnten sie natürlich public machen
. Öffentliche Exemplarvariablen sind immer oder fast immer eine ganz,
ganz schlechte Idee
Aber wir wissen ja,
wenn wir den Wert einer Exemplarvariablen nach außen geben wollen,
können wir das mit einer öffentlichen Methode machen,
die einfach diesen Wert returnt.
Und das machen wir jetzt auch. Wir schreiben uns ein Ghetter
. Deswegen ist logischerweise Public, gibt ein Int zurück.
Public schreiben wir mit Eltern, steht auf Public da,
nennen diese Methode Get Card.
Die nimmt keine Parameter entgegen
Und im Rumpf dieser Methode schreiben wir einfach Return, Card.
Und jetzt ersetzen wir einfach die Exemplarvariable durch die öffentlichen Methode,
die den Wert dieser Exemplarvariable zurückgibt. Und das machen wir
nicht nur hier im Kommentar, sondern auch in Athird.
Und schon haben wir jetzt An der Schnittstelle dieser Klasse alles für den Klienten sichtbar,
was er braucht, um diese Methode sinnvoll zu benutzen.
Das war es jetzt erst mal zu den Vorbedingungen.
Jetzt erzähle ich noch mal ganz kurz was zu den Nachbedingungen,
Nachbedingungen, bezeichnen das, worauf sich ein Klient verlassen kann,
nachdem die Methode durchgelaufen ist.
Das heißt also, wenn der Klient die Vorbedingungen einhält,
darf er sich darauf verlassen,
dass nach dem Durchlaufen der Methode die Nachbedingungen erfüllt sind
Die Nachbedingungen werden allerdings im Gegensatz zu den Vorbedingungen nicht mit Assoirsions geprüft,
sondern für die Nachbedingungen werden Testfälle geschrieben.
Warum das so ist,
dass Vorbedingungen mit Assert geprüft werden und Nachbedingungen mit Testfällen,
das erzähle ich euch im nächsten Video