Herzlich willkommen zur Vorlesung 4. Dabei geht es um Implementationsvererbung und
wir setzen fort, was wir in Vorlesung 3 besprochen haben.
Wir haben heute ein ziemlich komplett ziemlich volles Programm.
Wir starten mit einer kurzen Wiederholung und Wiedereinführung,
haben dann ein paar Begriffe, sprechen über den Reihenfolge von Methodenaufrufen,
über den Begriff abstrakte Klassen, führen ein Entwurfsmuster ein und sprechen darüber,
wie es sich mit den Konstruktoren verhält und den Schnittstellen.
Lassen Sie uns starten mit einem Einstieg zunächst erst mal,
warum noch mal das Ganze, was wollen wir damit erreichen?
Da ist zunächst erst mal, wir wollen damit strukturieren und vereinfachen.
Wenn wir sehr viele Elemente haben, ist es gut,
die gemeinsamen Eigenschaften zusammenzufassen. Ja,
und damit gelingt es uns, Redundanz zu vermeiden,
uns zu konzentrieren auf das Wesentliche und nicht so viel zu verstreuen,
Informationen zu verstreuen.
Jede Änderung muss dann hoffentlich nur an wenigen Stellen gemacht werden.
Damit gelingt es uns in komplexen Systemen,
das Ganze leichter einfacher zu strukturieren,
also nicht so viel Änderungen zu machen
Ich betone das deswegen immer wieder, weil viele,
gerade die Leute, die vor allen Dingen die Programmiersprache gelernt haben,
immer auf Vererbung abfahren.
Wir haben beim letzten Mal ja auch darüber gesprochen, dass Implementationsvererbung auch Nachteile hat.
Die Vererbung ist das Mittel der General, ist das Mittel,
was die Generalisierung dann umsetzt in unserer Programmiersprache.
Und wir sprechen insbesondere, die führt mit über die Implementationsvererbung.
Dabei wollen wir zum einen Dinge anpassen, indem wir
speziellere Eigenschaften einführen. Zum anderen natürlich das, was wir
eben schon gesagt haben,
Redundanz vermeiden
Wir können es auch noch vervollständigen,
dass wir mehr Eigenschaften haben, wenn wir es wiederverwenden wollen.
Nur nochmal zur Gegenüberstellung in Vorlesung 3 letzte Woche hatten wir,
dass die Typvererbung auch nochmal erwähnt, das war das,
was Sie schon kannten.
Wir sitzen zusätzlich die Implementationsvererbung dazu ein, dass wir Hierarchien bilden,
indem wir ausführbare Elemente verwalten können, ordnen können, strukturieren können.
Eine Hierarchie ist ja immer so eine Baumstruktur,
wo wir oben die gemeinsamen Dinge zusammenfassen
Ja, und dieses Generalisieren hat letztlich auch den Gegenpol die Spezialisierung.
Also beide Seiten zu sehen. Zum einen, wir fassen Sachen zusammen.
Also wir haben zwei Klassen, die irgendwas gemeinsam haben.
Wir fassen die zusammen durch Generalisierung. Und dann gelingt es uns
die gemeinsamen Sachen in die Oberklasse auszulagern und dabei nur einmal zu haben.
Das ist, was ich mit Vermeidung von Redundanz meine,
nehmen wir uns mal an, irgendwie, es gibt Performance-Probleme,
dann brauchen wir es nur einmal zu beheben.
Es gibt ein Sicherheitsloch, wir brauchen uns nur einmal
zu beheben, weil alles sehr drin ist.
Gleichzeitig gibt es auch das Umgekehrte,
die Spezialisierung
Down-Richtung. Also wir haben etwas in der Oberklasse
und wollen aber diese Eigenschaften nochmal ein bisschen spezieller haben,
dann können wir eins oder zwei oder noch viel mehr Unterklassen bilden,
die jeweils die speziellen Eigenschaften nur hinzufügen.
Also hier stände nur ein bisschen was drin,
dann die Hauptsache von oben genommen werden kann.
Also in der gemeinsamen, in der Oberklasse, in der Superklasse.
Ja, auch damit erreichen wir das Ziel, geringere Redundanz zu haben. Das sind,
das sind die Ziele, die wir haben damit und dabei Können wir sagen,
dass wir dem neuen Kontext, die eine bestehende Klasse einpassen können, indem wir kleine Motivfikationen vornehmen?
Also wir haben zum Beispiel eine alte Klasse,
wir nehmen noch mal so ein Beispiel fürs Auto, ja,
da haben wir also ein Auto, hat irgendwie einen Blinker,
der Blinker wird durch Software gesteuert und da haben wir die Blinker-Steuerung,
aber wir wollen jetzt was hinzufügen,
wir brauchen einen Anhänger und der Anhänger,
der braucht noch eine separate Kontrolle,
dass die Anhängerlampen auch noch allegant sind,
dass da Kontakt ist,
dass der Stecker richtig dran ist,
irgend sowas.
Und da brauchen wir
zusätzliche Eigenschaften
Und das können wir durch Ableitung, durch Vererbung hier hinzufügen.
Das heißt, hier unten dieses C-Strich,
diese abgeleitete Klasse, hat nur die Eigenschaften,
die die Obere nicht hat, nur die hinzugefügte.
Und damit haben wir Redundanz, vermeidet. Ja,
so, und das können wir immer dann auch umgekehrt machen.
Also wir fassen die oberen Sachen zusammen. Die beiden Listen
hatten wir letzte Woche schon, fassen wir zusammen zur abstrakten Liste.
Student und Dozent in unserem System Stine sind beides Personen,
die gemeinsame Eigenschaften haben. Zum Beispiel,
sie gehören zu eurer Fabrität oder sie haben ein Passwort oder
irgend sowas
Ja, also das sind auch die Punkte,
die wir in der, auf unseren Wiederholungsfragen haben,
hier die Ziele von Implementationswerbung, hier wird nach zwei Zielen gefragt,
man hätte auch nach drei Zielen fragen können, ja,
also zum einen wollen wir Gemeinsamkeiten zusammenfassen,
eine Folie vorher war noch, wir wollen spezialisieren,
ja, und noch eine Folie vorher war dieses Redundanz vermeiden,
das wären das Oberziel,
was wir damit erreichen wollen
So, wir machen weiter mit der Nummer 8. Ja,
nein, die gibt es nicht bei uns, die,
wir wollen nochmal die Übersicht haben, die Superklasse oder Subklasse,
Ober- oder Unterklasse, die sind standardmäßig auch weitergegeben.
Ja, und damit haben wir die Möglichkeit,
eben diese Redundanz zu meiden, weil das nur einmal in der Oberklasse haben.
Dabei trifft er Felder bzw. Attribute zu, dass die üblicherweise unverändert übernommen werden. Ja,
man kann natürlich welche hinzufügen,
wenn man noch in den Unterklassen weitere Sachen braucht,
also zum Beispiel uns auch Beispiele, also vorgehende Folie,
nein, hier war es mit Student und Dozent,
ja, die haben vielleicht separate Attribute, also der Student,
der hat einen angestrebten Studienabschluss und Noten,
während der Dozent dann eher noch ein Verzeichnis hat,
der Kurse, die ergibt.
So, für Methoden bzw. Operationen ist das noch vielgestaltet,
wir haben noch mehr Möglichkeiten,
zum einen können wir in der Unterklasse etwas Neues hinzufügen,
also Dozent oder der Student kann etwas,
was Person gar nicht kann
Manchmal ersetzen wir etwas. Ja, also der Student hat auch etwas,
wo er vielleicht eine Bezahlung kriegt für,
aber die Bezahlung ist bei der Person irgendwie verallgemeinert und beim
Studenten und beim Dozenten ist die anders.
Da können wir sie entweder komplett ersetzen oder erweitern.
Beides, alles das werden wir jetzt gleich nochmal besprechen.
Und dann können wir auch noch was Neues machen,
für die es vorher nur eine leere Methode gab, also nur eine abstrakte Methode.
Er kommt zu diesem Begriff abstrakte Methoden. Jetzt auch noch. Ja,
und weil wir hier die beiden Begriffe so nebeneinander haben,
Methode, Operationen, möchte ich das noch mal klarstellen,
die Begrifflichkeiten, dass wir die voneinander trennen.
Manchmal ist das notwendig, manchmal darf man einfach so ein bisschen locker drüber hinweggehen.
Also wenn wir gezielt nur die Schnittstelle Man meinen,
dann sollten wir den Begriff Operation nehmen,
wenn wir die Schnittstelle und ganz gezielt die Implementierung meinen,
sollten wir die Methode verwenden.
Ja, also wenn wir hier beim Definieren geht es um
die Methode, weil wir haben die Implementierung hinzugefügt.
Ja, bei dem Redefinieren geht es um beides Schnittstelle und
Methode.
Das noch mal im Beispiel mit Konto und Sparbuch.
Konto ist das Allgemeinere. Und da kann man,
muss man sich natürlich den Saldo anzeigen lassen.
Da gibt es Schnittstelle und Implementation. Ich habe das hier mal so gezeichnet,
was ist innen, was ist nach außen sichtbar.
Und für das Sparbuch, ja, da gibt es diesen Saldo auch,
wie hier oben, wir können den übernehmen.
Dieser Pfeil steht ja für die Vererbungsbeziehung.
Und wir können noch etwas hinzufügen und das wäre jetzt Spezialisierung.
Ja, wir fügen etwas hinzu, in dem Fall hier
eine Methode,
nämlich Schnittstelle und Implementierung
Ja, das kennen wir schon vom letzten Mal, das Schlüsselwort dafür Extenz. Ja,
und das Extenz führt dazu, dass das Sparbuch erstmal alles erbt,
was hier oben bei Konto ist,
indem wir klares Sparbuch-Extenz-Konto schreiben, dann steht automatisch,
dass wir das Einzahlen auszahlen, gibt Saldo hier auch haben,
obwohl es hier unten nicht dasteht.
Also das Extenz muss jeden beim Lesen des Kurz sagen,
okay, wenn ich wissen will,
was es hier gibt,
muss ich auch die Oberklasse-Konto,
das Superklasse-Konto anschauen
Soweit. Dazu und wird ein Exemplar davon erzeugt.
Ja, also instanzieren wir etwas. Dann ist,
da sind da alle Felder mit drin und alle Operationen verfügbar.
Ja, so und also die von oben,
die ins Sparbuch selber definierten Operationen und die in Konto und gegebenenfalls im weiteren Oberklassen definierten Operationen.
Ja, also wenn das im Klassendiagramm das,
was wir für da vorgehen, Folie haben,
ich gehe nochmal zurück, gleich sieht im Klassendiagramm mehr so aus,
Konto hat diese drei Operationen hier,
es steht jetzt nicht Klammer auf, Klammer zu,
das ist durchaus, man kann das auch weglassen im Klassendiagramm.
Was jetzt hier vielleicht noch fehlt, ist der Strich,
wir müssen uns hier noch eine weitere Linie,
müssen wir eigentlich hier haben, fällt mir gerade auf.
Also bitte malen Sie sich noch mal eine Linie dran,
wenn Sie es ausgedruckt vor sich haben,
weil wir haben im zweiten Feld die Attribute und Felder und
die Operationen bzw. Methoden erst im dritten Feld von dem Klassensymbol.
Ja, also jetzt hier im Sparbuch selber gibt es nur
diese zwei Operationen und wenn wir dann eine Instanz erzeugen,
ein Exemplar erzeugen, dann haben wir tatsächlich die von hier oben verfügbar,
die Geerbten und die eigenen.
Hier sehen wir es nochmal im Quelltext, ja,
in Klaas gab es diese beiden Public Method,
die drei Public Methoden und hier gab es neben dem Konstruktor nur die zwei.
Noch zusätzlich, ich gehe da zurück zu der anderen Folie,
hier sieht das im Klassendiagramm so aus.
Soweit dazu, das waren die Public Methoden,
Public Operationen, die ich dann nach außen auch sehe
Aber wie sieht es aus, wenn ich was nicht nach außen zeigen kann?
Das kann ich steuern durch diese Modifikatoren und private Eigenschaften kann ich dann in der Unterklasse nicht benutzen. Ja,
also wir haben hier die Möglichkeit, durch Protected oder Private das zu machen,
ja, protected, die sind nur für Abendeklassen zugreifbar,
nicht für Klienten aufrufbar, das machen wir ganz am Ende,
sprechen wir das nochmal an heute, wie das mit den Schnittstellen aussieht,
also diesen Unterscheidungen, ja, Erbendeklassen sind welche,
die darauf bezogen Zug nehmen über Extent,
aber man kann es nicht aufrufen.
Protected haben wir hier auch noch mal. Private bedeutet,
ich kann sie gar nicht zugreifen, außerhalb der Klasse. So,
soweit, ja genau, hier haben wir das Protected für ein,
für das Feld, Float, Saldo und Float, Zinssatz,
ja, Float Zinssatz ist dann nur in der Klasse.
Sparbuch selber, woanders nicht sichtbar
Ja, wir sollten, hier ist noch so ein bisschen
der Grundsatz, so ähnlich wie Datensparsamkeit.
Wir sollten versuchen, wirklich nur den öffentlich auch sinnvoll nutzbaren Kern freizugeben.
Nicht nur die Sachen, wo wir keine Probleme erwarten,
sondern wir sollten das gezielt steuern, dass die Schnittstelle relativ schmal bleibt.
So, ein Punkt, Zusammending sollte ich bei der Gelegenheit gleich noch mit einführen,
wenn wir mal bei einer Klasse kein Extens angegeben haben.
Ja, dann gibt es immer noch die Klasse Object.
Das ist speziell für Java, in Java haben die Erfinder
von Java definiert
Jedes Objekt, was in Java ist,
hat mindestens die Klasse Objekt als Oberklasse, jede Klasse.
Also Object, auch wenn nichts dran steht mit Extense,
wir gehen wieder eine Fulle einmal zurück, ja,
hier steht Sparbuch, Extense, Kondo, okay,
er lampt, erbt von Kondo, aber bei Konto steht nichts.
Hier steht es trotzdem, also sie können sich dann immer
daran denken, Extense, Object.
Das würde, als würde das dranstehen. Mensch,
schreibt es nicht dran, ja, aber es wird immer,
und deswegen sagen wir, implizit,
ohne dass es angegeben werden muss,
erben wir immer von Object
Object ist die allgemeine Oberklasse von allem. Und diese allgemeine Oberklasse muss deswegen
nur Eigenschaften enthalten und darf nur welche enthalten, die alle brauchen.
Und da gibt es relativ wenig. Wir sprechen hier über drei Operationen,
die am Ende jeder von Düsseldorf Object eingeführt,
jede Klasse in Java für seine Exemplare hat.
Und zwar sind das zunächst erstmal dieses Two Stream.
Diese Darstellung als Stream, die braucht man zum Beispiel,
wenn man eben die Bagger was darstellt,
also zum Beispiel die Klasse Buch,
da steht dann irgendwie
ein Buch oder sowas
Kann ihm angeben, dass ich bei diesem,
nicht ein Buch stehen habe,
sondern vielleicht den Titel und den Autor und das Jahr.
Das kann ich selbst definieren, indem ich die von Object
geerbten Klassen verändern möchte. Ja, also indem ich darstelle,
was da dargestellt wird, wie das im Debaker oder sowas erscheint.
In der Gui kann ich sowieso darstellen, was ich will.
Aber in der Konsole oder in Debaker, das steuere ich mit Dustringen.
Das nächste, was wir alle, was wichtig ist zu erwähnen,
es gibt noch mehr und nebenbei merkt außer den dreien,
aber diese drei sind uns wichtig.
Wenn ich Objekte vergleiche, vergleiche ich die Identität von Objekten.
Da gehen wir noch mal separat drauf ein. Aber wenn ich die Inhalte vergleiche oder davon abhängige,
also zum Beispiel referenzierte Objekte,
dann muss ich das über Equals definieren, dass ich sage,
okay, wenn du mich vergleichst, dann musst du auch gucken,
ob ich von meinen über Assoziationen angebundenen Objekten auch gleich bin.
So, das sind Beispiele, Hashcode berechnet einen Code,
den ich verwenden kann, in Baumstrukturen, im Suppensuchen,
der hat das Objekt repräsentiert und auf die Weise als Identifikator,
damit ich nicht das ganze Objekten nehmen kann, sondern einfach sagen,
ja, das ist das Objekt und das ist das Objekt.
Dazu berechne ich den Hash Code. Soweit zu der Besonderheiten
der Implementation, des Vererbungen in Java. Wir machen gleich weiter,
das andere hängt eigentlich auch damit zusammen,
mit den Begriffen redefinieren, redeeklarieren,
aber das ist erstmal
die nächste Einheit