Ich glaube jetzt. Ja, herzlich willkommen. Ich wünsche
Ihnen allen ein glückliches, neues Jahr und freue mich,
dass Sie alle wieder da sind und auch nicht auf dem Eis ausgerutscht sind oder so.
Wir hatten hier in der letzten Vorlesungswoche vor Weihnachten damit begonnen,
über das kommendes Object-System zu reden.
Also die eine Möglichkeit, um objektorientierte Programmierung im Racket einzubringen.
Und ich möchte an der Stelle weitermachen. Also ich hoffe,
dass diejenigen, die vor Weihnachten nicht hier waren,
immerhin die Weihnachtsferien genutzt haben und mal ein bisschen reingeguckt haben,
wie das so geht.
Teil können wir auch noch mal ein bisschen wiederholen.
Ich versuche mal an die
Erste Stelle zu kommen, wo wir überhaupt eingeführt haben,
was man in Reckett so tut. Also der Hauptpunkt,
wenn es objektorientiert hat, in funktionalen Sprachen geht,
ist die Frage, was passt davon eigentlich in die funktionale Welt?
Zum einen kennen Sie das ja aus Ihren Java-Erfahrungen,
Objektorientiertheit ist in Herrent mit dem Imperativen Programmierspiel verknüpft.
Zumindest und so, wie man es den Imperativen Programmiersprachen noch lernt. Das Wichtige an Objekten ist,
dass Sie eine Einheit sind, dass Sie Zustände haben,
dass Sie Zustände sich ändern können und damit Wird man ganz natürlich anfangen,
imperativ zu programmieren, wenn man versucht, Objekte zu modellieren,
die Welt zu modellieren und Übergänge zwischen den Zuständen der Welt zu modellieren.
Objektorientiertheit kommt ja ursprünglich auch vor allem aus
den Anwendungen zur Simulation und da passiert das wunderbar rein.
Aber abgesehen von der treffenden Modellierung der Zustände von Objekten in
der Welt und von gut lesbaren Beschreibungen der Objekte ihrer Eigenschaften und dem,
was sie können, hat sich objektorientiertheit in zwei ganz,
ganz wichtigen Punkten herauskristallisiert als ein wichtiges Mittel beim Software-Engineering,
um wartbare, wiederverwendbare Software zu bekommen.
Und das eine ist zum einen natürlich,
dass man rigoros bei der Definition von Klassen,
sie vernünftig so schreibt, dass es lesbarer Code ist,
dass man selbst dokumentierenden Code hat,
dass wir Schnittstellen sauber modellieren.
All das steht absolut nicht im Widerspruch zum funktionalen Programmierstil.
Diesen Teil können wir ganz natürlich auch verwenden und buttlesbaren
Code schreiben,
strukturiert und so weiter
Da ist nichts vom Imperativen drin zu sehen. Der zweite Teil,
wo auch das Imperative überhaupt nicht trägt und was genauso wichtig ist,
ist, dass systematische Erweiterung von Software durch Vererbung.
Wir haben Klassen, schreiben ein Programm für einen Zweck und
wir möchten wiederverwendbaren Kot haben. Also nicht jedes Mal von
neuem Anfang, wenn die Aufgabe sich leicht ändert,
sondern wir nur ein bisschen ändern müssen.
Und der Teil Ist auch völlig unabhängig davon,
ob es um Zustandsorientierte Programmierung geht oder nicht.
Das ist ein Entwurfswerkzeug, das sehr gut in die Welt
des Funktionalen Programmierens passt. Und das ist,
was in Zählers für mein Gefühl unglaublich gut gelöst ist.
Wir haben für diesen Teil, wie schreibe ich wiederverwendbaren Code
und verändere den bestehenden Code für neue Spezialisierung in einer portierbaren Weise.
Das haben wir vor Weihnachten schon angesprochen. Beim Beispiel der Methodenkombination,
den Teil möchte ich ganz kurz nochmal wiederholen und dann zu
einem anderen Teil kommen
Wo es darum geht, wir verändern wir ererbte Methoden.
Wir haben vor Weihnachten vor allem drüber gesprochen,
wie machen wir die Mehrfachvererbung sauber. Und das schauen wir
uns nochmal ganz kurz an, wo die Akzente waren.
Sie haben das jetzt auf diesem Aufgabenblatt ja auch.
Und ich hoffe, Sie haben es auch in den Übungen besprochen.
Weil nur damit wir alle im selben Film sind und Zillos
Code auch lesen können, nochmal die wichtigsten sind taktischen Dinge.
Also wenn wir eine Klasse schreiben, verwenden wir diese intaktische Form Dev Class.
Wir haben mit Dev Class beschreiben wir erstens,
wie die Klasse heißen soll,
von welchen Klassen
sie abt
Welche Attribute die Objekte der Klasse haben? Für konkrete Klassen
und Objekte heißen die Attribute in Zählers, Communous Object System.
Da heißen sie eben Slots. Also ich werde in Zukunft
immer Slots sagen. Wenn ich für eine konkrete Klasse die Attribute meine.
Das, was an Operationen ausgeführt werden kann auf Objekten.
Das ist in der funktionalen Welt so gelöst,
dass man es mithilfe von generischen Funktionen macht.
Also alles, was wir machen, schreiben, ist eine Funktion.
Spezielle Sortefunktionen sind generische Funktionen. Die haben klassenspezifisch viele mögliche Implementationen und wir können jederzeit,
egal wo wir gerade am Schreiben sind,
nur nicht gerade in einem Dev Class oder so,
aber wenn wir so zwischen Funktionen in irgendeinem Modul,
in einem Paket sind, können wir Dev Generic schreiben und sagen,
wir führen jetzt eine Operation ein.
Als generische Funktion. Und dann können wir an der Stelle auch anfangen,
dass für all die Klassen, für die es uns interessiert, zu implementieren.
Generische Funktionen sind wie jede andere Funktion. Auch sie können
ein bisschen mehr, weil wir können sie so verwenden,
wie wir es bisher gelernt haben. Das heißt,
ein Lab, ein Filter, den ganzen Apparatus der Funktionen,
höherer Ordnung darauf anwenden, wenn es um Operationen auf Objekten geht.
Und das ist wirklich bestechend, dass wir auch durch die Syntax klar machen.
Es sind Funktionen, diese Operationen auf den Objekten.
Nicht in Java schreiben sie, dass sie einem Objekt eine Nachricht schicken.
Und das lässt sich dann weniger gut in einen Kontrollrahmen,
Funktionen höherer Ordnung reinbringen, weil sie nicht nur die Nachricht als selbst weitergeben können,
sondern sie müssten immer ein Objekt mitgeben, einen Händler,
der versteht, was diese Nachricht ist.
Wenn wir eine bestimmte Operation ausgeführt haben wollen,
können wir in der funktionalen Welt schlichtweg Map neben Filter und
diese generische Funktion übergeben und dann geht es auch. Gut,
wir definieren die generischen Funktionen als Signatur für die Operationen,
sowas wie Show oder Plot und das sind für viele Objekte
vieler Klassen klappen soll und dann implementieren wir es,
da wo es gebraucht wird mit Dev Message und wir können
viele Implementationen vorsehen.
Ein Beispiel für einen Dev Class,
wir hatten das letzte Mal eingeführt, eine klassische Cues oder Schlangen,
so syntax nur um deparat zu haben,
wir schreiben Dev Class, der Stern hier ist ein Autoprovide,
also wenn wir das in einem Modul machen,
dann werden die hier definierten Methoden und Accessor-Funktionen automatisch in ein Provide-Statement eingebaut.
Wir müssen die explizit schreiben, was nach außen sichtbar sein soll.
Also der Stern hier ist für Faule,
die wirklich nichts geheim halten wollen, sondern halt sagen,
alles, was ich hier definiere,
darf außerhalb verwendet werden
Ja, das eine Attribut, was diese Klasse hat,
hier implementiert als ein Slot, soll Items heißen.
Ja, wir haben eine Schlange und die Schlange enthält Elemente.
So. Und wenn wir darauf zugreifen wollen,
dann müssen wir in der Klassendefinition sagen,
das ist eine Akzessorfunktion geben sollen, mit der man zugreifen kann.
Und deshalb schreiben wir hier Doppelpunktreder und Q-Items.
Wenn wir die Items ändern können wollen,
also in der Schlange soll sich noch jemand anstellen können oder so,
dann brauchen wir auch einen Reiter.
Deshalb verbinden wir hier das syntaktische Schlüsselwort Writer und geben dem
Kind einen Namen und damit wird diese Schreibezugriffsfunktionen erzeugt und die
heißt ZQI Items und wir haben hier noch das Benderhemd,
um zu sagen, das modifiziert das Objekt.
Für die Initialisierung haben wir gesehen, Inite Value. Wenn wir den Typ festlegen wollen,
bei der Klasse, weil es uns wichtig ist,
dass gleich in dem Moment, wo man was reinschreibt,
geprüft wird, ob der Typ stimmt, können wir hier sagen,
Typelist und dann ist festgelegt die Elemente dieser Schlange sind alle als Liste abgelegt.
Haben wir es noch dokumentiert und die Sachen da unten,
wiederholen wir das nächste Mal. Wenn wir eine Klasse haben und wollen,
und die hat jetzt verschiedene Slots, Können wir uns für die Slots überlegen?
Sollen die für alle Objekte verschieden sein? Jedes Objekt hat ja
eine private Instanz. Dann würden wir sagen, Elocation Instance,
dann hat jedes Objekt einen eigenen Slot und die Werte können sich unterscheiden.
Oder wenn es nur einmal in der Klasse für alle abgelegt werden soll,
Elocation Class. Das hier ist die Voreinstellung, also wenn
mir nichts anderes verlangen hat, jedes Objekt, die Attribute.
Okay. Wenn wir eine generische Funktion schreiben wollen,
um jetzt Operationen auf den Klassen zu sagen, auch nochmal zur Erinnerung,
Schreiben wir Death Generic und das Implementieren geht mit Death Message.
Wenn wir die Schnittstelle abstrakt lassen wollen, implementieren wir eben nichts,
sondern geben nur die Signatur mit Death Generic vor.
Und auch da hätten wir ein Beispiel uns angeschaut.
Wenn wir jetzt ein NQ für unsere Klasse machen wollen,
ja, das schreiben wir Death Generic Stern,
um auch zur Verfügung zu stellen.
Und die Sonntagswahl hier noch bemerkenswert. Sie sehen schon die
Zahl der Klammer nimmt ein bisschen zu. Wir haben jetzt
gleich zwei öffnende. Die Argumentliste für diese generische Funktion,
die klammert alle Objekte, für die wir Den Parameter von der Klasse abhängig machen wollen.
Also hier sagen wir, wenn jemand einen Q übergibt,
dann muss es von der Klasse Q sein.
Und das wird ja einfach so geklammert. Wir könnten hier jetzt,
also viele Parameter angeben und die immer klammern, mit einem Klassennamen dahinter.
Und dann wird in der Signatur festgelegt, dass die Parameter
diese Klasse haben müssen. Wir können es auch festlegen für Argumente,
die keine Objekte einer Klasse sind, sondern schlichtweg Standardferte,
sowas wie List oder so, geht auch.
Und die Methode, die Methoden werden dann bei ihrer Aktivierung
davon abhängen, ob sie alle typgerechte Argumente haben.
Also jetzt für unsere Warteschlangen hatten wir es so implementiert,
also erstmal spezifiziert, wir brauchen ein Deckue,
um was wieder aus den Schlangen rauszuholen, ein NQItems,
um da viele Items reinzuhängen.
Und sie sehen schon hier, habe ich gesagt,
die Items müssen als Liste übergeben werden.
Ja, List ist keine Klasse, sondern normaler Typ.
Aber ich kann sicherstellen, dass dieses NQ nur verwenden in QItems
nur verwendet wird, wenn man auch wirklich eine Liste übergibt.
Und das erste Element der Klasse, der Schlangeabfragen,
feststellen ist sie leer und so weiter.
Ja, also hier haben wir schön
Signatur erstmal abstrakt, wie diese Klassen funktionieren.
Okay. Denn mit Death Message implementieren wir es,
ja, wenn wir Death Message schreiben, Deck You,
dann sagen wir hier, okay, Typ,
Klasse und schreiben, wie es gemacht werden soll.
Das ist eine Liste, also nehmen wir einfach
die Funktion in Pop und holen das Element raus,
dann kriegen wir das Element zurück und die Schlange ist modifiziert worden.
Ja? Oder, okay. Wir werden in dem Beispiel,
was ich bespreche, gleich noch die Menge aller Schlangen brauchen.
Schlangenklassen, die wir eingeführt haben,
deshalb wiederhole ich sie an dieser Stelle
auch nochmal ganz kurz
Wir hatten das letzte Mal folgende Unterklassen eingeführt. Last in
, first outcute, das ist mir also ein Keller.
Immer wird zuerst gekommen, es kommt als Erster wieder dran.
First in, first out, das ist die typische Wörter,
warteschlange, da hatten wir noch geordnete Schlangen,
wo man entsprechend seiner Schulterstreifen eingereiht wurde oder was immer der Rang ist.
Und da hatten wir noch eine Random Cue, wo einfach gewürfelt wird.
Na, wo stellen wir die Person, die jetzt kommt, gerade hin?
Und das Erben dieser Klassen würden wir Jetzt so schreiben,
indem wir sagen, Dev Class, nahme der neuen Klasse,
ja, und von welcher Klasse sie erben soll.
Hier ist es die FIFA-Cue, first and first out.
Und wenn wir uns das effizient machen wollen,
dass man sich hinten anstellen kann, wie in einer ordentlichen Warteschlange,
dann müssen wir wissen, wo das Ende der Schlange ist.
Sie erinnern sich ja, bei Listen ist es
ein bisschen mühsam, sich bis zum Ende durchzuhangeln.
Das ist proportional zur Länge der Schlange. Also merkt man
sich lieber Anzeige aufs Letzte Element. Und dafür haben wir hier
eben bei dieser speziellen Klasse ein zusätzliches Attributeal, ja,
als ein Slub-Till mit einem Rieder und einem Reiter.
Und damit können wir, wenn wir hinten was reinhängen wollen,
am Ende der Schlange
was bewirken
Gut. Das MQ wird dann dieses ausnutzen, ja.
Dann hatten wir noch kurz angesprochen, die Meta-Methoden,
die brauchen sie für die Übungsaufgabe, aber brauchen wir heute in der Vorlesung.
Nicht so viel nur zur Erinnerung, wir können jedes Objekt fragen,
was seine Klasse ist mit Classoff. Wir können zwei Klassen vergleichen mit Zapp-Class,
ja, wir können fragen, ist dieses, diese Klasse,
eine Unterklasse von der und dann erfahren wir alle Oberklassen ab der Gefragten und der Klasse,
ja, wir können zwei Klassen Namen darauf vergleichen,
welches die spezifischere ist, also welche der anderen untergeordnet ist.
Und wir können,
wenn wir beim Programmieren sind und vergessen haben, ach Mensch,
welche Slots hatten wir eigentlich alle in dieser Klasse definiert,
dann können wir die Glas-Slots abfragen und kriegen hier die Liste mit allen Accessor,
Rieder, Reiterfunktionen und auch noch die Dokumentation, ganz praktisch.
Was Sie hier dran jetzt gesehen haben sollten,
zum einen ist, dass wir,
wenn wir eine Klasse definieren, wirklich nichts weiter definieren,
als,
wie heißt die Klasse,
was sind die Slots
Wie greife ich auf die Elemente zu?
Und was sind die Oberklassen, von denen wir haben?
Zur Klassendefinition gehört nicht die generischen Funktionen und die Implementationen dieser.
Also wir sind, wir brauchen sie natürlich generische Funktionen,
wenn wir sie verwenden wollen und irgendwo müssen sie mal schreiben.
Aber sie sind außerhalb der Klassendefinition.
Sie stehen nicht drin. Das Ende Death Class endet,
nachdem alle Slots da sind. Wir können jederzeit,
wenn es uns gefällt und nötig ist,
können wir
weitere Zugriffsfunktionen zufügen
Wir können fragen, eine Klasse, was implementiert ist mit Generic Message.
Denn also wir haben ein Lenky und wollen jetzt wissen,
ist es überhaupt schon implementiert und wenn ja, welche habe ich?
Und dann erfahren wir, für welche unter Oberklassen das alles implementiert ist.
Und die Stelligkeit können wir auch noch abfragen. Okay.
Zum Erzeugen der Objekte hatten wir das letzte Mal auch gesehen,
wenn wir eine, jetzt so eine Warteschlange erzeugen wollen,
sagen wir Mac und geben den Namen der Klasse
an und wir haben ein Objekt dieser Klasse
Beispiel Eisbecher, Dev Glas Eisbecher mit zwei Kugeln
in zwei verschiedenen Sorten. Wenn wir Mike Eisbecher sagen,
kriegen wir zurück eine Beschreibung, was die einzelnen Felder sind.
Und wenn wir jetzt von der Initialisierung abweichen wollen,
also sie sehen an diesem Beispiel auch nochmal,
wir können gleich bei der Definition der Slots sagen,
wie sie denn initialisiert werden, sollen wir nicht anders bestellt.
In it value. Und da haben wir Erdbeer vorgegeben.
Also wenn die an das bestellt wird, das erste Feld
immer Erdbeereis sein. Wenn wir was anderes haben wollen,
dann können wir im Make hier sagen, Schlüsselwort SO2,
das hätten wir hier als Kennung fürs Inet-Arc bei der Sorte 2 vorgesehen,
dass wir dann lieber Zitrone kriegen oder so.
Das heißt, wir brauchen nicht für jede mögliche Belegung des Konstruktors Kombination,
einen neuen Konstruktor vorsehen,
sondern wir schreiben einen hin und mit den Schlüsselargumenten können wir einfach gezielt für die Parameter,
wo wir was anderes haben wollen, was anderes angeben.
Das heißt, wir haben im Wesentlichen einen Konstruktor Make
und Abweichung von der Default-Initialisierung machen wir,
indem wir diese Schlüsselwörter hier verwenden
Wir können auch initialisieren durch Aufruf in einer Funktion.
Wir haben hier definiert, eine Funktion Random-Kugel,
die würfelt einfach und nimmt aus der Liste von Elementen eins.
Das kriegen wir hin, indem wir sagen, Initializer,
dann wird diese Initialisierungsfunktion aufgerufen an der Stelle. Gut,
gut, wir hatten das Beispiel,
was ich jetzt nochmal ganz kurz wiederholen möchte, sagt uns,
was wir bei der Mehrfachbeerbung für Erbung tun können,
wenn wir in dieser Situation sind,
wir haben zwei Klassen und oder drei oder vier oder viele und wollen eine neue Klasse haben,
die die Eigenschaften aller dieser Klassen in sich vereinigt.
Dann werden wir natürlich erstmal viele Slots üben,
die teilweise doppelt sind und wir werden auch für die generischen
Funktionen eventuell mehrere implementierte Methoden erben.
Der eine Weg ist schlichtweg, man verbietet die Mehrfachvererbung,
dann kommt es nicht vor, dann muss sich keiner drum kümmern,
ist aber unpraktisch.
Oder dann muss man eben mit Interfaces anfangen,
die weiteren Klassen zu berücksichtigen und die zu implementieren.
Es ist sehr viel einfacher, man erlaubt es den Programmierern
und unterstützt sie dabei, das ordentlich zu machen.
Ja, die Konflikte gut aufzulösen. Das ist der Weg der Enzillos
gewählt wurde, eben über all die Meta-Funktionen, die wir haben.
Können wir das einfacher machen? Also hier erben wir sowohl von
der Klasse Jackett als auch Hose und haben dann einen Anzug.
Ja, und die Frage ist, wie geht man damit
jetzt dumm? Also zum einen, um dieses hinzukriegen,
ich habe hier die Klasse Jackett und Hose definiert,
beides mit Dev Class,
der Anzug abt jetzt Jackett und Hose
und hat damit dieses Feld Größe zweimal geerbt.
Ja,
mit unterschiedlichen Initialisierungswerten
Solange ich nichts weiter sage und bestelle,
wir haben gesehen hier, das erste Feld ist Jackett,
wenn ich jetzt bei der Größe zwei verschiedene Werte habe,
dann wird einfach in dieser Liste von links nach rechts das erste genommen.
Ich kann es aber anders haben. Und wenn ich mir die Glaslots von Anzug anschaue,
dann sehe ich, dass beide da sind, mit unterschiedlichen Initialisierungswerten.
Also im Ernstfall kann ich sie beide bekommen. Ich kann mir
auch die und Oberklassen hier anschauen, mit ZAP-Class an Sukurse und so weiter. Gut,
das will ich nicht wiederholen, wichtig,
aber es Wenn wir einen auf vielen Wegen erben können,
dass das System dann in der Lage sein muss,
dass es einen Klassenpräzedenzgraf errechnet, der sagt,
welche Klasse vor, welcher Vorrang hat,
wenn es um Erbschaftsstreitigkeiten geht.
Es muss möglich sein, eine strikte Ordnung zu definieren.
Und das macht der Klassenpräzedenzgraf. Und von dem können wir
erfahren, in welcher Reihenfolge geerbt worden ist.
In dem Beispiel hier, in dieser Vererbungshierarchie, Moment,
die so programmieren, sehen wir, dass die Erbung so geht.
Für Erbung, so geht es,
wir erben zuerst von der erstgenannten Oberklasse,
dann von deren Oberklassen in der Reihenfolge des Nennens,
dann erben wir von der nächstgenannten Oberklasse
und dann von deren Oberklassen
Das sagt uns der Klassenpräzedenzgraf, wenn wir zu faul sind,
das selbst rauszukriegen, rufen wir ihn auf und lassen uns mitteilen,
in welcher Reihenfolge wir geerbt haben.
Und wenn wir jetzt hier oben eine Klasse haben,
von der alle gemeinsam geerbt haben, dann geht es immer noch nach dem Schema.
Und ganz zum Schluss kommen wir bei der gemeinsamen Oberklasse an. Okay,
wenn wir jetzt nochmal auf dieses Beispiel Anzug Kyako Hose zurückkommen,
wir haben nicht nur Slots geerbt, sondern auch Methoden,
auch die Accessor-Funktionen auf die Slots sind Methoden, die wir haben, dann
Möchten wir eventuell lieber alle haben, statt nur einen davon.
Das haben sie hoffentlich jetzt auch in diese Woche
in den Übungen gesprochen. Ich möchte nur sicher sein,
dass es bei allen in den Übungen besprochen wurde.
Und deshalb wiederhole ich es hier nochmal kurz. Also zum Beispiel beim Anzug,
wenn wir den verkaufen wollen, ja,
und fragen nach dem Preis entweder,
dann können wir ja zuerst mal nur den Preis für die Jacke bekommen oder für die Hose.
Egal welchen der beiden nehmen wir,
wenn wir den Anzug für einen Preis eines der Einzelteile verkaufen,
sind wir bald bankrott.
Wir wollen verkaufen zur Summe der Preise
Oder wenn uns Kunden nach der Farbe von den Teilen fragen,
und wir geben immer nur eine an, dann sind sie enttäuscht,
wenn das andere Teil eine andere Farbe hat.
Geht auch nicht in die Kunden unzufrieden. Also muss man
sich irgendwas einfallen lassen? Wie kriege ich die Methoden sinnvoll
kombiniert? Und wenn schon so viele da sind und man
sich die Mühe gemacht hat, die alle zu programmieren,
warum sie nicht alle aufrufen und deren Ergebnisse gezielt kombinieren?
Und deshalb für den Preis möchten wir definieren können,
dass wenn jemand bei einem solchen Aggregat hat,
ihr habt von vielen nach dem Preis fragt,
dass dann alle Preismethoden aufaddiert werden und ich den Preis für
alle Teile aufsummiert kriege.
Bei den Farben möchte ich
die Farben als Liste zurückkriegen
Also implementieren wir es nochmal, diesmal mit der Oberklasse Kleidung und da definieren wir abstrakt eine Funktion,
generische Funktion preis und eine generische Funktion Farbe.
Und dann Jackett und Hose als Unterklassen davon und dann gemeinsam geerbt. So,
jetzt gucken wir uns das mal an,
wie das in Zählers geschrieben aussieht, Dev Klaas Kleidung,
ja, und da haben wir schon für die Größe initialisiertes Feld,
okay, wir definieren Generic Price und hier ist der wichtige Punkt deshalb in Rot.
Combination, wenn wir das hier unten hinschreiben,
dann wird für diese generische Funktionen gesagt,
wenn sie mehr als eine Implementierung hat,
dann werden sämtliche passende Methoden genommen, aufgerufen und deren Werte addiert.
Bei der Farbe haben wir gesagt, Kombination, Generic a Pento Combination.
Das heißt, die Resultate, die zurückgegeben werden,
werden mit Appent verbunden. Das erzwingt natürlich automatisch,
dass die Resultate, Teilresultate vom Typ Liste sein müssen.
Sonst geht es schief. Und jetzt haben wir wieder Jacketto und so weiter definiert.
Und wenn ich jetzt mal nach dem Preis frage,
Ich implementiere hier für das Jackett-Preis, ja,
20. Und für Hose implementiere ich eine Methode, die sagt,
der Preis ist 40.
Ich rufe jetzt im nächsten Moment auf, Preis von Mick Jackett kriege ich 20.
Wenn die Aufruhe bepreist von Mick Anzug, dann kriegt ihr aber 60 raus.
Warum? Weil die Preise für Jackett und Hose addiert worden sind.
Wenn ich hier die Farbe von Mekose aufrufe, ist sie vielleicht blau,
weil wenn ich jetzt einen Anzug erzeuge und frage nach dessen Farbe,
dann ist der rot und blau.
Ich kriege beide Farben zurück. Also das ist Die eine
Möglichkeit sicher mit Mehrfachvererbung umzugehen, dass wir gezielt sagen,
wenn mehrere Methoden eine generische Funktion implementieren, was mache ich damit?
Welche wähle ich aus? Wie sollen sie kombiniert werden?
Und die Liste, die wir sie zur Auswahl haben,
die schon fertig ist, ist zum Beispiel Generic Plus.
Das ist für den Preis verwendet worden. Wir können eine
Liste der Resultate machen. Wir können das Minimum nehmen,
das Maximum. Das ist mit Appent verbinden.
Das pennt mit dem Bang dahinter, ist destruktiv,
das hängt es wirklich in die Liste rein,
statt den Anfang zu kopieren.
Wir beginnen,
entnehmen oder oh
, ja
Ja, das ist besonders mächtig,
wenn wir uns daran erinnern, dass wir,
kann ich separaten, eine Funktion Preis definieren müssen oder so,
sondern die Akzessoren für die Slots sind ja schon,
schon generische Funktionen.
Und diese Akzessoren für die Slots können wir also nehmen und Methodenkombinationen dafür definieren.
Und dann wird der Zugriff auf die Attribute eines Objektes,
wenn wir uns die Slots anschauen, mit Methodenkombinationen gemacht und alles geschickt kombiniert.
Also wir sagen hier DevGeneric Preis,
der Preis soll kombiniert werden mit der Generic Plus Combination.
Und wenn ich jetzt die klassische Jackette definiere und sage,
die Accessor-Funktion auf den Preis des Jacketts, unterschiedliche Namen,
der Slot heißt Preis Jackett,
weil es in der klassischer Kate definiert ist,
die Accessor-Funktion soll Preis heißen,
dann implementiert diese Klassendefinition,
diese generische Funktion
hier oben
Mit einer Akzessorfunktion namens Preis. Und von der ist festgelegt,
okay, das hat mir Plus kombiniert. Ja,
und für die Hose, da haben wir die Akzessorfunktion genauso
Preis genannt, obwohl der Slot in der Klasse,
der hat einen anderen Namen, der heißt Preishose.
Also diese beiden Felder haben unterschiedliche Namen, können wir gut unterschiedliche Werte reinschreiben.
Wir können sie unterschiedlich initialisieren. Aber die Accessorfunktionen haben
denselben Namen. Und weil sie dieser Kombination hier unterliegen,
wird, wenn ich Preis aufrufe,
werden sämtliche implementierte Preismethoden für dieses Objekt mit mehrfach Vererbung
genommen,
Und entsprechend der Kombinationen zusammengefasst. Also das funktioniert, wann der war.
Jetzt bis hierhin sind wir vor Weihnachten gekommen. Ich hoffe,
für diejenigen, die vor Weihnachten nicht da waren,
reicht dieser Blitzdurchgang, dass sie auch im richtigen Fahrwasser sind mit uns.
Und wir jetzt den zweiten Teil gut anschauen können.
Jetzt soll es drin gehen, wenn ich eine Klasse geschrieben habe,
mit vielen, vielen Methoden, generischen Funktionen, die sehr spezifizieren.
Und jetzt hat die Firma also erfolgreich ein Jahr lang
das Paket verkauft
Aber die neuen Kunden haben noch ein paar extra Wünsche.
Und ich möchte die Geerbten Methoden für neue Unterklassen,
die speziellen neuen Kundenwünsche erfüllen, aufpeppen,
sodass sie möglichst viel vom alten Gut wiederverwenden.
Aber für den neuen geeignet sind. Wie macht man das
im Jahr wahr? Typischerweise, man hat eine Methode,
die macht 90 Prozent von dem, was getan werden soll.
Und in der neuen Unterklasse für den neuen Kunden
muss man noch ein bisschen was dazu tun.
Na gut, dann überlebt man die Methode mit einer neuen
Und für den Code, den man wiederverwenden will,
nimmt man den Supercall und ruft den aus der Oberklasse auf.
Also im Wesentlichen können wir das in Sillas auch so machen,
aber wir können es noch ein bisschen eleganter machen,
indem auf den ersten Blick klar ist,
was an Änderungen dazukommt gegenüber dem, was man überlädt.
Und von, wenn wir jedes Jahr neue Ärger da
dran bauen und eine ganze Latte von Änderungen haben,
die als Ergänzungen dazukommen, dann ist es sehr viel einfacher.
Wir verwenden das, was Sillas uns da bietet,
dessen Ergänzungsmethoden
Da sieht man auf einem Blick, wenn man Sints schreibt,
hier wird eine bestehende Methode genommen.
Es wird ein bisschen was davor gemacht.
Es wird ein bisschen was danach gemacht. Die definieren wir
separat und auch die können wir mit Methodenkombinationen dann kombinieren.
Also, der Supercall ist auch da, der heißt einfach Call Next Message.
Wenn wir ohne mit diesem Sonderen besonderen Zielasmöglichkeiten zu arbeiten,
mal eben die Methode der Oberklasse haben wollen,
dann sagen wir Call Next Message und dann wird nach
der entsprechenden der Klassenpräzedenz die nächste anwendbare
Methode genommen. Bei den Ergänzungsmethoden können wir aber sagen,
nimm die Methode, die du hast, aber mach vorher
ein bisschen oder mach nachher etwas ein bisschen oder mach ein bisschen drumherum.
Und das machen wir durch Schlüsselworte, bevor Around and After kenntlich.
Und das zeige ich immer an einem Beispiel aus dem Zählersbuch von Paul Graham,
das Beispiel finde ich einfach genial und das ist sehr hübsch gemacht,
wie das so geht.
Also wir haben eine klasse Redner. Ein Redner ist
ein Objekt, das einfach Text von sich gibt.
Und das hat Nichts weiter als eine Methode, dass ich sprechen kann.
Die heißt Speak. Das ist die Primary Remethod. So,
und wenn wir diesen Redner jetzt reden lassen und sagen,
immer soll das und das sagen, wird genau das rauskommen,
was wir ihm gesagt haben, was er sagen soll.
Jetzt machen wir eine zweite Klasse. Intellektuelle,
die sind ja dafür berüchtigt, dass sie das Gehirn einschalten,
bevor sie sprechen und ein bisschen drüber nachdenken.
Und dem wird etwas, wird zwar sagen,
was man bestellt hat, aber immer Einwände haben,
ein bisschen der Vorsagen und ein bisschen danach was sagen.
Und dann haben wir noch einen Diplomaten,
der zwar alles sagt, aber gleich an die rechtliche Situation
denkt und das noch einschränkt
Vorsichtige Klauseln, die es diplomatisch nicht angreifbar machen, dazu fügt.
Alle haben sie die Methode Speak. Und das implementieren wir
jetzt mal, also die simple Klasse Speaker,
Death Class, Speaker ab von nix außer Job.
Für die implementieren wir die Methode Speak. Ja,
es sei ein Speaker und er soll einen Text sprechen. So,
was macht das Ding, das zeigt einfach den Text an,
das Split-Text, dass die primare Methode, was er sagen soll,
wird wörtlich gesagt, ohne wenn und aber.
Also probieren wir es mal aus, die feinen S-Makes,
Speaker und rufen die Methode, die generische Funktion Speak-Off,
Speak, Das Objekt S soll sprechen, I am Hangried,
dann wird angezeigt, I am Hangry.
Jetzt nehmen wir den vorsichtigen Redner, also den Intellektuellen,
der zu einem seinen Senf dazu geben muss.
Und da ist er, der sagt sich, also mein,
ich muss ein bisschen davor sagen, das geht so nicht.
Nicht einfach so direkt heraus, das ist nicht intellektuell genug.
Und danach auch noch ein bisschen. Also,
der soll jetzt, wird den Text auch sagen,
aber vorher sagte I Think,
ja.
Und Tim daher
Weil das bei Think ist eben noch nicht vorsichtig genug.
Ihr habt ja in some sense. So. Und dadurch erreichen wir das.
Wir ergänzen die Methode Speak mit dem Schlüsselwort, hier,
before, wir führen eine zusätzliche Implementation für Speak ein,
kenntlich mit Before und das bevorsorgt davor,
dass bevor die primäre Methode ausgeführt wird, wird dieses ein Think ausgeführt.
Und dieses Schlüssel Wort After, das sorgt dafür,
dass wenn immer die primäre Methode ausgeführt und aufgerufen wird,
von einem Objekt dieser Klasse, intellektuell,
dann kommt dahinter noch das Insome Sense.
Jetzt erzeugen wir mal hier, intellectual und sagen ihm,
er soll die generische Funktion Speak anwenden, Speak intellectual I'm hungry,
dann kommt, I think, I'm hungry in some sense.
Wir haben die primäre Methode unverändert genommen, da haben wir,
wir haben keine Fehler gemacht beim Abschreiben und so weiter.
Wir müssen auch nicht mit Supercall explizit aufrufen.
Wir sagen einfach in der Unterklasse eine Intellektuelle, was davor
und was danach geschehen soll für diese Methode und fertig.
Die werden kombiniert. Man nimmt dieses im Wesentlichen dafür oder meistens
, wenn es darum geht, Initialisierungen sicherzustellen. Dadurch,
dass wir es auf einer bestimmten Ebene mit Before und After festgelegt haben,
was geschehen muss, kann in keiner weiteren Spezialisierung verhindert werden.
Dass unser Teil der Ballbevor- und Nachbarn, und After steht, wegfällt.
Es ist nicht möglich. Es ist in zehn das nicht möglich,
wenn Dinge mit Before und After in einer bestimmten Schicht da sind,
das wegzulassen, wenn jemand die generische Funktion verwendet und aufruft.
Die Vor- und Nachmethoden werden garantiert auf jeden Fall ausgeführt
So, und jetzt spezialisieren wir noch weiter,
um mal zu sehen, was denn passiert,
wenn wir viele vor Nachmethoden, für dieselbe Operation implementiert haben.
Wir haben eben jetzt eine Klasse Diplomat. Der soll es
noch weiter einschränken, damit wirklich ihr niemand darauf festlegen kann,
was er gesagt hat. Und der wird,
also bevor er irgendwas sagt, erst mal Purpose sagen.
Und wenn wir jetzt einen Diplomaten haben, und der soll sagen,
The World is round, oder der Ball ist rund,
wenn es ein Fußball-Fan wäre,
also und sagen,
Diplomat.de, the world is round, dann kommt per Höps,
I think, the world is round in some sense.
Also, das ist wirklich fürs internationale Parkett geeignet.
Jetzt haben wir also gesehen, dass wir in der Hierarchie
der Unteroberklassen mehr als eine Ergänzung haben.
Ja, in welcher Reihenfolge werden die jetzt eigentlich ausgeführt? Also,
es ist so geregelt, bevor die primäre Methode ausgeführt wird,
werden zunächst alle anwendbaren Vormethoden ausgeführt und wir beginnen mit der spezifischsten.
Ja, dann wird die spezifische Primärmethode ausgeführt und dann werden
Alle anwendbaren Nachmethoden ausgeführt. Und da beginnen wir mit der Allgemeinsten.
Okay. Also wir können das einfach mal testen in Zählers,
indem wir hier eine Klasse A schreiben und dann eine Klasse
Baby von Klasse A erbt und Klasse C ab von Klasse
B und da haben wir eine Methode teste.
Und die schreibt Right Lang Klasse A. Und dann führen wir hier
eine Bevormethode für Klasse B, ein VB und After,
die schreibt Nacht B und dann ein Bevor C und der
schreibt Nacht C.
Und dann müssen wir
es aufrufen
Wir erzeugen ein Objekt der Klasse C und testen C,
dann kommt erst VC, dann VB,
dann kommt die primäre Methode Klasse A, dann Nacht B, Nacht C.
Also für Initialisierung ist das unglaublich wichtig,
dass wenn wir Code schreiben, ja, und diese Initialisierungsmethoden haben,
dass wir sicher sein können und ruhig schlafen können,
dass jeder, der unser Paket spezialisiert und die Methoden ergänzt,
dass nichts von unseren Initialisierungen wegfallen kann.
Es wird über die ganze Schicht von Vererbung, ist sichergestellt,
dass diese Grundoperation gemacht werden, Diese generische Funktion aufgerufen wird.
Okay, also das ist deutlich sicherer als beim Supercall.
Sonst müssten wir auch immer in unserer Software genau dokumentieren,
was bei Spezialisierung auf jeden Fall noch aufgerufen werden muss,
um die Initialisierung sicherzustellen.
Das können wir uns in ziellos sparen, weil das kann nicht spezialisiert werden,
ohne dass unsere Vor- und Nach-Methoden ausgeführt werden.
Also wir müssen, es wird auch eben nicht überladen und verschattet, sondern es wird ergänzt.
Es ist ein Sonderfall von Todenkombination, bevor and after.
Also ich finde es sehr mächtig und macht den Kurt unglaublich
gut lesbar. Und man sieht auf den ersten Blick,
wenn man sich anschaut, was gemacht wurde in der Erweiterung.
Man sieht an dem Vor- und Before-and-After einfach deutlich, was ist hinzugekommen?
Hier, als Beispiel möchte ich Ihnen jetzt auch noch eine Anwendung zeigen.
Und zwar möchten ein kleines Simulationssystem programmiert, einfach deshalb,
weil es wirklich in jedem Lehrbuch was objektorientiert halt einfügt zu den Klassikern,
steht immer drin, wie mache ich so eine ereignisorientierte Simulation.
Ja, und die wollte ihnen zeigen,
dass das eben auch gut im Funktionalen Programmierstil geht.
Und wir können an dem Beispiel sehen, wo ich diese
Arten von Vererbung, Ergänzungsmethoden und so weiter genutzt habe.
Also das System hat verschiedene Ebenen. Zum einen ist es einmal
ein abstrakter Rahmen, der erlaubt, etwas zu simulieren,
was sich über ereignisorientiert, diese Simulation darstellen lässt.
Und dann haben wir verschiedene Anwendungen, dieses Simulationsrahmens, wo spezielle Bediensysteme gezeigt werden.
Ich habe den Rahmen genommen, um mal ein Bediensystem zu implementieren.
Der Klassiker-Bediensystem ist, es gibt eine Station oder mehrere Stationen,
wo Kunden hingehen können und sie werden bedient.
Und solange sie nicht bedient werden, müssen sie sich anstellen in der Warteschlange.
Und der Ablauf dieser Bedienung geschieht eben so,
dass immer die Person, die vorne steht, wird bedient,
die geht dann weg und ist glücklich oder auch nicht.
Und dann kommt die nächste dran und so weiter. Und der Ablauf,
wenn man das simuliert, wird so entlang eines Zeitstreits geschehen.
Im Gegensatz zu einer kontinuierlichen Simulation modelliert dann bei der ereignisorientierten immer nur die Momente,
wo die Welt sich ändert und definiert dafür Objekte vom Typ Event,
die dafür sorgen, dass die Simulation voranschreitet.
Wir haben eine Uhr, die zeigt, wie weit ist die Welt,
in der wir laufen und haben einen Kalender und in diesem Kalender wird vermerkt,
Kunde soll eintreffen um 10.3 Uhr, Bedienung endet, dann und dann,
nächster Kunde trifft dann und dann eine Bedienung, endet dann und dann.
Und im Wesentlichen gibt es eine Einheit, ein Skettjule,
der trägt immer in diesen Simulationskalender ein, wann ein Ereignis eintreten soll. Und es gibt einen Dispatcher,
der guckt so in der Schlange der anstehenden Ereignisse,
die jetzt geschehen sollen nach, welches ist das erste Ereignis,
was jetzt als nächstes geschehen muss,
und teilt dann den Akteuren mit, aha,
wir haben das Ereignis, Bedienung beginnt, ja,
dann wird es ausgeführt und das nächste Ereignis gleich per Dispatcher wieder reingeschrieben.
So, dieses Grundschema, das können wir uns dann in
verschiedenen Implementationen im Recket
mal anschauen
Also die Simulation ist einfach deshalb so interessant,
weil wir, ja, ein Modell einer Anwendungsdomäne entwerfen.
Und da können wir drin experimentieren, ohne dass wir es
in der realen Welt kaputt machen. Aber die Herausforderung ist immer,
dass wir das abstrakte Modell, in dem wir es implementieren,
testen, vorhersagen, machen es als Vorhersage-Modell nehmen,
dass es in allen wesentlichen Dingen zur realen Welt identisch ist und wir die Ergebnisse auch übertragbar sind.
Also wenn man sowas verwendet, ist der Punkt Modell Validierung mit die Hauptaufgabe,
dass man aus den Vorhersagen des Objektes sagt und des Modells sagen kann,
unter welchen Bedingungen ist es eigentlich übertragbar.
Man macht es, wenn es in der realen Welt technisch
gar nicht möglich wäre, wenn wir eine Raumfahrtmission planen,
bevor wir auf dem Mars sind, können wir schlechte.
Vorhersehen, wie es da sein wird oder wenn es zu teuer
wird oder zu gefährlich ist oder wir es immer wieder machen wollen und das Modell soll verschleißfrei sein.
Also das Schöne an der Software ist, die Software können wir,
ich weiß nicht, wie oft benutzen,
ohne dass es der Sand im Getriebe gibt,
nur die Hardware, auf der die Software läuft,
die unterliegt im Verschleiß
So, also so ein Simulationsmodell, wir untersuchen unsere Anwendungsmodelldomäne,
fragen uns, was ist da wichtig?
Denn abstrahieren wir die wichtigen Teile, die modellieren wir explizit.
Und das, was wir für unwichtig halten oder entschieden haben,
dass es unwichtig ist, lassen wir es weg.
Das große Problem bei der Methode ist,
dass wir beim expliziten Modellieren wirklich darüber nachgedacht haben,
was nehmen wir und wie machen wir es.
Beim Weglassen können wir nur über einen Teil nachdenken,
den wir weglassen und das ist ziemlich viel,
was unendlich viel, was wir weglassen,
worüber wir
nie nachgedacht haben
Ja, da ist die Klemme bei dem ganzen Vorgehen.
Es geht gut in einer abgeschlossenen Welt, wo das,
worüber man nachdenken muss, endlich ist. Und die hat man selten. Gut,
aber da muss man das Modell validieren,
dann simulieren wir unsere Anwendungsprozesse im Modell und machen eine Rückübertragung
auf die reale Welt und sagen, ja,
in 100 Jahren haben wir eine mittlere Temperaturerhöhung weltweit von 5 Grad oder so.
Mal sehen. Und das ist eben der kritische schwierige Punkt
Nee. Bei der Zeit diskreten Simulation, da gucken wir jetzt mal drauf.
Also im Wesentlichen läuft es entlang eines Zeitstrahls ab und wir modellieren
die Welt bei dieser Methode, sodass sie in Sprüngen voranschreitet.
Wir schauen uns nicht die Zeiten an, wo nichts geschieht,
wo sich nichts ändert, sondern nur zu diskreten Punkten tritt ein Ereignis ein.
Und dazu haben wir eben die Uhr,
die uns anzeigt, wie spät es ist,
wo wir gerade eine Simulation sind und den Kalender,
wo die Ereignisse, die antreten sollen, Kunde kommt,
Kunde geht, ist bedient worden, hat bezahlt,
begeht Zechbrällerei.
Das wird ja so vermerkt
Diese Schleife ist so alt, erfunden worden in der Zeit,
wo wir imperativ programmiert, nur imperativ programmiert haben.
Ich habe es jetzt hier tatsächlich auch mal als Repeat in Imperativer Sprechweise geschrieben.
Letztendlich wird so ein Bedienensystem in einer Repeat an Tillschleife.
Können wir ein Zielos so schreiben? Das nächste anstehende Ereignis
im Kalender holen? Dann wird es gucken, was
das Ereignis ist. Ankunft eines Kunden. In dem Fall
wird beim Bedienensystem gesagt, plane das nächste Ankunftsereignis.
Ja,
ein Kunde trifft ein
Damit die Simulation weitergeht, muss in dem Moment,
wo ich einen Kunde trifft, ein Ereignis verbrauche,
ein neues Kunde trifft, ein Ereignis in den Kalender eingetragen werden.
Sonst steht das Ganze. Also jeder Kunde,
der kommt und sich anstellt, der gebührt einen neuen Kunden,
der die Zähne betrifft und dann dafür sorgt,
dass die Schlange nie leer wird.
Beim Ende einer Bedienung, dann verlässt der Kunde die Warteschlänge.
Und dann muss das nächste Ereignis geplant werden,
wenn die Bedienung des nächsten Kunden fertig ist.
Und das machen wir so lange, bis die Simulationszeit abgelaufen ist.
Und das gucken wir uns jetzt mal an in verschiedenen Arten
und bei denen können wir dann sehen,
wo diese objektorientierten Merkmale aus Zählers Greifen in der Modulierung und die Gutmachen.
Wir brauchen als kleinen Seitenschlenker noch, wir brauchen ein bisschen Statistik.
Warum? In einer solchen simulierten Welt möchte man nicht
alle Objekte manuell von Hand erzeugen und jeden explizit modellieren,
sondern man betrachtet sie eher als eine Menge,
die gemeinsame statistische Eigenschaften haben und man erzeugt dann automatisch
diese Menge mithilfe von Verteilungen
Das machen wir einfach statistisch, indem wir 10.000 Kunden erzeugen,
mit einer zufälligen Verteilung der Ankunftszeiten. Und wie uns,
wenn eines der Beispiele, die wir besprechen werden,
wird die Mensa sein, als wir uns in der Mensa am Essensausgabe schallt,
damit der Keller die Suppe offen in den Topf geschüttet wird.
Und auch das modellieren wir statistisch, dass nicht bei jedem Kunden
exakt gleich braucht, aber vielleicht einfach am einen gemeinsamen Mittelwert schwankt.
Die Verteilung, die wir brauchen,
das sind einmal Gleichverteilung, das nimmt man gerne,
wenn es zu jedem Zeitpunkt exakt gleich wahrscheinlich ist,
dass das Ereignis eintritt.
Und dann, das können wir einfach durch eine solche Wahrscheinlichkeitsdichte
machen, wo wir eine Konstante vorgeben.
Und bei der Simulation haben wir jetzt den Punkt,
dass wir nicht immer gucken wollen, ist das Ereignis jetzt angetreten, kommt es?
Wir wollen von dem Zeitpunkt, wo wir sind,
vorhersagen, wenn das Nächste einetrifft. Das heißt,
wir müssen die zeitlichen Abstände zwischen Gleichverteilten Ereignissen modellieren.
Und Dafür nehmen wir dann eine negativ exponentielle Verteilung.
Die beschreibt nämlich den Abstand zwischen gleichverteilten Ereignissen.
Ein Treffen des Kunden, zerfallenes Atomkerns und so weiter.
Und da hätten wir eine solche Wahrscheinlichkeitsdichte.
Ich habe ihn in Reckett für die verschiedenen Wahrscheinlichkeitsdichten,
die wir brauchen, die einfach mit in der SE3-Bib modelliert.
Wie wir das machen, brauchen wir jetzt uns nicht mehr
so genau anzuschauen. Aber die zeitliche Verteilung zwischen gleichverteilten Ereignissen
folgt eben einem solchen Negativ exponentiellen Verlauf.
Also je größer die Wartezeit ist, desto unwahrscheinlicher ist es,
dass wir so lange hätten warten müssen
Also es ist unwahrscheinlich, wenn gleichverteilt in jedem Moment ein Kunde den Saal betreten kann,
dass wir tausend Jahre warten müssen, bis der nächste kommt.
Kann vorkommen, aber es ist unwahrscheinlich, okay.
Dann haben wir für das Schöpfen von Suppe auf den Teller
und so weiter, da gehen wir davon aus,
das dauert im Wesentlichen immer wieder immer gleich lang,
aber mit leichten Variationen, da können wir eine Normalverteilung nehmen.
Und auch das haben wir vorgesehen, so die Folgen,
die ich eben übersprungen habe, beschreiben,
wie man eine Wahrscheinlichkeitsdichte nimmt und daraus Dass die nächsten Wert erzeugt.
Ja, das ersten, zum einen, wie meinen Namen
Zufallszahlen gut erzeugt, worauf man achten muss und so weiter.
Das nehmen wir alles gegessen hin, ob ich sie für implementiert,
aber es steht im Skript drin, wie man es machen müsste.
Jetzt gucken wir uns mal das System an und die verschiedenen Komponenten, die wir brauchen.
Also wir haben zum einen einmal eine Klasse Akteure.
Das ist alles, was in dem Simulationssystem aktiv ist,
das können die Kunden sein, das ist aber auch der Kalender,
der Simulationskalender, der immer sagt,
jetzt steht das nächste Ereignis an,
Akteure sind die Leute, die bedienen. Das ist die Tür in die Mensa,
wo Menschen reinkommen können und die uns,
also alle Augenblicke in neuen Studenten generiert,
der die Szene betritt und dann irgendwas tut.
Wir brauchen also erstmal diese Dominobjekte von der Klasse Actors.
Wir brauchen Ereignisquellen, Objekte, die dafür sorgen, dass die Simulation weitergeht.
Also durch das, was sie tun und handeln,
dafür sorgen, dass neue Ereignisse eintreten können.
Dann haben wir Ereignisse, die etwas auslösen als Klasse.
Die werden behandelt, müssen behandelt werden, Kunde eingetroffen oder so.
Ja, Kalenderuhr, wir haben Protokollfunktion,
Dienstleistung, über die reden wir heute nicht
Die Klasse der Akteure hat ein paar Grundoperationen,
also unabhängig davon, was es eigentlich für ein Akteur ist,
ob das der Mensch an der Essensausgabe ist oder die Kunden, die kommen.
Die Basisdienste ist auf jeden Fall, dass die Objekte initialisiert
werden müssen und in den Startlöchern stehen für den Anfang des Simulationslaufes.
Wir müssen auch alle wieder in den Startlinie zurückbringen können,
wenn die Simulation beginnt, das Rücksetzen, den Prozess starten,
dass sie in Gang kommen und wir müssen fürs Protokoll immer fragen,
können da,
wie geht es euch,
welchem Zustand seid ihr eigentlich
Deshalb die Klasse Sim Actor, die hat sie Initialisierung,
einen Staat, dann geht das Ganze los,
Abfragen und einen Broadcast an alle, dass man die Akteure immer fragt,
alle wieder zurück oder gebt mal euren Zustand oder so.
Und wir müssen sie darstellen,
können deshalb bei dir das Objekt auch noch eine Viewklasse,
die anzeigt, wie sie aussehen soll.
Und habe ich hier abgekürzt zu einem kleinen Picture,
einem Bild, was sie haben. Unsere Objekte,
das habe ich vielleicht etwas übertrieben gemacht, indem wir,
aber um zu zeigen,
wo man mehrfach Vererbung nutzen kann,
viele,
viele Objekte verwenden
Sind Aggregate aus vielen Dingen und verwenden viel, viel Methodenkombination.
Zum Beispiel der Simulationskalender ist ein Aggregat aus einer Uhr und
einer Tabelle mit den Daten, in denen drinsteht,
in welchem Zustand, ja welche Ereignisse demnächst anstehen sollen.
Jede Komponente im Aggregat hat eine klassenspezifische Initialisierungsmethoden. Und wenn
wir jetzt solche Aggregate initialisieren, dann muss man natürlich dafür sorgen,
dass es initialisiert wird für alle Klassen, von denen sie geerbt haben.
Und deshalb Hat die generische Funktion Sim Inite, die dafür sorgt,
dass was immer ein Objekt in unserer Simulation ist,
das initialisiert werden soll, verwendet die Generic Beginn Combination.
Das stellt sicher, dass sämtliche Initialisierungs-Implementation, Methoden-Implementationen durchaus geführt werden.
Wird keine vergessen. Beim Simmstart wird der Staat auch an sämtliche Teile weitergegeben,
aus denen das Objekt zusammengesetzt ist, damit die auch alle gleichzeitig loslegen.
Und beim Info fragt man auch, alle Zeitlassen,
von denen man geerbt hat und kriegt deren Ergebnisse zurück.
Dann haben wir eine Klasse, die beinhaltet alle Akteure der
Szene und die hat im Wesentlichen eine Liste der Akteure, die vorkommen.
Und wir erzeugen diese Liste und hat eine Methode Ad Actor,
dass wir auch was weitere Akteure hinzufügen können.
So, wenn die Objekte, das endet war,
die Objekte sollten das, was sie zu tun haben,
initialisieren, an die richtige Stelle gehen und so.
Die Eigenschaften zu initialisieren. Dafür wird im Konstruktor
Das habe ich vorhin vergessen zu erwähnen, schade.
Also, wenn wir Milk verwenden, ja?
Nein. Habe ich hier nochmal einen Weg?
Nein. Muss ich aus dem Kopf machen. Also,
wenn wir Milk verwenden und Ambjekt, ein Objekt einer Klasse zu erzeugen,
das habe ich das letzte Mal betont, dann geschehen zwei Dinge.
Zum einen, das Objekt wird erzeugt, Milk rooft,
die Funktion Make Instance of. Das ist eine reine Funktion,
ja? Weil solange wir ein Objekt noch nicht erzeugt haben,
hat es keine Klasse und wir können nicht über die Klasse drauf zugreifen.
Also, wir können nichts klassenspezifisches damit machen.
Wir sagen dem Make, erzeugt mir ein Objekt dieser Klasse.
Und in dem Moment, wo das Objekt existiert.
Haben wir ein Objekt, das eine Klasse hat?
Und ab dann können wir klassenspezifisch generische Funktionen darauf anwenden.
Und dann wird automatisch die richtige Methode ausgewählt und so weiter.
Und deshalb ist es in Zählers so gelöst,
sobald das Objekt existiert, wird uns zu gefallen,
die Methode oder generische Funktionen indische Lize aufgerufen,
für das Objekt dieser Klasse.
Und das ist unsere große Chance, dass wir für diese
Klasse schreiben können, was indische Lize eigentlich tun soll.
Und deshalb Werden wir, gehen wir jetzt mal wieder hier hin.
Für die Klasse Set of All Actors, die Methode Initialize
, verwenden. Und zwar als Nachmethode. Irgendwas tut.
Unser Zylos ja schon, in dem es Initialize aufruft.
Ja, die primäre Methode wird ausgeführt. Dann kriegen wir
ein Objekt, das ist schon ziemlich gut initialisiert.
Und alles, was wir jetzt an Sonderwünschen für die Initialisierung haben,
die stecken wir in eine Nachmethode zur indischen Live.
Die wird ausgeführt, wenn das Objekt so weit initialisiert ist,
wie es aufgrund der Klassendefinition vorgegeben ist.
Und was tun wir in der Klasse für List of Actors
Ja, die, wenn immer wir ein neues Objekt erzeugen,
vier Object-Sim-Actor, hier haben wir ein neues Objekt erzeugt.
Und wenn immer wir ein solches Objekt am Wickel haben,
dann rufen wir die Methode at Actor auf für All-Actors.
Und ein neu erzeugtes Objekt wird bei der Initialisierung in
der Liste aller bekannten Akteure automatisch dahinter gehängt.
Oder davor, in dem Fall. Was immer at Actor macht,
ja, ist die Liste der aller Akteure wird hier verwaltet.
Und wie gesagt, hier steht After Initialisierung,
also solange jemand die Klasse Sim-Actor verwendet,
Hat er in unserem System keinerlei Möglichkeiten zu verhindern,
dass dieser Akteur bei der Initialisierung gleich in der Liste aller Akteure eingetragen wird.
Das ist also sehr sicher. Noch, weil das Initialize
After wird auf jeden Fall gemacht. Wenn da jetzt
noch 30 Spezialisierungen kommen, die würden vorher ausgeführt werden,
aber irgendwann sind wir dran und dann wird dieses indische Lize auch ausgeführt.
Können wir drauf bauen. Und das zweite Argument Axt ist einfach eine Liste,
dass fast alle Argumente zusammen, die im Make übergeben wurden
und die erfahren wir in dem Moment und können auch noch darauf reagieren.
Jetzt haben wir also Akteure und wir wollen, dass die Simulation
in Gang kommt. Und dazu müssen wir diesen Terminkalender führen,
der sagt, wenn das nächste Ereignis stattfindet, ja.
Und der hat diesen Dispatcher und guckt sich an,
was ist das nächste Ereignis in meiner Liste.
Dann muss das Ereignis ausgeführt werden. Also diese Ereignisverwaltung weiß
wahrscheinlich gar nicht, was geschehen soll.
Es hat aber eine Methode Hände, die die Akteure kennen.
Also die Akteure selbst müssen das Händel Implementieren und dann weiß man,
dann und denen teilt man mit, dass sie was zu tun haben.
Wir haben die Uhr, die muss zu Anfang gesetzt werden.
Und wir haben insgesamt noch einen Kontrollrahmenszenario,
der alles nett zusammenfasst, dass man es leicht aufrufen kann.
Ich habe ja gesagt, wir werden ziemlich viel mit mehrfach
Vererbung in diesem System zu tun haben.
Erstens, um zu sehen, wie man damit sicher umgeht.
Und zweitens, um auch mal Beispiele dafür zu haben.
Also die Klasse SIM-Sim-Szenario
Da hätte ich lokale Variable definieren können oder Slots für
ein Actorview, für die Clock und so weiter.
Aber was soll's? Wir sind in Erzählerswelt. Und da
bin ich dann den Weg gegangen, den viele Simulationssysteme gehen.
Dass Simulationsszenario erbt einfach die Dinge, die es braucht.
Ja, es ist eine Klasse, die ein Aggregat ist
von vielen Dingen. Das Ereignis selbst ist ein Event.
Wer will unserem Universum abstreiten, dass es ein Ereignis ist?
Es hat den Big Ben gemacht, ja. Wir haben der SIM-Kalender,
selbst ist auch ein Das sind, das Szenario selbst ist,
es hat nicht nur einen SIM-Kalender, es ist ein Kalender.
Es ist auch eine Uhr. Und das Szenario selbst,
weil wir auch sehen können, es handelt,
wir wollen ihm Nachrichten schicken können, es muss alles können,
was ein Ektor kann. Und deshalb ist es auch ein,
ihr habt es auch von der Klasse SIM-Ektor,
das tut es hier, indirekt über SIM-Block und Kalender,
hat zweimal den Zustand Ektor geerbt.
Und es hat ein Bild und wir können es darstellen.
Und der Kalender, der erbt von der Klasse Ranked Cue,
die wir vorhin eingeführt haben
So. Also, unsere Clock selbst erstmal,
diese Klasse erbt nur von diesem Ektor.
Sie ist ein Ektor, sie kann was tun.
Sie hat die ganzen Initialisierungssachen geerbt. Und damit sind wir
schon fertig. Der Kalender, der ist ein Sim-Ektor.
Kann was tun, kann initialisiert werden. Er ist auch
gleichzeitig eine geordnete Schlange. Ja. Und da werden wir
die Sachen so eintragen wollen. So, die Ereignisse,
die erben erstmal von gar nichts, außer von der Klasse top.
Was ist für ein Ereignis wichtig, wann es eintreten soll?
Get you are time, ja. Die Zeit ändern wir
nicht mehr, dass sie wirklich nur einen Rieder vorgesehen,
Nur zu Anfang dürfen wir es, sollten wir es
einmal initialisieren, aber im Wesentlichen brauchen wir den Rieder.
Der Initialisierungswert ist null. Und wir können eine andere Zeit
bestellen, wenn es eintreffen soll. Und für die Ereignisse
muss irgendwie implementiert werden, wie man damit umgehen soll.
Wir haben jetzt Defgeneric Handle. Es gibt bestimmte Ereignisse,
da können wir gleich sagen, was geschehen soll.
Zum Beispiel eine Verklemmung, ein Deadlock, wenn unser System einfach,
es steht nichts mehr an, was getan werden soll.
Es tut, ja,
dann dafür können wir einen Händler direkt programmieren und auch ein Quitt,
wenn von außen gesagt wird, Ende ist gekommen.
Und es nimmt Snapshot einfach mal festhalten, das steht zurzeit noch an.
Dann Skett Julia trägt die Ereignisse ein, sehen wir hier,
das Petcher holt eins raus und der Dispatcher, der eins herausholt,
der ist ganz wichtig, der muss dieses Ereignis auch behandeln,
ruft Tendel auf für das nächste Ereignis und dann hoffen wir,
dass was geschieht.
Okay. Und auch für die Ereignisse, für den Kalender
muss initialisiert werden Ich habe in dem Fall,
dass man verwendet, um dafür zu sorgen,
dass eine globale Variable Karre im Kellen der gesetzt wird auf den Kalender,
den wir gerade neu erzeugt haben.
Ja, und das auch mit Initialize After. So,
dass ein Szenario erbt viel versprochen von mehr Klock,
dem Kalender und dem Ereignis, ja.
Und indirekt erbt es auch von der Klasse Ector.
Dann haben wir eine Methode Simulate, da können wir eben so ein Universum übergeben.
Das Szenario, das simuliert werden soll, zu sagen,
wie groß es gezeichnet werden soll und noch ein paar Ticks,
das fast gezeichnet wird.
Die generische Methoden, die jetzt die Anwendungsklassen implementieren müssen,
dann sind wir später mal es eigentlich.
Die müssen vor allem Ereignisquellen erzeugen, ja. Also Kunden,
Türen, durch die jemand antreten kann und so weiter.
Ich muss sagen, wie es aussehen soll, alte Drow World,
ist da, aber das sollte dann schon implementiert werden.
Und die nächste Welt, wenn zu einem bestimmten Zeitpunkt
da gezeichnet ist, soll die nächste gezeigt werden.
Und mit dieser, diesen Vorbereitungen können wir das Ganze über
das Recht Market-Animationspaket Universe machen. Die Methode, Start der Simulation,
die registriert einfach in so einem Bracket-Universum, On-Key-Event und Tick-Event.
Jan Drehbrauerworld und Lastworld, wenn wir fertig sind.
So, ich gehe mal an die Stelle,
wo man auch sehen kann, was passiert.
Ereignisquellen, die müssen jetzt dafür sorgen,
dass einfach entsprechend der gewählten Statistik hier Gleichverteilung konstante Verteilung,
negativ exponentielle Verteilung,
das nächste Ereignis erzeugt wird
Und um das in Gang zu kriegen, verwenden wir die Weckermetapher.
Das hat auch in der Simulationswelt, hat sich rumgesprochen.
Statt da einfach nur Ereignisse in die Schlange zu tun.
Und das Ereignis muss jetzt drüber grübeln. Wim sag ich
, dass es abgehandelt werden soll. Macht man zu jedem
Objekt, das in der Simulation vorkommt. Die Kunden,
die Bedieneneinheit, die aktiven Elemente, die neue Ereignisse erzeugen.
All die sind selbst von der Klasse Event.
Die sind ein Ereignis. Also ein Kunde ist einfach seine
pure Existenz ein Ereignis. Und wenn ich jetzt dem,
wenn der Dispatcher jetzt das Ereignis eintragen will, neuer Kunde kommt,
dann schnappt er sich den Kunden und setze ihn in die Warteschlange.
Der ist das Ereignis in seiner Tabelle. Und wenn dann
das abgehandelt werden soll, hat er ja den Kunden,
also das konkrete Ereignisobjekt ist der Kunde oder die Bedienung.
Und dem wird jetzt gesagt, Tendel,
und der weiß dann, was er zu tun hat.
Also wir können den Kalender praktisch verstehen als Liste von Wegaufträgen an die handelnden Objekte.
Ja, weil die stehen in dieser Warteschlange drin,
sind von der Klasse Event und wissen,
was zu tun ist
Okay, dann haben wir noch die EreignisQuellen,
ich gehe da mal ziemlich schnell durch,
die will ich gar nicht so genau im Einzelnen anschauen,
sondern wir schauen uns jetzt mal so eine Bedienststation an.
Also wir haben hier irgendwie eine Bedienststation und Kunden kommen,
werden bedient. Die Bedienststationen selbst,
nur mal als abschreckendes Bild, ist die klasse Server Station.
Und die habt jetzt eben auch von allem,
was wir so eingeführt haben, sie ist erstens ein Sim-Ector,
sie ist eine Ereignisquelle.
Und an der Bedienung, wo wir das Essen ausgeben oder
so,
haben wir
eine Normalverteilung
Next Normal Event von der Klasse Erbs. Fürs Protokoll erben wir vom Pass,
dann haben wir bei der Bedienststation die Fifocue, von der wir haben.
Und es kann dargestellt werden, Serverstation View, ja.
Und wichtig ist jetzt für diese Bedienststation, wir haben die Operation Surf.
Damit können wir bedienen. So, und beachten Sie bitte
einen folgenden Punkt beim Bedienen. Die hängt ab,
erstens von der Klasse des Kunden, der bedient werden soll,
und zweitens von der Klasse der Station,
an der wir stehen.
Wenn sich ein Kunde anstellt,
dann macht er
einen Request
Und wenn gesagt wird, du stehst hier falsch,
geh erst mal raus und zieh eine Wartemarke oder so,
da haben wir das Reject und dann wird der Kunde weggeschickt.
Mit dem Pass, das macht die Statistik,
das gehen wir jetzt mal,
die Kunden selbst ist auch etwas kompliziert,
die kommen durch eine Tür in die Szene und diese Tür
erzeugt mit einer Gleichverteilung eben immer neue Kunden,
die rankommen und bedient
werden sollen
Wir gucken uns das System jetzt mal an ein Beispiel an,
das Menser-Szenario. Wenn wir uns jetzt mal vorstellen,
wir simulieren unsere Männer damit, dann haben wir da die verschiedenen Essensausgaben,
die erzeugen wir mit Make Station, ja.
Und dazu wird hier ein Mick the Servers aufgerufen und bekommen hier
die ganzen Mix Stations, Essen 1, Essen 2,
Essen 3 und so weiter.
Dann erzeugen wir einfach eine Liste von Kunden, ja,
und die werden, ja, auch erzeugt.
Ich glaube, mir hat einfach mal ein paar Namen ausgedacht
, egal
Wenn wir das jetzt aufrufen, dann finden es in der SE3-Bib-Sim-Mensa-Szenario Peckish.
Und da probieren sie mal Mensa-Demo, wann,
das ist die erste Lösung. Da sehen wir hier,
an der Tür steht noch kein Student, Zeit ist null,
an allen Bedienenstationen wird geschlafen, hier gibt es Corndocs,
Currywurst, Pizza.
Ja, dann kommt der erste Kunde. Jetzt die Simulationszeit
geht in Sprüngen, ereignisorientiert. Jetzt steht er bei der Pizza.
Jetzt warten wir darauf, dass er seine Pizza kriegt.
Inzwischen trifft Helmut ein. Dominik, ja,
bedienen ist ein bisschen langsam. Einer ist bedient worden,
sind im nächsten Moment, ja, Und so weiter.
Also hier läuft alles, die Kunden kriegen zu essen.
Jetzt wollen wir es mal spezialisieren, Essensausgabe und Gäste,
das ist eigentlich der Teil, wo wir jetzt ausnutzen können,
was wir besprochen haben.
Wir müssen, wenn wir jetzt eine neue Kategorie einführen,
die Männer halt gelernt, wir haben auch Vegetarier und möchte
auch eine Bedienststation für Vegetarier haben und Vegetarier sollen bedient werden.
So, jetzt brauchen wir spezialisierte Kunden und wir brauchen spezialisierte Essensausgaben.
Wir führen unsere Server-Stations spezialisieren. Also da,
wo es das Allgemeine Essen gibt, die Fleischtöpfe.
Dafür führen wir jetzt einen General-Foot-Server, die Erben von
der Server-Station und das Wetsie-Essen ist auch eine neue Klasse.
Ja, und wir haben eine neue Klasse, Kunden Vegetarier.
Die Methode Rejecting, die soll jetzt dafür sorgen,
dass wenn sich ein Vegetarier beim Fleischstapfen anstellt, dass die Bedienung verweigert wird.
Hier ist einfach Rejecting is true,
Und die Bedinnmethode, wenn sich ein Vegetarier anstellt,
bei den Fleischtöpfen, ist einfach reject.
Wird höflich aber bestimmt umgelenkt zum Brokkoli oder so.
Jetzt ist eine kleine, ein kleines Problem.
Und auch da finde ich, ist das Zählers ganz speziell
und bringt Spaß. Wir haben von der vorherigen Mensa-Szenario 1,
Klasse, haben wir nicht nur die Klassen geerbt.
Wir haben schon fertige Objekte geerbt. Das heißt,
wir haben schon Unmengen an Studenten, die wir geerbt haben
Und die betrachten wir erst mal als Nicht-Vegetarier.
Wir führen jetzt noch weitere Kunden ein. Wir ergänzen einfach
die Methode Me Customers mit einer Nachmethode. Für unser Mensa-Szenario 2.
Und da führen wir jetzt noch ein paar Vegetarier ein.
Wo ist Marie und Tinkerbirl, mit kleinen Kräuterhexen.
Und die kriegen, wie wir sie besser unterscheiden können als Bild,
mit dem sie angezeigt werden, das grüne Gesicht.
Das Grün beschreibt nicht die Qualität des Essens,
sodass man hängt nach dem Essen so aussieht, sondern einfach die Vorlieben.
Das heißt, Me Customers erzeugt noch weitere
Die Bedienstationen, aber die sind auch schon fertig.
Und die wollen wir auch nicht wegschmeißen. Wir müssen jetzt aus der einen Bedienststation,
die bisher Abs und Suppe mit Speck serviert hat,
eine machen, die jetzt ein Corndox servieren kann.
Und was macht man jetzt? Eine bestehende Station nehmen und
eine speziellere Klasse geben. Also die meisten objektorientierten Programmiersprachen,
die sagen, erzeuge eine neue Instanz,
kopiere alles rüber und diese neue Instanz wird dann genommen.
Aber das wollen wir nicht. Sitzt man auch dieselbe Frau in der Ausgabe?
Es ist die identische Klasse, wir vorher hatten,
das identische Objekt nur mit einer neuen, spezielleren Klasse.
Und deshalb verwenden wir jetzt um die Bedienstationen für die aufzupeppen,
dass die jetzt spezialisiert ist auf nur Fleisch ausgeben oder auf nur vegetarisches Essen.
Wir nehmen die bestehende Station und ändern die an Klasse mit Change-Class.
Ja, es ist dasselbe Objekt wie vorher,
hat jetzt aber nach dem Umzug eine andere Klasse.
Die Identität des Objektes ist gewahrt
In allen Datenstrukturen, wo es vorher drin stand, steht es immer noch.
Es hat jetzt nur eine neue Klasse. Also Chips-Class finde ich
extrem mächtig und nützlich. Nicht alle Programmiersprachen erlauben es,
dass wir an der Laufzeit eines Programms die Klasse eines Objektes geändert wird.
Da musste man neu erzeugen. Wir können jetzt,
also um hinterher die ganzen Bedienststationen neu zu machen,
also einfach die Methode, die die Klasse verändert,
hier mit Broadcast, an die anderen Objekte schicken.
Und das machen wir mit einer Nachmethode zu Mick the Servers.
So, jetzt ist unsere Mensa umgerüstet für Vegetarier.
Und wir können jetzt Mensa Demo 2
laufen lassen
Also hier gibt es jetzt Corndox, Currywurst, Pizza und Eintopf.
Und jetzt kommt ein Vegetarierin, stellt sich bei der Pizza
an. Da stellt sich Mr. Clou beim Eintopf an.
Ist vielleicht auch nicht so gut. Bei der Currywurst ist
ja die Grüne sofort weggeschickt worden. Und der arme Russmarie
bei der Currywurst geht es auch nicht gut.
Wir sehen jetzt die Implementation der Reject-Methode. Das heißt,
was wir an dem Beispiel sehen können für das Erweitern,
Die Methoden, die ich benutzt habe,
von mir aus der Software technisch,
Sicht um das bestehende System von Einheitsbrei auf Unterscheidung zwischen Vegetarier und Fleischesser zu erweitern ist.
Erstens, mit Nachmethoden wurden die Vegetarier hinzugefügt. Mit einer Nachmethode wurde dafür gesorgt,
dass die Mensa modernisiert wurde und die existierenden Objekte mit Chains Class geändert worden,
sodass sie spezieller sind und sich anders verhalten.
Und wir konnten durch Einfügen Wir konnten die Methode Reject so machen,
weil sie eben zwischen den Klassen steht und abhängig ist von Zweitklassen, dafür sorgen,
dass eben ein Vegetarier nicht aus Versehen Currywürste zu essen kriegt.
Ja, man für Cornlocks hält. Also die wichtige Methode ist einmal das Change Glass,
die Methodenkombination über Nachmethoden, die erlaubt hat, Dinge zu spezialisieren,
die Mehrfachverarmung, die es uns möglich gemacht hat,
dass die Kunden selbst als Ereignisse im Bedienkalender eingetragen werden konnten.
Und jetzt können wir uns nochmal angucken,
was wir alles an Initialisierungen hier kennengelernt haben
Also schon in der Klassendefinition können wir schreiben, Indit Value, Initializer and Indit arg.
Mit dem Indit Value hatten wir einfach für die Slots,
die vordefinierte Werte gegeben, die default sind,
wenn nichts anderes angegeben ist,
mit Initializer können wir schon in der Definition der Klasse eine Funktion aufrufen,
die das initialisiert,
mit Indit arg können wir im Konstruktor eine Markierung machen für die Argumente,
wo die vorinitialisierten Werte überschrieben werden sollen,
durch die,
die wir im Moment
direkt angeben wollen
Das Initialize After, das nehmen wir immer dann,
wenn wir so initialisieren wollen, dass wir die Klasse des Objektes kennen müssen,
in dem Moment, wo wir es identalisieren wollen.
Einfach eine Nachtmethode zur standardgenerischen Funktion Initialize und wir können sicher sein,
dass unser Objekt die Initialisierung alle überlebt. Dann Chains Class,
das ist die mächtige Methode, die wir anwenden können,
wenn wir nicht nur Klassen erben und implementierte Methoden,
sondern wenn wir geerbten Objekte übernehmen wollen.
Ja, aber an unsere eigenen spezielleren Klassen anpassen,
dann können wir die Klasse der Objekte ändern.
Und das Inded SIM, da hatten wir eine selbst definierte Initialisierungsfunktion,
die hatten wir deshalb schreiben müssen,
weil der ist Inded SIM erst dann loslaufen lassen können,
wenn alle Objekte erzeugt sind.
Also wenn sie in der Situation sind,
dass sie erst das Universum mit Planeten und allem ausgestattet haben müssen,
bevor sie den letzten Initialisierungsschritt machen können,
dann schreiben sie eine eigene Methode inded SIM
Und da war es ganz wichtig, dass wir Methodenkombinationen hatten,
weil ja alle Objekte, die wir haben,
fast alle, von vielen Klassen erben.
Und wir von allen Oberklassen des Indiz-Sim auch ausführen müssten.
Also hier wurden die Methodenkombinationen ganz wichtig. Okay. Vielleicht in
den letzten fünf Minuten noch einen Vergleich zu dem zur Syntax.
Und auch wie der Aufruf der Methoden geschieht.
Also typischerweise haben wir Objektorientierten Programmiersprachen, oft einfach die Art,
dass wir sagen, Tal, Object und wir senden eine Nachricht.
Ja, das ist das Message Passing. Und dann schreiben,
in Java würden wir es so machen, Objekt,
und dann schreiben wir die Nachricht hier hin und die Parameter.
Das ist bei generischen Funktionen komplett anders. Da schreiben wir
den Namen der Funktion und dann schreiben wir alle wichtigen Objekte hin,
auf die diese generische Funktion angewendet werden soll.
Das Problem bei dieser Punktnotation, Objekt und Message ist,
die Nachricht kriegt nur ein Objekt mit
Wir können dir nicht trauen, der vier Objekte vor dem Punkt schreiben.
Und damit diese Nachricht abhängig machen von der Klasse,
von mehr als einem Objekt. In dem Mensa-Beispiel eben,
wenn der grüne Wurzelsepp sich bei der Currywurst anstellt,
dann wird das Reject ausgeführt,
weil die Syntax der generischen Funktionen es möglich macht,
dass sowohl die Klasse der Bedienststation,
hier gibt es Fleisch und Klasse des Kunden, ich möchte vegetarisches essen,
dafür sorgt, dass die richtige Methode ausgesucht wird.
Einfach ein Reject, nein, gibt es hier nicht.
Und deshalb ist schon von der Syntax her
den Namen der Funktion zuerst und dann beliebig viele Objekte,
die alle mit ihren Klassen dafür sorgen,
dass die Auswahl der Methoden spezialisiert wird.
Macht es deutlicher, wovon es abhängt. Ansonsten ist die Schreibweise
nur syntaktischer Zucker, aber es ist mächtiger bei der Art der Methodenbindung.
Also, die dynamische Auswahl einer Methode kann von mehreren Objekten abhängen.
Und das ist das Wichtige dabei. Und wir können diese
generischen Funktionen einfach zwischen die Klassen schreiben. Diese Unified Modeling Language,
die ist auch dafür ausgelegt, dass jede Operation oder ihre Implementation
als Methoden von den Klassen, von einer Klasse abhängt.
Diese Methode Surving wüsste ich gar nicht, wie ich in dem Diagramm schreiben soll.
Ich muss sie zwangsweise bei Server Station oder bei Customer reinhängen.
Sie gehört aber eigentlich dazwischen. Und diese Notation erlaubte,
ist gar nicht ausdrucksmächtig genug, um Zählers beschreiben zu können.
Deshalb, es ist in der Zählersfeld eigentlich nur ein Notbehelf.
Okay. Noch ein Unterschied zwischen Nachrichtenmodell und generischen Funktionen.
Beim Nachrichtenmodell dient die Klasse auch gleichzeitig zur Modularisierung.
Das ist für sie die Art Java gewesen, wie strukturiere ich das Programm.
Dafür haben wir in der Recket-Welt einfach Module.
Und die Klassenfassung wirklich nur die Objekte mit ihren Attributen zusammen.
Die Klasse ist kein gekapselter Namensraum und sie ist keine Datenkapsel von der Syntax her.
Ja, erst wenn das Objekt existiert, ist es das.
Bei den generischen Funktionen haben wir die Klasse eigentlich nur zur Vererbung,
ist eine Datenkapsel für die Attribute der Objekte,
aber die Mutter Solidarisierung wird über Module und Pakete gemacht und
generische Funktionen können wir zwischen den Klassen beliebig überall spezialisieren.
Okay. Was ich im Skript noch beschrieben habe, sind weitere Dinge,
die typisch sind in dieser Welt und die auch benutzt werden.
Das können Sie sich in der SE3-Bib anschauen. Sowas wie
Broadcast und so weiter, wo wir einen Tell implementiert haben.
Ich wollte mir zum Abschluss einfach noch mal ein Beispiel aufrufen.
In der SE3-Bib haben wir auch ein weiteres Modul,
wo sie Das Mensa-Szenario sehen können und speziell jetzt erweitert auf die kleinen Provinz Aremorika.
Simulett Galia. Wenn Sie dann mal reinschauen,
ich hoffe,
es läuft überhaupt