Hey, jetzt zum zweiten Teil der Vererbung der Implementationsvererbung.
Hierzu auch wieder ein kleines Beispiel. Diesmal mit einer Bank und Konten.
Am besten, ich zeige euch erstmal dieses kleine Beispielprojekt.
Wir haben hier die klasse Girokonto und Sparbuch mit den üblichen Verdächtigen,
unter den Methodenzahlereinhebe ab. Gib Saldo. Wir haben hier
eine Bank, noch mit einem leeren Konstruktor. Das wird
sich ändern. Im Moment sieht es noch komisch aus,
eine Methode, um ein Girokonto zu eröffnen,
eine Methode, um ein Sparbuch zu eröffnen und eine Methode,
um ein Girokonto oder ein Sparbuch nach außen geben zu können an einen Klienten,
als externen Klienten haben wir hier die Methode Start-up.
In der Main-Methode wird eine Bank erzeugt, ein Girokonto,
ein Sparbuch angelegt. Und eine Methode aufgerufen,
die eine Bilanz veröffentlicht, das besteht hauptsächlich darum,
dass daraus drin,
dass ein Girokonto ein Sparbuch Gebühren abgezogen und Zinsen gut geschrieben
werden und dann wird er danach entstandene Saldo auf der Konsole ausgegeben
Aber gucken wir uns zuerst mal die beiden Konten an.
Für mache ich das andere hier mal zu und das Bild
aus. Wenn wir die beiden vergleichen,
dann sehen wir, dass sie sehr viel gemeinsam haben.
Beide haben Saldo, beide haben Zeile ein, Heber ab.
Diesmal im Vergleich zum Video vorher mit den Interfaces sind die Implementationen auch gleich.
Das ist vielleicht wichtig. Und wir haben dann hier noch Heber ab,
gibt Saldo und alles passiert auf gleiche Art und Weise.
Das heißt, wir haben eine Menge doppelten Code, doppelter Code,
bedeutet, ganz oft Wartungsprobleme, wenn was verändert werden soll,
muss es an ganz vielen Stellen verändert werden.
Das wollen wir nicht so gerne. Also machen wir jetzt
eine gemeinsame Oberklasse, in die wir die Gemeinsamkeiten dann reinziehen.
Ich mache hier also eine neue Klasse,
nennen die Konto, weil beides sind ja Konten,
Sparbuch und Girokonto und sorgt dann erst mal dafür,
dass Sparbuch und Girokonto von Konto erben.
Schlüsselwort ist Extense
Dein Konto. Und das Gleiche bei Girokonto.
Und jetzt kann ich die Gemeinsamkeiten in von Sparbuch im Girokonto
in die gemeinsame Oberklasse Konto ziehen.
Das ist zum ersten Mal der Saldo.
Dann schneide ich hier aus und packe ihn ins Konto
Und schon kriegen wir von Sparbuch geschimpft,
weil er sagt, hey,
Saldo kenne ich gar nicht mehr, das liegt daran,
dass die Variable Saldo hier ja private ist und nur innerhalb dieser Klasse sichtbar ist.
Public wollen wir sie nicht machen, aber es gibt ein
Zugriffsmodifikator, der heißt Protected. Und der sorgt dafür,
dass der Saldo innerhalb der Klasse Konto und in allen erbenden Klassen,
aber sonst für keine weiteren Klassen sichtbar ist.
Und schon sehen wir, dass Gemäcker, hört hier auf,
wir wollen dann im Konstruktor ein Saldo übergeben können,
im Konstruktor vom Konto,
also machen wir in
Saldo. Und schreiben hier, ich weiß nicht, dass hier der Variablen Saldo zu.
Jetzt kriegen wir schon wieder geschimpft, weil es wird gesagt,
hey, die Oberklasse von Sparbuch hat einen Konstruktor,
der einen Parameter entgegennimmt, wo soll er den denn,
oder wo soll sie die denn hernehmen?
Also sagen wir super und übergeben da Saldo
Super ist immer der Konstruktor der Oberklasse.
Super ist der Konstruktor in diesem Fall der Klasse Konto.
So, und jetzt können wir noch weitere Gemeinsamkeiten rausziehen.
Das ist hier Zahle ein. Kontheber ab.
Und außerdem noch Kiebseil. Und das war auch das,
was wohl in Sparbuch als auch in Girokonto drin war.
Packen wir hier auch ein. Und dann machen wir noch
ein paar hässliche Leerzeilen weg,
Nur weil ich sie nicht mag. Und mit Giro-Konto,
da können wir es einfach rauslöschen, weil wir müssen hier
ja nichts mehr hochkopieren, das haben wir ja schon gemacht.
Hier haben wir auch wieder einen super Aufruf,
den wir brauchen, also den Aufruf des Konstruktors, der Oberklasse.
Und schon kriegen wir auch nicht mehr geschimpft. Und wenn
wir diese Methoden jetzt löschen, und diese können wir das tun,
weil wir diese Methoden hier oben ja reingetan haben
Und die klassische Sparbuch- und Girokonto, das erbt,
was in Konto drin ist,
sowohl die Variablen oder die Variable in dem Fall,
als auch die Methoden.
Was bedeutet das jetzt für unsere Bank? Wir können uns hier
die beiden Exemplarvariablen sparen, indem wir uns wieder eine Liste machen.
Das ist dann insgesamt flexibler Element, typisches Konto.
Und wir nennen es mal Konten
Dann müssen wir die Liste natürlich erzeugen und Content zuweisen.
Gleich. Raillist. Elementtyp ist logischerweise Konto. Klammer auf
, Klammer zu Semikolern. List kennt er nicht,
das kennen wir schon aus dem letzten Video.
Also importieren wir es, Araillist, kennt er auch nicht,
importieren wir auch. Und jetzt haben wir hier eröffnet Girokonto,
das verallgemeinern werden, indem wir einfach sagen,
eröffne Konto
Und dann hier als statischer Typ auf ein Konto hin.
Und wir nennen die Variabler auch Konto. Und das machen wir
dann indem wir das Konto, was als Parameter hier übergeben wird.
Einfach zu Konten hinzufügen. Da bietet er mir schon
ein Konto an, was sehr zuvor kommt.
Und jetzt brauchen wir hier auch diese Methode nicht mehr,
weil wir hier eine Methode haben,
mit der wir irgendein Konto,
also irgendeine von Kontoerbende Klasse reinstecken können
Wir wollen auch jetzt nicht mehr ein Girokonto zurückgeben,
sondern eine Liste von Konten. Und deswegen nennen wir es
auch nicht mehr, es gibt Girokonto, sondern gibt Konten.
Und wir return, die Konten. Und Sparbuch brauchen wir
auch nicht mehr als Gettern. So, dann haben wir
hier auch schon wieder einiges an Code gespart.
Hier haben wir doppelten Code in die Oberklasse gezogen.
Hier haben wir Code gespart, weil wir hier den allgemeineren Typ der Oberklasse nehmen können.
Was bedeutet das jetzt für Start-up? Wir haben nicht mehr
die Methode, eröffnet Girokonto, der ist ein Sparbuch,
sondern wir haben nur noch die Methode eröffnen Konto.
Das macht uns nichts, das benennen wir hier einfach kurz um.
Und jetzt kommen wir zur Methode für öffentliche Bilanz.
Wir können uns nicht mehr in einzelne,
doch wollen uns auch nicht mehr in einzelnes Girokonto aus Sparbuch holen,
sondern wir wollen uns eine Liste holen.
Und zwar die Liste mit sämtlichen Konten, die in dieser Bank vorhanden sind.
Also List Element Chip Konto, nennen wir wieder Content.
Dann gleich Bank und die hat ja die Methode, gibt Conten.
Jetzt haben wir da eine Liste hinzugefügt und natürlich könnt ihr
auch hier die Liste wieder nicht. Also müssen wir so
uns importieren. Hierzu kommen wir gleich ein bisschen später,
versuchen wir das hier überhaupt erstmal schöner zu schreiben.
Erst machen wir am besten mit einer For-Each-Schleife erweiterten Vorschleife oder
wie manche Vimis gesagt haben,
schöneren Vorschleife
Hier wird mir alles schon gleich angezeigt für jedes Konto,
Konto aus Content, tue Dinge.
Und wir machen als erstes, dass wir uns ein Saldo
vom jeweiligen Konto geben lassen, gleich Konto.
Nicht Content, sondern Konto. Punkt. Gib Saldo.
Und dann haben wir wieder unsere Methode,
das ist im Outprintline mit der Abkürzung Syso-Steuerung leer.
Und übergeben da
den Saldo
Das, was ihm hier nicht gefällt, ist,
dass wir hier oben schon mal Saldo deklariert haben.
Das ist nicht weiter schlimm,
weil wir ja gerade das deswegen dieser erweiterten Vorschleife gemacht haben,
damit wir diesen Kram hier loswerden können.
Und das machen wir jetzt auch mal.
So, und jetzt kommen wir zu diesem Teil.
Ich schreibe erst mal ein bisschen was und dann erzähle ich,
warum ich das Ganze schreibe.
Wir machen hier als allererstes einen Typtest,
If-Konto.
Instance Off
Girokonto. Dann machen wir was. Und zwar,
wir erzeugen eine lokale Variable. Vom statischen Typ Girokonto
nennen die Girokonto. Und weisen ihr jetzt Konto zu?
Das machen wir, indem wir in diese Runden klammern.
Girokonto schreiben
Das liegt daran, dass ich an einer Variablen nur die Imperationen,
die im statischen Typ drin sind, aufrufen kann.
Wenn ich jetzt aber was haben möchte,
was in der Klasse Girokonto drin ist und nur da,
nämlich ziehe Gebühren ab, dann muss ich vorher einen Typtest machen,
eine Typ Zusicherung. Das heißt, hey,
lieber Compiler, ich habe mich wirklich vergewissert,
das Konto in diesem Fall vom dynamischen Typ Girokonto ist,
weiß, dass eine Variablen vom statischen Typ Girokonto zu und kann jetzt auf Girokonto
Die Methode ziehe Gebühren ab, aufrufen. Das Gleiche muss ich auch noch mal mit Sparbuch machen,
weil auch Sparbuch eine Methode hat,
die in Konto nicht drin ist und auf die ich nicht zugreifen könnte,
wenn ich vorher nicht Typ testen, Typ Zusicherung gemacht habe.
Also Als If. Ihr erinnert euch vielleicht ein bisschen,
dass wir das Ganze schon mal im letzten Semester bei der Equals-Methode überschreiben hatten.
Also wenn Konto Eine gültige Referenz auf ein Objekt der Klasse
Sparbuch hält. Also Quanto, Instance of Sparbuch.
Dann machen wir wieder eine variabel vom statischen Typ Sparbuch,
die wir Sparbuch nennen.
Gleich. Und hier in die Rundenklammern schreiben wir wieder Sparbuch
Ja, also wir vergewissern uns hier, dass das Konto,
was wir gerade am Wickel haben über diese Vorschleife,
ein Exemplar, der klassisch Sparbuch ist.
Also vom dynamischen Typ Sparbuch ist, sagen dann hier,
hey, das ist wirklich vom dynamischen Styp Sparbuch,
deswegen darfst du, ist einer Variablen vom statischen Typ Sparbuch zuweisen.
Und auf der Variablen,
weil sie jetzt vom statischen Typ Sparbuch ist,
können wir
die Methode schreibe Zinsen gut ausrufen
Ja. So, das hier oben brauchen wir nicht mehr.
Und im Prinzip funktioniert das Ganze jetzt bis auf die Tatsache,
dass ich wie immer mindestens einen Semikolon vergessen habe.
Im Prinzip würde das Ganze jetzt schon so funktionieren,
wenn ich jetzt hier Run as Ever Application mache,
dann komme ich hier unten die jeweiligen Entseiden der beiden Konten.
Ich sage gleich, die Zinsberechnung und Gebührenberechnungen sind nicht so,
wie sie in der Praxis sind.
BWLer und Banker mögen mir da verzeihen. Wir haben mit
dieser Vorgehensweise allerdings noch ein Problem. Was ist,
wenn wir jetzt zum Beispiel noch ein Tagesgeldkonto haben?
Oder wir haben irgendwelche anderen festgelegt, Festgeldkonten oder Investmentkonten,
was auch immer
Dann kriegen wir irgendwann hier eine If-Ls-If-Kette mit jeweils Instant-Off-Prüfungen,
die wird sehr lang und wird sehr schwer zu pflegen.
Also wollen wir uns irgendwie was Besseres überlegen,
wie wir das Ganze in den Griff kriegen,
dass wir diese Instance-Off nicht brauchen.
Wenn wir uns jetzt hier Sparbuch angucken,
dann ist ja Zinsen gut schreiben oder bei Girokonto Gebühren abziehen,
schon fast der halbe Weg zu so einer oder einem Jahresabschluss.
Hier mögen wir die Buchhalter verzeihen, weil das ist bestimmt
irgendwie fachlich nicht ist, aber in unserem Fall ist es das.
Das Einzige, was dann noch fehlt, ist,
dass das Ganze auf der Konsole ausgegeben wird.
Also könnten wir ja in der gemeinsamen Oberklasse vom Sparbuch und Girokonto
eine weitere Methode machen, die von beiden geerbt wird.
Public gibt nichts zurück und heißt Mache Jahresabschluss
Nur keine Parameter entgegen und kapselt erstmal den Teil,
der gemeinsam sein wird, wenn wir hier dieses Printline ausgelagert
haben werden, indem wir nämlich hier einfach sagen, Süßo
. Und dann wird einfach der Saldo zurückgegeben. Also der Saldo
auf der Konsole ausgegeben. Diese Methode wird zwar von Sparbuch und Girokonto geerbt,
Sie können damit allerdings noch nicht so wahnsinnig viel anfangen,
weil sie ja immer noch hier ihren Saldo brechen müssen,
in dem entweder Zinsen draufgerechnet werden oder Gebühren abgezogen werden.
Deswegen redefinieren sie die Methode, die sie aus Konto erben.
Ich schreibe ja als allererstes mal at overright.
Und dann Public. White. Mache Jahresabschluss
Und hier rufen sie als allererstes ihre Methode auf, die sie besonders haben.
Also in dem Fall sparberuft, schreibe Zinsen gut auf.
Und die Methode wird ab jetzt nirgendwo anders mehr benutzt.
Deswegen können wir die auch private machen. Und jetzt wollen wir ja noch,
dass das Ganze auch tatsächlich auf der Konsole ausgegeben wird.
Jetzt wäre es blöd, wenn wir das nochmal da reinschreiben.
Deswegen sagen wir super, Punkt,
mache Jahresabschluss
Das heißt also, wir redefinieren die Methode, mache Jahresabschluss,
indem wir uns hier eine eigene Methode, mache Jahresabschluss,
bauen und rufen dann aber nochmal die Methode, mache Jahresabschluss,
die wir hier im Konto schon drin haben und die nichts anderes tut,
als den Saldo auf die Konsole zu schreiben, nochmal auf.
Redefinieren nennt man auch überschreiben und ihr kennt aus dem letzten Semester noch einen anderen Begriff,
mit über, nämlich überladen, überschreiben,
überladen ist was unterschiedliches, überschreiben ist,
wenn ich eine Methode,
die ich geerbt habe,
redefiniere,
so wie wir
das eben gemacht haben
Überladen ist eine, bedeutet das eine Methode,
den gleichen Namen haben darf,
solange sie entweder eine unterschiedliche Anzahl von formalen Parametern entgegennimmt oder
diese formalen Parameter oder wenigstens einer dieser formalen Parameter einen anderen Typ hat.
Nur mal so als kleiner Tipp,
sowas wird ganz gerne in SE1-Klausuren auch gefragt.
Und ich glaube, der ein oder andere ist ja jetzt
daran gehindert worden zum zweiten Termin zu schreiben.
Wie gesagt, nur mal so als Tipp.
Jetzt machen wir den gleichen Spielspaß auch für Girokonto.
Das heißt, wir definieren auch für Girokonto die geerbte Methode,
schreibt wieder zuerst
at override
Und dann Public. Wollt. Mach Jahresabschluss.
Und hier schreiben wir dann rein Zielgebühren ab.
Die Methode können wir auch wieder private machen,
weil wir sie jetzt nirgendwo anders mehr brauchen.
Und jetzt rufen wir wieder aus der Superklasse
Mache Jahresabschluss auf. Und damit das Ganze eben auf der Konsole
ausgegeben wird. Eine kleine Bemerkung noch zu Ad Overright.
Das Ganze überschreiben oder auch redefinieren, funktioniert auch ohne Ad Overright.
Wenn ich das hier also wegnehmen würde,
würde das Ganze genauso ablaufen, als wenn es da stünde.
Was mir halt overright bringt, ist,
wenn ich mich hier jetzt zum Beispiel verschreibe,
ich schreibe,
mache Jahresabschluss ohne
Dann wird mir das hier rot unterkringelt. Das wäre nicht
der Fall, wenn ich at overright auskommentiere.
Das wird mir deswegen rot unterkringelt, weil at overright mir sagt,
hey, du versuchst eine Methode aus der Oberklasse zu überschreiben,
die es da aber gar nicht gibt.
Oder anders ausgedrückt, at overright ist eigentlich eine bessere Rechtschreibprüfung.
Dann mache ich das eher hier wieder rein. So,
und jetzt gucken wir an, was das Ganze für unsere klasse Startup bedeutet.
Wir können uns hier diesen ganzen Klumpatsch,
den wir hier drin gemacht haben,
mit Instance Off und hier den Seido nochmal einzeln ausgeben,
können wir uns komplett sparen
Indem wir hier einfach schreiben, Konto, Punkt, mache Jahresabschluss.
Das heißt, wir haben jetzt sehr viel Code gespart und
sehr viel Flexibilität gewonnen. Jetzt wird auch nicht mehr geschimpft
. Ich lösche mal die Konsole hier und sage hier,
run as Yava Application und schon haben wir unten wieder unsere Werte.
Das ist das System ist dadurch deutlich wartbarer geworden,
weil wir hier und hier den doppelten Code nicht mehr haben
und ausgelagert haben in unsere gemeinsame Oberklasse.
Das System ist flexibler geworden, weil werden wir uns weitere Konten einfallen,
dann können sie wieder von Konto erben und wir können hier als Typ die gemeinsame Oberklasse nehmen.
Vielleicht als kleine Bemerkung, eine Implementationsvererbung ist auch gleichzeitig eine Typvererbung,
das heißt zwei Klassen, die mit Extenz von Konto erben,
haben auch Konto quasi als Typ gewonnen.
Das heißt, ich kann Ihnen eine Liste von Konten
sämtliche Klassen reintun, die von Konto erben.
Und das Ganze ist ein bisschen schlanker und schöner geworden.
Und jetzt soll ich euch noch ein bisschen was
zum Zusammenhang zwischen Vererbung und dem Vertragsmodell erzählen. Angenommen,
wir wollen in der Klasse Sparbuch eine Methode redefinieren, zum Beispiel Hebab.
Oder gehen wir anders vor. Angenommen, wir sagen,
Der Saldo darf nicht negativ werden. Das heißt also,
damit wir hier abheben dürfen, haben wir als Vorbedingung...
Ed... Ed... Ey, ja. Ähm... Betrag
... Kleiner, gleich... gib... Saldo
Ja, wenn der Betrag kleiner ist als der Saldo,
dann kann das Konto nicht negativ, also ins Minus gehen.
Und dann funktioniert das eben. Wenn wir jetzt in der Klasse Sparbuch
aus irgendeinem Grund die Methode hebe ab, auch redefinieren wollten.
Das ergibt jetzt fachlich relativ wenig Sinn, was ich mache,
aber sich gute fachliche Beispiele hierfür auszudenken, wird ein bisschen schwierig.
Deswegen probiere ich es halt irgendwie.
Wir schreiben hier wieder
at overright
Und sagen dann, Public wollt, hebe ab.
Und da überall geben wir ein Int, das ist ein Betrag.
Und wir machen hier irgendeinen Kram, machen wir mal wieder
super.
Hebe ab, Betrag, das ist gut.
Und dann sagen wir, unterstrich Saldo, minus gleich.
Ein Cent. Keine Ahnung. Buchungsgebühr bei Abhebungen, warum
auch immer. Wie gesagt, fachlich ist das jetzt
gerade mal so ein bisschen.
Dann dürften wir hier nicht sowas schreiben wie Ed Require
Betrag strikt kleiner. Und das andere kleiner. Gibt Seilo
. Weil in erbenden Klassen die Vorbedingung der Oberklasse nicht
verschärft werden darf. Ich darf hier also nicht sagen,
in der Oberklasse steht zwar kleiner gleich, ist ausreichend,
dann darf ich hier in der Unterklasse nicht sagen,
ich will aber aus irgendeinem Grund strikt kleiner haben.
Das heißt also, Erbendeklassen dürfen Vorbedingungen nicht verschärfen.
Und außerdem dürfen Erbendeklassen nach Bedingungen nicht aufweichen. Das heißt,
wäre mir hier eine einigermaßen vernünftige Nachbedingung eingefallen,
dann dürfte ich hier zwar eine striktere Nachbedingung einhalten.
Das heißt, ich liefere mehr als eigentlich gefordert wurde.
Ich dürfte sie aber nicht aufweichen. Ja,
soviel dann von mir für diese Woche zur Vererbung
und wir sehen uns dann nächste Woche