Okay, 14.15 Uhr in Deutschland. Schönen guten Tag.
Kurz davor den Schaukelstuhl für mich rauszuholen, den Sie nicht sehen.
Ich sehe, das sieht aus wie eine Einladung.
Sie sehen da schon angeschrieben, Vorlesung 10 plus plus.
Und nachdem Ihnen Fred ja jede Woche erläutert,
den Unterschied zwischen plus plus i und i plus plus,
können Sie die Bedeutung dessen wahrscheinlich auch schon ahnen.
Die Folien, die ich heute dabei habe,
die werde ich nicht nur heute auflegen,
sondern wahrscheinlich auch noch nächste Woche
Nachdem Fried mich gebeten hat, ihm heute mehr Zeit zu geben,
weil er für seine Programmierübungen einfach mehr Zeit braucht.
Wird er also nach einem, zu einem bestimmten Moment in
dieser Vorlesung, wird er mir dieses Zeichen machen.
Und das bedeutet, dass wir dann hier den fliegenden Wechsel machen.
Ich weiß nicht, wann dieses Zeichen kommt.
Deswegen lege ich jetzt einfach mal los. Heute werden wir
uns beschäftigen mit einem Thema, das da heißt Klassenentwurf.
Und dieses Thema Da machen wir heute die Einführung,
da werden zwei Begriffe, werden eine besondere Rolle spielen,
die ich Ihnen rauf und runter versuchen werde, an möglichst einsichtigen Beispielen zu erläutern.
Das sind die Begriffe Kopplung und Kohession. Ich glaube,
ich verspreche Ihnen nicht zu viel,
das wird Sie noch ein paar Jahrzehnte begleiten,
dieses Thema, beziehungsweise diese beiden Begriffe,
weil das Thema Klassenentwurf, jedenfalls mindestens so lange,
wie wir es mit objektorientierter Programmierung als dem vorherrschenden Paradigma der Entwicklung interaktiver Softwaresysteme,
Solange es wir dann, solange wir es damit zu tun haben,
wird uns auch das Thema beschäftigen,
wie groß sollen Klassen sein?
Wie klein? Wie viele? Wie sollen die
miteinander zusammenhängen? Fragen über Fragen und wir werden uns,
also mal mit dem Erfahrungswissen, das die Welt bisher gesammelt hat,
zu diesem Thema und ein paar dazugehörigen Definitionen werden wir uns heute und nächste Woche beschäftigen.
Den Abschluss der Vorlesung bildet etwas, das heißt Solid,
das ist so ein Satz von Prinzipien,
da werden sie uns wieder in unserer Eigenschaft als Prinzipien Anreiter kennenlernen.
Das sind keine Prinzipien, die wir uns ausgedacht haben,
aber nachdem wir Freunde, Frontprinzipien sind,
ist es uns natürlich eine besondere Freude,
ihnen diese Prinzipien hier auch nahezulegen.
So, kurz nochmal zur Einstimmung, wiederholenden Einstimmung.
Diese Folie kennen Sie vielleicht schon oder noch. Es geht
um Qualität. Ja, wir haben schon mal so,
wir haben schon mal ein paar Aussagen über Qualität gemacht.
Insbesondere haben wir so drei, drei Arten von Qualität unterschieden,
externe, äußere Produktqualität. Das ist so alles,
was so mit den mit der Begrifflichkeit beziehungsweise sowas mit nach außen hin sichtbar ist,
an so einem Stück Software, also fragende Usability.
Dann gibt es die innere Produktqualität. Das sehen Sie auch,
dass Bertrand Meyer darunter versteht, also die ganzen Fragen von Verständlichkeit, Wartbarkeit, Modularität.
Also alles, was ein Stück Software von innen ausmacht.
Und die dritte Art von Qualität, die hier auf dieser Folie
überhaupt nicht thematisiert ist und die wir auch in den beiden Lehrveranstaltungen,
SE 1 und 2 nicht näher betrachten und wirklich nicht näher betrachten,
das ist die Prozessqualität
Die Art und Weise, wie ein Stück Software hergestellt werden kann.
Das ist die ganze Diskussion über Vorgehensmodelle. Das werden wir,
wie gesagt, hier nicht weiter vertiefen. Dazu können Sie dann,
wenn Sie das Thema interessiert, in die Lehrveranstaltung,
Softwaretechnik kommen, weil da werden die Vorgehensmodelle rauf und runter,
werden die dort Vorgehensmodelle der Softwareentwicklung, werden dort besprochen.
So, heute das Thema Kopplung,
Korrision im Zusammenhang mit Klassen im Zusammenhang mit Klassenentwurf ist ganz eindeutig,
also innerhalb der Diskussion über innere bzw. interne
Qualität verankert
Ja, mal gleich ein berühmtes Zitat an den Anfang dieser Diskussion zu stellen,
da fragen Sie sich also, wie soll ich eine Klasse entwerfen,
was macht einen guten Klassenentwurf aus,
sodass so Fred da drauf guckt und sagt,
das ist aber eine schöne Klasse, die Sie da geschrieben haben,
nach welchen Kriterien kann der das überhaupt so beurteilen oder welche Kriterien legt er an,
um also zu einem solchen Urteil zu kommen.
Dieses Zitat da in der Mitte sollte sich in ihre Retina,
sollte sich das so ein bisschen einbrennen,
so ein Objekt ist ein Verantwortungsmitfall, verantwortungsvolles Mitglied einer Objektgemeinschaft.
Dieses Objekt, also das, was zur Laufzeit aus einer Klasse erzeugt wird,
sollte sich insbesondere dadurch kennzeichnen, auszeichnen, dass es eine bestimmte Aufgabe gut erfüllen kann.
Das ist eine Aufgabe, eine bestimmte Aufgabe,
nicht zwei Aufgaben und nicht also unbestimmte Aufgaben,
sodass man sich fragen muss, wofür ist dieses Objekt eigentlich zuständig,
sondern in so einem Objekt Geflecht in dieser Gemeinschaft von Objekten soll ein Objekt,
dem soll man ansehen können so wozu es gut ist,
also wozu, wofür es verantwortlich ist.
Und diese, die Grundidee hier,
Leitbild genannt ist einfach solche Zuständigkeiten so zu schneiden, in Anführungsstrichen,
dass man so einem Objekt ansieht, Westgeisteskind, Westgeisteskindes ist.
So, wie kriegen wir das hin? Da hat also eben jede Rebecca Verse Brock,
hat sich eine Art von Methode überlegt und Grundgrund oder ein
wesentlicher Bestandteil dieser Methode sind die sogenannten CRC-Karten,
wobei die drei Buchstaben CRC stehen für Klaas, Responsibility und Collaboration.
Klaas bedeutet, das Ding braucht einen Namen,
einen Namen, der treffend ist. Einen Namen,
der schon mal so eine Idee davon gibt,
also wozu dieses Ding gut sein könnte.
Gute Idee ist, also jetzt bin ich mal über,
jetzt frage ich gleich, guter Name ist Konto.
Das ist ein super Name. Da kann jeder sofort
was mit anfangen. Ein schlechter Name ist,
konnten Manager, konnten Assistent,
konnten irgendwas
Also immer, wenn so Manage,
wenn das Ding Manager heißt oder wenn es Assistent heißt,
ist das schon mal so ein Zeichen dafür, hm,
derjenige, der diese Klasse geschrieben hat, der wusste nicht so genau,
wozu das gut ist oder nenne ich es mal Manager.
Oder ich sage eben Assistent dazu, weil das kann so,
dass die Hoffnung ist derjenigen, die das lesen,
gucken nicht so genau hin, haben so eine ungefähre Vorstellung,
was es sein könnte und dass diese Vorstellung möglicherweise falsch ist,
dazu kommen wir dann später.
Also treffende Namen, Zuständigkeiten, das ist das,
wofür das Ding nach außen hin steht, kann es?
Wie sieht die Schnittstelle dieser Klasse aus? Das ist also,
dass nach außen hin sichtbare Interface,
nach außen hin sichtbare Interface ist das ein bisschen doppelt gemobbelt,
weil es ist ja, das Interface ist gerade dadurch gekennzeichnet,
dass es nach außen hin sichtbar ist.
Aber ich möchte dem Ding an seiner Schnittstelle ansehen können, wozu es gut ist.
Und nicht, ich habe sich auf gar keinen Fall möchte,
ist, ich möchte in das Innere einer Klasse schauen müssen,
um zu verstehen, was es tut.
Das Innere möchte ich höchstens gucken, um zu schauen,
wie es das tut, was es tut.
Aber das ist eigentlich etwas, was ich vermeiden möchte.
Und der dritte Teil, die Zuständigkeiten, die Collaborators,
das ist der Teil, was brauche ich, um das,
was ich nach außen hin versprochen habe, um das realisieren zu können.
Also die Menge von Zuständigkeiten, die Klasse wird,
also ihr Versprochenes, nach außen hin sichtbares Verhalten nicht alleine,
nicht vollständig selbst implementieren,
das wäre wirklich seltsam und es sind in den allermeisten Fällen falsch,
sondern diese Klasse wird sich auf andere Klassen mit ihren je eigenen Zuständigkeiten,
Entschuldigung, mit ihren eigenen Zuständigkeiten beziehen um ihr Verhalten zu realisieren.
So, das kann man sich jetzt überlegen, also wie,
so, wenn man das, denke, diese Idee ist erstmal so grundsätzlich nachvollziehbar.
Jetzt, also diese Methode ist in den 80er Jahren entstanden
und es hat unzählige Versuche gegeben. Mittlerweile ist das,
glaube ich, wird es, glaube ich, nicht mehr so häufig gemacht,
zu sagen, okay, wir implementieren jetzt so ein Stück grafische Software, mit der also CRC-Karten dann also dargestellt werden können. Das hat sich seltsamerweise nicht durchgesetzt. Das,
was man aber manchmal sieht, ist,
dass Menschen in ihrem Alter, die so kleinere Stücke Software schreiben,
die so meinetwegen aus 10, 20 Klassen bestehen,
dass die anfangen, also mit so kleinen Pappkarten,
also zu experimentieren, sagen so,
ich mache mir jetzt mal hier so eine Klasse,
mit so ein paar Zuständigkeiten, da schreibe ich mal links,
also die nach außen hin sichtbare Schnittstelle auf,
was braucht ihr denn alles, die braucht also so,
wenn sie das hier an dem Beispiel verfolgen,
also ich brauche sowas wie eine Liste oder ich brauche sowas wie einen Behälter,
gut, dann brauche ich eben eine Karte, glaube ich,
Behälter drauf und mache die Zuständigkeiten, dann entstehen so Objektgeflechte,
so Geflechte hoffentlich so in einer hierarchischen Form,
keine zyklischen Abhängigkeiten,
komme ich gleich nochmal drauf zu sprechen und dann können sie so Abläufe Use Cases mit diesem,
mit diesen Karten können sie durchspielen.
Dann können sie auch schon mal so unter Verwendung dieses einfachen Mittels-CAC-Karten,
können sie schon mal sehen. Also da gibt es
sehr große Klassen oder gibt es viele ganz kleine Klassen.
Das heißt, sie kriegen so eine Idee davon, also wie die Funktionalitäten,
die sie implementieren wollen, wie die auch verteilt sind.
Und das ist ein extrem anschauliches, um nicht zu sagen handgreiflich,
b-greifliches Hilfsmittel, diese CAC-Karten. Also kann ich Ihnen nur empfehlen,
dass zur Vergegenständlichung ihrer eigenen Ideen sich durchaus mal,
also so ein Kärtchen,
so ein Stapel Kärtchen zu kaufen und das in so einer Designrunde am Tisch,
wo auch immer, mal durchzuspielen,
welche Verantwortlichkeiten von welchen Klassen implementiert werden sollen und wie die miteinander zusammenhängen.
Und das, was diese Karten so attraktiv macht, ist,
man kann sie wegschmeißen. Das ist vielleicht nicht so ökologisch,
aber vielleicht erstmal umdrehen und einen neuen Versuch starten.
Aber man kann also mit diesen Karten spielen, in Anführungsstrichen.
Man kann also Entwürfe auch mal versuchen,
Alternative Entwürfe durchzuspielen, wie sich diese Karten ergeben.
Die physikalische Begrenzung dieser Karte hat, man ahnt das ja nicht,
was da so an impliziten Konzepten Sequenzen jeweils dranhängen.
Diese, die Begrenztheit der Karte, also so dieses DIN
A6-Format ist das, glaube ich, oder?
Also maximal DIN A5 sollten die haben. Die dient auch dazu,
sich selbst mal zu disziplinieren, weil es gibt so Entwurfsregeln,
die sagen, eine Klasse sollte nicht mehr als sieben exportierte Operationen haben.
So diese Zahl sieben, die begegnet einem ja immer wieder.
Das ist ganz seltsam. Sieben Wochentage, sieben Todsünden,
sieben Sakramente Die 70er. Die 7 Zwerge. Wie bitte?
Meerich-Freund einer Verschwörungstheoretiker, würde ich jetzt mich verfolgt fühlen.
Also, und eine Methode soll nicht mehr als sieben Zeilen-Code
haben und auch schon gar nicht mehr als sieben Parameter.
Und diese Begrenztheit der Karte hilft einem auch,
also sich da ein klein wenig zu disziplinieren und nicht nur so Klassen zu schreiben,
die auf einmal sieben mal sieben Operationen nach außen hin zur Verfügung stellen.
So, also meine Einladung an Sie, haben Sie das,
das haben Sie jetzt in Ihrem Methodenköfferchen,
diese CRC-Karten und bei Gelegenheit holen Sie das wieder raus.
So, jetzt komme ich zu den beiden zentralen Begriffen für
die nächsten paar Minuten, Kopplung und Kollision.
Nur die Grundidee haben wir jetzt gerade schon kennengelernt,
den Entwurf nach Zuständigkeiten. Also ich will wissen,
wofür ist dieses Ding namens Klasse, also diese Klasse,
die ich jetzt gerade implementieren will, wofür ist die zuständig?
Und das sollte ich in einem, in einem geraden deutschen
Satz ausgedrückt durch einen substanzen sollte ich das sagen können.
Darüber hinaus wollen wir jetzt also diese zwei Prinzipien,
Kopplung und Kohision und Sie sehen schon,
in welche Richtung das geht, wollen wir kennenlernen.
Kopplung ist etwas, das ist Böses, das gehört zu den sieben Todsünden.
Und die Art von Kopplung, das heißt also die Art und Weise,
wie Klassen miteinander in einem Objekt orientierten Entwurf miteinander verbunden sein sollen, sei lose.
Umgekehrt ist es bei der Kohision, das ist so,
ich komme gleich noch zu den exakten Definitionen,
jetzt erstmal so die Einführung in diese Begrifflichkeiten,
die Kohision innerhalb einer Entwurfseinheit sollte hoch sein.
Das heißt, es sollte, also die Kohäsion bedeutet,
diese Art von Bindung untereinander.
Also die Methoden in einer Klasse sollten eine hohe Kohäsion aufweisen.
Und das, was in einer Methode steht,
sollte also in sich auch eine hohe Kuhäsion aufweisen.
So, jetzt kommt die eigentliche Definition Kopplung, was ist das,
bezeichnet den Grad der Abhängigkeiten zwischen den Einheiten eines Softwaresystems.
Was dieses Entwurfsprinzip anbetrifft, also wenn sie da mal hier hinschauen,
So kann ich auch hier zeigen, ist ja rechts unten.
So. Wenn Sie ein derart gekoppeltes System haben, stellt sich unmittelbar die Frage,
warum tun Sie das nicht alles in eine Klasse rein?
Wenn jeder jeden kennt, da braucht man die auch nicht mehr voneinander unterscheiden.
Man hängt alles mit allem zusammen und man kann diese Entwurfseinheiten
vielleicht noch getrennt voneinander übersetzen. Aber sonst,
wie will ich das Verständnis von diesem Ding hier erreichen,
ohne dass ich mir nicht alle anderen anschaue
Das geht gar nicht, weil die ja alle miteinander zusammenhängen,
muss ich sie auch alle betrachten, um jeden Einzelnen zu verstehen.
Dass er schwert, die Verständlichkeit eines Stück Softwares.
Und das ist ein Qualitätsmerkmal nach Maya.
Das ist wieder Wissenschaft, das darf man sagen. Umgekehrt,
da oben sehen Sie jetzt einen Entwurf, nein,
ich werde jetzt nicht behaupten, dass der toll ist,
mindestens kann man von ihm behaupten,
dass die Kopplung der Klassen untereinander geringer ist als in dem anderen Entwurf.
Möglicherweise hat aber dieser Entwurf, also nach einem anderen Kriterium ist er schlecht,
da könnte ein Bad Smell das werden wir gleich auch noch kennenlernen, beziehungsweise nächste Woche.
Dieser Entwurf könnte eine Godclass enthalten. Das ist so die Klasse,
die alles zusammenhält und die anderen,
so, jetzt muss ich aufpassen,
dass ich in der religiösen Metaphorik mich nicht zu weit aus dem Fenster lehne,
die alles bestimmt.
Das ist die Definition von Gottklasse. Und sowas wollen wir
in einem objektorientierten Entwurf Pflicht sehen. Das ist so die
Verantwortlichkeit in dieser Klasse dürfte zu hoch sein und die anderen,
die Satellitenklassen sind, haben da möglicherweise zu wenig Verantwortlichkeit.
So, zurück nochmal zu der, was Kopplung denn jetzt,
so wie man überhaupt Kopplung feststellt.
Wir können also Abhängigkeiten, die hier sind ja,
also unbestimmt, also Vererbungsbeziehungen werden es wohl nicht sein.
Das werden wohl im Wesentlichen benutzt, Beziehung sein.
Das ist die eine Art und Weise, Kopplung auszudrücken.
Die zweite Art Kopplung auszudrücken, die noch schärfer ist eigentlich.
Das sind die Vererbungsbeziehungen. So, und die wollen wir
uns jetzt nochmal anschauen, wie kriegen wir das hin,
eine möglichst lose Kopplung hinzubekommen.
Erstmal Nochmal so einführendes. Wir haben schon eine Art kennengelernt,
eine zyklische Benutztbeziehung zwischen zwei Klassen. Das ist ja eine
sehr starke Kopplung dann zwischen diesen beiden Klassen, die aufzulösen.
Und das Mittel, das wir verwendet haben, war das Beobachtermuster.
Da haben wir zwei Klassen, die stark miteinander gekoppelt war,
in einer Weise entkoppelt, in der Weise entkoppelt,
dass die Benutztbeziehung nur noch in einer Richtung war und
in der anderen Richtung durch den Beobachtungsmechanismus implementiert worden ist.
Das ist so die Richtungen, die diese ganze Diskussion jetzt geht,
starke Kopplung, vermeiden und Mechanismen finden, mit denen wir Klassen,
die voneinander in einer bestimmten Form abhängig sein müssen,
dass wir sie möglichst lose miteinander koppeln.
Zwei Arten von Kopplungen werden, sei es unterschieden,
sehen Sie hier explizite und implizite Kopplung.
Die explizite Kopplung ist die Kopplung, die zum Beispiel durch einen Compiler nachweisbar ist.
Klasse A, benutzt Klasse B, das heißt,
ist irgendeine Exemplarvariable vom Typ B in A definiert oder ein Parameter B in einer Methode von A,
so was von der, das kann ein Compiler sehen und sagen,
okay,
ich male jetzt mal so ein Klassendiagramm und dann sehe ich
diese Abhängigkeit
Weil das ist eine Art von Abhängigkeit,
die kann man also durch betrachten, kann man sie entdecken.
Und dann weiß ich, ich muss hier möglicherweise was tun.
Zum Beispiel, weil ich eine zyklische Abhängigkeit zwischen diesen beiden
Komponenten A und B habe, dann kann ich die auflösen.
Die Mittel dafür, also Beobachter, muss da irgendwas von der Art,
kommen gleich noch zu ein paar anderen Mitteln, stehen nutzt zur Verfügung.
Was viel, was ich auf der Zunge habe,
ist ekliger, was viel ekliger ist als die explizite Kopplung,
ist die implizite Kopplung.
Das ist nämlich die Kopplung, die sie in ein Programm
einbauen, die von einem Compiler nicht überprüfbar ist
Piller immer so statisch geprüfte, statisch getypte Programmiersprachen.
Um Ihnen da mal ein Beispiel zu geben, was implizite Kopplung,
was das sein kann, sehen Sie das hier?
Also da gibt es jemanden, der hat so einen Behälter
implementiert und dieser Behälter liefert auf Anforderungen aller Elemente,
die in ihm drin sind, in alphabetischer Reihenfolge.
Oh, das ist ja cool, denkt,
also der Klient und verlässt sich darauf.
Das ist aber nirgendwo spezifiziert, dass die Dinge von
diesem Behälter, also in einer alphabetischen Reihenfolge kommen
Das ist eine implizite Abhängigkeit, eine implizite Kopplung. Also jetzt nicht,
dass er den Behälter benutzt, sondern wie er den benutzt.
Das steht nirgendwo. So, dann liefert das jetzt und
der Klient verlässt sich da drauf. Und jetzt sind hier
ein paar Tage, Wochen, Monate ins Land gegangen.
Und ein neuer Mann kommt ins Team und schaut sich den
Behälter an und sagt, das geht ja gar nicht.
Wie der jetzt implementiert ist, der kennt natürlich den Klienten nicht.
Den Klienten kennt man ja nicht.
Das ist ja, man wird benutzt in diesem Programm
Der kann ja ganz woanders sitzen. Und reimplementiert diesen Behälter.
Und jetzt wird diese implizite Annahme, nämlich, dass da sortiert rauskommt,
wenn man sagt, gib mir mal das nächste Element,
diese implizite Annahme stimmt auf einmal nicht mehr.
Und dann, hier steht jetzt etwas, ein bisschen effekthaischerisch,
der Klient-Uncode zerbricht. Um Gottes Willen, Porzellan am Rechner.
Also, was das heißt, ist, die Annahmen,
unter der dieser, Behälter benutzt worden ist, diese Annahmen.
Also er weisen sich jetzt im Laufe der Zeit als falsch.
Formal ist hier überhaupt nichts passiert. Formal ist ja,
es wurde kein Vertrag verletzt. Und wenn man entgegen des Rates,
den ich, wir ihnen hier geben, das Vertragsmodell nicht eingesetzt hat,
um also diese Art von Spezifikation auch vertraglich explizit zu machen,
dann kann man also den Schuldigen für dieses Verhalten,
also der ist jetzt schwer auszumachen.
Also tendenziell würde ich schon den Klienten beschimpfen,
dass der sich auf etwas verlässt,
was vertraglich nicht zugelassen ist
Aber das sei mal jetzt genug als Beispiel für eine implizite Kopplung.
So, jetzt habe ich schon über das Vertragsmodell gesprochen und
jetzt sehen Sie da oben, sehen Sie so eine Aufforderung?
Wähle geeignete Schnittstellen. Ich hoffe,
dass jetzt bei dem einen oder anderen von Ihnen denkt,
ja, das ist ein super Hinweis,
den er uns da jetzt gibt.
Ich könnte Ihnen auch als Hinweis für die Softwareentwicklung geben,
denken Sie nach.
Oder machen Sie
keine Fehler
Jetzt habe ich Ihnen schon drei Hinweise gegeben, wie sie
gute Software entwickeln können. Und geeignete Schnittstellen wählen,
also das kann ich sogar noch genauer sagen, die sollen vollständig sein.
Aha, vollständig. Ihr Gegenüber, was denn? Was ist denn hier,
was ist denn das Maß, an dem ich jetzt messe,
ob etwas vollständig ist? Die sollten klar sein,
also trinken Sie keinen Federweißen, der ist trüb,
konsistent, na gut, das geht noch,
also weil wenn Sie so eine Schnittstelle von,
sagen wir mal, sieben Operationen haben,
dann sollten die vielleicht unabhängig voneinander sein, die Operationen oder die sollten,
also wir haben schon über Zuständigkeiten gesprochen, die sollten,
sie sich nicht widersprechen.
Minimal, super. Also man sollte so eine Methode nicht
zweimal haben oder so, ähnlich, Operationen implementieren.
Und das letzte, als letztes toll,
ich blicke wieder auf den Schaukelstuhl, bequem benutzbar.
Ja. Also sie sehen, ich kann, hier stehe ich,
kann ich anders, Gott sei mit mir armen.
Das sind jetzt so diese Kriterien, lassen sich nicht scharf formulieren.
Und das ist ein Teil der Krux, der der Softwareentwicklung. Wir können,
wir kommen jetzt im Laufe der Zeit, kommen wir dazu,
wie wir, also auch unter Einsatz von Metriken,
also feststellen können, ist ein Softwareentwurf, eine Implementation,
richtig komisch oder riecht sie erstmal gut?
Das, abgesehen, dass sie wissen, dass ich jetzt metaphorisch rede,
so weit kommt es, dass das auch noch anfängt zu riechen.
Wir werden uns so in Softwaretechnik, so kann ich Ihnen versprechen,
wir gucken uns, also Metrikenmaße mit also nicht,
also die Qualität von Software bestimmt werden kann, aber die Indikatoren dafür liefert,
dass ein Stück Software möglicherweise eine Verbesserungsfähige Qualität hat.
Und dann werden wir ihnen im zweiten Schritt beibringen,
wie kann man Werkzeuge über Listen, die anhand von Metriken feststellen,
dass eine Software ein bestimmtes Qualitätsmaß unterschreitet.
Und sie gehen hier nachher, also dann als Bachelor raus,
um vielleicht sogar als Master. Und das,
was ich Ihnen, das einzige, was ich Ihnen,
Leute, die hier auf dieser Seite des Plenums stehen,
zusichern kann, ist, Wir zeigen Ihnen alles,
also was wir wissen, und dann ist die Aufforderung,
machen Sie was draus.
Wahnsinn gute Software, das war jetzt schon der vierte Tipp-Folg für heute.
So, Konkretisierung, es geht natürlich ein bisschen konkreter.
Verwende Interfaces. Das ist nochmal bretthart umzusetzen. Also jede Klasse,
darüber hatten wir, glaube ich, auch schon mal gesprochen,
also es sollte nicht direkt verwendet werden, sondern eine Klasse sollte,
und das ist jetzt eine disziplinarische Herausforderung,
jede Klasse sollte über ein explizit gemachtes Interface in Java,
Wir sind ja jetzt hier bei Java als Implementierungssprache,
verwendet werden.
Schon allein das diszipliniert denjenigen, der diese Klasse implementiert,
dahingehend, dass er sich Gedanken darüber macht,
was gehört denn jetzt in das Interface hinein?
Und was, also ist das Zeug, was das Interface implementiert?
Also die Idee, ich muss mich davon lösen, möglicherweise implizites Wissen an der Schnittstelle bereitzustellen. Dafür ist also die Definition eines Interfaces oder dieses Sprachmittel-Interface ein absolut,
nicht nur absolut, sondern das geeignete Mittel,
um Solches implizites Wissen oder implizite Kopplungen zum Beispiel,
also nicht zu vermeiden, aber um sich selber auch darüber bewusst zu werden,
dass man möglicherweise so etwas eingebaut hat und sagt,
also Erich Gammer, hattest du ja auch auf den Punkt gebracht,
also man soll immer dann, also gegen eine Schnittstelle und nicht gegen eine Implementierung programmieren und Voraussetzung dafür ist halt, dass man erst mal Interfaces implementiert hat.
So, das Geheimnisprinzip,
als ich noch mal durch diese Folien vorbereitend gegangen bin,
habe ich gedacht, also so ein bisschen,
ich sollte hier keine die Griffe gebrauchen, die ich nicht definieren kann.
Also Paranoika sind, glaube ich, Leute,
die an Verfolgungswagen leiden. Das sagen wir mal so.
Das ist in medizinisch wahrscheinlich was anderes, aber sei es drum.
Das Geheimnisprinzip spielt bei Informatikern, bei Softwareentwicklern auch eine Rolle.
Man sollte so viel wie möglich verheimlichen.
Und wir werden doch so ein paar andere Grundsätze später kennenlernen.
Nur relevante, Achtung, wieder ein unscharfer Begriff,
relevante Merkmale einer Entwurfs- und Konstruktionseinheit sollten nach außen hin öffentlich gemacht werden.
Wir haben ja schon einiges darüber gehört, so was den
Unterschied zwischen Public Protected und Priva zwischen diesen unterschiedlichen Sichtbarkeitsregeln,
was das ausmacht. Man sollte also wissen über interner,
sollte man möglichst nicht nach außen hin verlagern,
weil das also die technischen Qualitätskriterien wie Wartbarkeit, Verständlichkeit in unzulässiger Weise verwässert.
Zyklen vermeiden. Ja, ich habe ein Beispiel des Entwurfs
mit einer maximalen Kopplung schon so ein bisschen drüber gesprochen.
Wir haben an anderer Stelle auch schon gesagt,
dass also insbesondere Fragen der Testbarkeit durch Zyklen stark beeinträchtigt werden.
So, hier wird jetzt nochmal hervorgerufen, hervorgehoben,
dass man in einem zyklischen Entwurf nicht feststellen kann,
also wo es einen offensichtlichen Einstiegspunkt, also für so eine Einarbeitung in diesen Entwurf gibt. Die Zyklen,
Vermeidungsmechanismen, die wir kennengelernt haben, haben sich bis jetzt,
also so im Wesentlichen darauf beschränkt, also den direkten,
unmittelbaren Zyklus, Zyklus zwischen zwei Entwurfseinheiten zu vermeiden,
viel unangenehmer und das ist das,
was in der Praxis leider Gottes immer noch häufig passiert und das,
was jedem von uns der Softwareprofessor entwickelt passiert ist, dass in größeren Einheiten, Zyklen, Innensoftware-Systeme eingebaut werden.
Und das ist zum Beispiel ein Albtraum, wenn es darum geht,
Teile von Software auf unterschiedlichen Rechnern laufen zu lassen.
Wenn man da so lange, wenn man große Zyklen hat,
also wird also die Frage der Verteilung entwickelt sich zu einem,
entwickelt sich zu einem Albtraum,
weil man also immer das ganze Stück im Zweifelsfall,
so im negativsten falschen Software,
sowohl auf einem Klienten als auf einem Server laufen lassen muss,
so was die Frage der Verteilung von Klein und Server
ja eigentlich ad absurde beführt.
Also Zyklen vermeiden
Gibt es im Übrigen auch Software-Werkzeuge, mit denen wir also überprüfen können,
ob solche Zyklen enthalten sind und dann haben wir das Mittel,
dann haben wir mindestens schon mal drin, wissen wir,
wo diese Zyklen sind und können Maßnahmen ergreifen,
um sie zu zerlegen, in eine hierarchische Beziehung zu bringen.
So, ein Mittel, um Zyklen,
also schon vom Design her, möglichst zu vermeiden, ist das,
was Sie hier auf der Ebene der SE2-Entwurfsregeln sehen und das,
was sich so im Werkzeugmaterialansatz, also aus dem Werkzeugmaterialansatz ergibt,
was sind so die, in Anführungsstrichen,
natürlichen Benutztbeziehungen zwischen den Entwurfseinheiten Und hier ist also,
hier wird ziemlich klar festgelegt,
also wer darf wen benutzen und allein aus dieser Orientierung wird also die Wahrscheinlichkeit minimiert, dass sich typische Beziehungen ergeben.
Und natürlich kann es also immer bald passieren, dass sie aus Versehen,
gerade bei den Materialien, dass die sich zyklisch,
dass die in zyklische Abhängigkeiten geraten, aber vom Prinzip her,
so wie das hier angelegt ist und so wie sie die Pakete strukturieren sollen,
ihrer Anwendung, die sie nach diesem Ansatz schreiben, wird also die Gefahr,
dass sie sich in dass sie sich in Zyklen verheddern, minimiert.
Das ist im Übrigen so als Design-Richtlinie geht das ja jetzt schon ein Stück weiter als das,
was zum Beispiel jetzt die Rebecca Werfsbrock mit, also ihren CRC-Karten, ihnen an die Hand gelegt hat. Sie sagt ja,
also CRC-Karten sagt ja nichts darüber aus,
also was sind so größere Orientierendere, orientierende Strukturen,
in denen sie ihre Software entwerfen können, sagt ja nur,
und das zeigt eigentlich so die Kompatibilität dieser beiden Ansätze,
Oder das, was wir sagen, naja,
wenn du jetzt ein Material entwerfen möchtest, dann kannst du diese Zuständigkeiten,
die dieses Material hat und die Kollaboration, sprich also die,
wer spielt da mit, um diese Dienstleistung,
Zuständigkeiten zu realisieren, dann verwende doch als Mittel die CRC-Karten,
um dir das mal zu vergegenständlichen.
Das ist also, das widerspricht sich nicht,
sondern das ergänzt sich an der Stelle. So, Fred,
ich werde noch das Demeter-Gesetz machen und dann machen wir hier den fliegenden Wechsel.
Das bin immer so ein bisschen skeptisch,
wenn die Leute mit griechischen Namen daherkommen.
Also wenn so Projekte heißen, Zeus. Oder auch gut
, Himalaya. So, drunter machen wir es nicht.
So, gleich so ein richtig, so ein Achttausender.
Demeter. Ich habe das nochmal nachgeguckt, soll die Göttin,
die griechische Göttin der Landwirtschaft sein. Und die Leute,
die das Law of Demeter aufgestellt haben,
haben die These vertreten oder die Sichtweise auf Softwareentwicklung,
die sie eingenommen haben, ist Software wird nicht gebaut.
Software wächst. Ist es nicht schön. Ja. So,
und es ist also in der, das kann,
das Wachstum kann eben auch ein Wildwuch sein, das wollen wir vermeiden.
Schon von denjenigen gesprochen, also die so das so im Geheimdienstgeschäft tätig sind,
die spielen bei dem Gesetz von Demeter auch eine Rolle.
Sprich nur mit deinen engsten Freunden. Also keine Fremden ansprechen.
Und das gilt auch für, das gilt auch für ihren Code.
So, was der tun darf, wen der ansprechen darf,
das sehen sie an diesen vier Punkten.
Also eine Methode M eines Objektes, oh,
darf nur Methoden von O selbst aufrufen.
Also alles, was in der Klasse drin ist
Sie erinnern sich so Zuständigkeiten. Ich darf nur Methoden aus
mir selbst aufrufen. Das ist ja schon mal was.
Wenn ich Parameter übergeben bekomme, dann darf ich auch,
also die Methoden der Objekte aufrufen, die mir als Parameter übergeben worden sind.
Das finde ich auch okay. Also es ist mir
schließlich übergeben worden. Von Objekten, die M erzeugt,
ja, das ist wohl klar.
Also wenn ich in einer Methode ein Objekt erzeuge,
dann werde ich Methoden dieses Objektes aufrufen dürfen.
Und von Exemplarvariablen, der mich umgebenden Klasse.
Das darf ich auch. Und sonst nichts.
Gar nichts
Wenn ich das nicht tue, wenn ich das lauer auf Demeter nicht kenne,
dann kann ich zum Beispiel zu sowas hier kommen.
Und das ist hohe Kopplung, at its best.
Also ganz schlecht. Weil wenn in diesem Objekt Geflecht,
jetzt was passiert, nämlich das, also sagen wir mal,
hier in der Klasse, so hierdurch eigentlich dereferenziert wird,
wenn sich da jemand in der Struktur was anderes überlegt,
dann bin ich drei benutzt Beziehungen weiter vorne gezwungen,
meinen Code zu ändern.
Das will ich nicht
Ich möchte nicht diese strikte Kopplung, diese enge Kopplung zwischen
den Benutztbeziehungen zwischen Klassen. Also mache ich was anderes.
Was mache ich? Das sehen Sie jetzt hier. Ja,
ich möchte nur noch einen Schritt weit jeweils zugreifen und sehen,
gucken Sie mal unter besser. Ich möchte die Schnittstelle bei dem Studenten,
möchte ich so gestalten und bei den nachfolgenden,
also in der Benutztbeziehung, tiefergehenden Klassen, dass die Dinger,
also mir eine in sich bündige Dienstleistungen anbieten.
Und nicht, dass ich mich als der letzte Klient darum
kümmern muss, wie wird diese Dienstleistung jetzt eigentlich erbracht?
Das will ich vermeiden. Und Sie sehen jetzt,
so gibt es extra drin gelassen, nicht einen Satelliten nach seinen Antriebsdüsen,
Fragen über eine Gat-Operation und dann eine Veranlassung über eine Set-Operation,
dass sie was machen soll, sondern das,
was sie, jetzt ich will nicht sagen eigentlich wollen,
aber die Dienstleistung, die dieser Satellit anbieten sollte,
ist doch,
richte dich neu aus
Tu was immer. Und ich sag höchstens noch,
in welche Richtung er sich neu ausrichten soll.
Und dann kann er den Song alleine tun,
indem er mit seinen Düsen so ein klein wenig rumspielt.
So, das hier ist auch so ein etwas,
ein Zitat in etwas deftigerer Sprache, dass den Gedanken,
den ich gerade ausgesprochen habe, nochmal vergegenständlichen soll.
So, dann würde ich sagen,
war für heute let's call it a day.
Und Fred übernimmt jetzt und er wird ihnen zeigen,
wie er aus einem schlechten Entwurf
einen guten macht
Schönes Wochenende. Okay. Also ich habe mal was für euch
vorbereitet. Ich programmiere immer ganz gerne so kleine Spiele.
Erstmal sehen, ob das irgendeiner von euch kennt, das Spiel.
Oh. Ich versuche es nochmal, dass mal irgendeine Situation entsteht,
wo man mal sinnvoll gewinnen kann, die Situation.
Tja, was mache ich denn jetzt?
Weiß jemand, wie das Spiel heißt
Meinst du mich? Weil das steht ja auch hier oben.
Gut. Okay, also Sinn dieses Spiels ist es eben
herauszufinden, wo die Bomben auf dem Spielfeld verteilt sind.
Hat das so mal eine schöne Situation. Und zwar,
das Spiel verrät mir jetzt schon Folgendes, überall,
wo das hier so etwas dunkler, blau ist, sind erstmal keine Bomben.
Und in der Nachbarschaft sind auch keine Bomben,
also wir fallen dann direkt drumherum. Aber jetzt hier,
wo so Einsen sind, das bedeutet,
es gibt in der Nachbarschaft jeweils eine Bombe,
also um dieses Feld ist eine Bombe irgendwo der Nachbarschaft,
hier auch, hier auch, hier auch.
Also hat jemand eine Ahnung, wo diese Bombe
wahrscheinlich liegen wird?
Hier, ne? Wahrscheinlich liegt da eine Bombe. Leider
kann ich das nicht markieren, soweit bin ich noch nicht.
Aber wir vermuten mal, dass ihr eine Bombe liebt.
Das heißt, hier kann keine Bombe liegen,
weil sonst würde ja hier zum Beispiel nur zwei angezeigt werden.
Da kann ich also gefahrlos raufklicken. Okay, und nach
dieser Logik muss man dann immer weitergehen. Ich glaube,
jetzt kommen wir hier nur noch mit Glück weiter.
Ist hier eine Bombe. Ich vermute mal, dass hier eine ist,
dann kann hier keine sein und hier auch nicht und da auch nicht.
Habe ich mich vertan. Okay. Gut,
ich glaube, wenn das Spielfeld ein bisschen größer ist,
dann entstehen ein paar mehr interessantere Situationen.
Okay. Und ja, jetzt steckt der ganze Quelltext in
einer einzigen Klasse drin
Weiß nicht, ob da bei euch jetzt schon so Alarmglocken läuten,
aber das ist ja vielleicht ein bisschen komisch,
dass ich da also nichts irgendwie großartig aufgeteilt habe.
Schauen Sie Kassel mal ganz kurz an. Erstmal ein paar Konstanten,
also wie groß soll das Spielfeld sein, wie viele Minen sollen
auf dem Spielfeld sein, das ist also die Anfängerstufe.
Dann so ein paar Swing-Konstanten, das ist einfach nur dafür da,
dass die Buttons nicht zu groß sind und dass sie vernünftige Farben haben und so weiter.
Ist jetzt nicht so wahnsinnig spannend. Dann kommt jetzt der
eigentliche Zustand des Spiels. Also ich merke mir hier einmal
in so einem zweidimensionalen Bulian Array, wo die Minen sind.
Also wenn ich das jetzt noch einmal spiele und absichtlich verliere,
Wenn man verlieren will, dann klopft es nicht.
Hier ist doch bestimmt einer in dir, du musst ja hier einer sein.
Genau, ne? Also dieses zweidimensionale RA merkt sich also,
dass hier keine Bombe ist, hier, also quasi Falls,
Fals, Fals, Fals, Fals, True,
Fals, Falls, Fals, Fals, Fals, Fals,
True, Fals, Fals, Fals und so weiter.
Also für jede Zelle in diesem Spielfeld einfach ein Booli,
ob da eine Bombe ist oder nicht.
Okay. Und dann eine tolle Variable namens Countdown,
die zählt offenbar runter, aber was zählt sie genau?
Sie zählt, wie viele Felder man noch freilegen muss,
damit man gewonnen hat. Also man kann das Spiel
auch gewinnen, glaubt es mir. Dann der J-Frame,
das kennt ihr ja von letzter Woche, also dieses Fenster hier,
jetzt sind wir also schon ein Gooi-Code. Oh Gott,
wir haben also schon irgendwie Fachlogik und Google-Code in derselben Klasse,
das ist ja schon mal irgendwie nicht so eine tolle Idee.
Na gut. Und dann haben wir ein,
zweidimensionales Array von Jay Buttons, weil ich ja eben auch
wirklich tatsächlich diese sichtbaren Buttons brauche in hellblau und dunkelblau
und ich kann raufklicken und es passiert was und so.
Mit Textbeschriftung drauf. Okay. Dann schließe ich das jetzt mal wieder.
Achso. Okay, dann haben wir einen Konstruktor.
Dann müssen diese ganzen Variablen in sinnvollen Anfangszustand gesetzt werden und ich bin schon total unruhig,
weil der Konstrukt ja gar nicht auf eine Bildschirmseite passt.
Na gut. Ja, hier werden diese ganzen Felder erstmal alle
auf False gesetzt. Das ist ja zum Glück der Standard in Java
, das muss ich nicht von Hand machen
Dann sorgt dieser Code dafür, dass zufällige Minen gesetzt werden.
Ja, dann könnt ihr euch mal in Ruhe
zu Hause angucken. Glaubt mir einfach, der Weg,
also zufällig in unserem Fall zehn Minen auf dem Spielfeld platziert.
Okay, dann wird ausgerechnet, wie viele Felder ich noch freilegen muss.
Ja, ich muss im Prinzip alle Felder,
die es gibt, freilegen, abgesehen von den bemiehten Feldern.
Ich muss also alle Felder, wo keine Minen frei sind,
die müssen sichtbar werden. Dann erzeuge ich meinen J-Frame,
kennt ihr von letzter Woche. Layout kennt ihr im Prinzip
, braucht man letzte Woche nochmal als Wiederholung.
Ein Gridlayout ist quasi so ein Schachbrett-Layout. Ich sage also,
wie hoch es sein soll, wie breit es sein soll,
jeweils in Anzahl Komponenten und dann wird das hoffentlich vernünftig ausgerichtet
Okay, dann erzeuge ich mir meinen Button-Array.
Ich brauche ja diese 64 Buttons, auch entsprechend zweidimensional.
Und jetzt kommt eine riesige Schleife, wo ich dieses Buttons-Array initialisiere. Okay,
ich laufe also durch alle Y-Werte, ich laufe durch alle X-Werte,
erzeuge mir diesen Button, setzt dann so ein paar Eigenschaften,
also welche Farbe soll er haben und bitte keinen extra Rand drumherum und so,
sonst würde das gar nicht auf dem Bildschirm passen,
das Spielfeld.
Wie groß soll das Ganze sein? Das habe ich oben
festgelegt, ich glaube 32 mal 32 Pixel oder so.
Na genau, das ist quasi diese Information. Okay,
jetzt kommt auch die Reaktion auf den Mausblick,
was ja eigentlich auch wieder in eine andere Klasse gehört,
ist jetzt ja auch in derselben Klasse
drin.
Ich habe jetzt keinen Action-Lister genommen, sondern einen Mauslösen,
aber der erlaubt es einem zwischen linker und rechter Maustaste zu unterscheiden.
Wenn wir später mal einbauen wollen, dass wir mit der rechten Maustaste
zum Beispiel so kleine Flaggen hinsetzen kann nach dem Motto,
ich glaube, dass hier eine Mine ist.
Das ist für größere Felder ganz hilfreich. Aber ist noch nicht eingebaut. Okay,
wenn also jemand hier mit der linken Maustaste klickt,
gucke ich erstmal, ob da eine Mine ist,
wenn da eine Mine ist, dann decke ich die ganzen Minen auf.
Das müsst ihr ihm jetzt auch einfach mal glauben.
Und ich habe jetzt mal hier geguckt, wir sind hier schon
in Spalte, 45. Also wir sind hier so in Einrückungsebene 11.
Das ist eine absolute Katastrophe. Ich bin also hier quasi,
ich bin in diesem Ifnen und das ist in dem Fonds,
in dem Fonds, in dem If,
in dem If, in dieser Methode,
dieser anonymen inneren Klasse,
dieser Vorschleife,
dieser Vorschleife des Konstruktors dieser Klasse
Also da kann man schon so eine Ahnung kriegen,
das ist wahrscheinlich nicht so schön, dieser Konstrukte.
Okay. Weil ich hier ja auch wahnsinnig viel machen muss.
Gut. Ja, nachdem ich also diese ganzen Minen aufgedeckt habe,
sage ich dem, ja, schade,
dass du es nicht geschafft hast, beende das Programm.
Ansonsten rufe ich eine Methode auf, die dafür sorgt,
dass so ein, ja, Spielfeld quasi outet,
dass diese eine Zelle aufgedeckt wird.
Schauen wir uns gleich an. Gut,
dann wird dieser Button, den ich gerade erzeugt habe,
samt seinem Listener in dieses 2D-Erry von Buttons
reingestopft und dann wird der Button auch dem Frame hinzugefügt
Jo. Okay, und dann kommt so ein bisschen ein
kleiner Radatsch, kennt ihr ja schon von letzter Woche.
Ich will ja auch mal was sehen und was soll passieren,
wenn ich Fenster schließe. Das ist alles nichts Neues.
Das ist vielleicht noch ganz neu. Ich wollte nicht,
dass jemand die Möglichkeit hat, das Fenster größer und kleiner zu machen.
Meistens sieht das bei so einem Mindscreeper einfach nicht toll aus.
Gut, dieses Clear, also nach dem Motto,
der Benutzer klickt irgendwo hin, wo keine Bombe ist.
Was soll dann passieren? Ja, das ist ja auch
schon wieder wahnsinnig viel. Okay. Kann mir
jemand erklären, wofür dieses IF gut ist?
Zeile 106. Was macht das IF?
Vielleicht bedeutet es auch, dass wir nur einiges entscheiden.
Genau, also ich prüfe erst mal, ob die X
und Y Koordinaten gültig sind. Das klingt erst mal komisch,
weil ich kann ja eigentlich nur gültige Felder anklicken.
Ich kann ja nicht außerhalb des Frames klicken, aber ihr werdet gleich sehen,
dass man die Methode auch in einem anderen Kontext aufrufen,
da muss man diese Überprüfung eben machen.
Okay, gut, jetzt hole ich mir den entsprechenden Button
an der Stelle, worauf geklickt wurde.
Und frage jetzt den Button, welcher Text steht auf dir drauf?
Und dann gucke ich, ob das der leere String ist.
Das heißt also, der Zustand,
ich starte das vorhin noch mal kurz,
also dieser Zustand,
dass hier zum Beispiel nur zwei steht und hier steht nichts
drin und hier werdet ihr gleich sehen,
steht etwas anderes drin
Also der eigentliche Spielzustand wird als Text einer Swing-Komponente gespeichert.
Kann mir irgendjemand sagen, warum das vielleicht nicht so gut ist?
Spielzustand in einem Button zu speichern. Ja. Richtig,
also ich koppel mich erst mal extrem an dieses Swing-Framework.
Ja. Man bedient sich mit den Briten. Das war
für die Bank eigentlich nur, das war eine Klodate,
die man bringt mit dem Mann auch weiter.
Wenn man anguckt und die macht, erfüllen. Er hat
dann gewählt. Er hat ein Bremen. Da kann man
weiter zu brechen. Ja, sehr schön. Also das war
sehr viel Wahrheit in dem, was du gesagt hast.
Und einfach nochmal grundsätzlich zusammengefasst, eine Oberfläche sollte den Zustand darstellen,
so wie er woanders in einer fachlichen Komponente gespeichert ist.
Und das ist eben auch deswegen wichtig. Stell dir zum Beispiel
mal vor, ich will das Spiel testen. Ja,
momentan wird das sowieso schwierig, weil ich nur diese eine Klasse habe.
Das würde ja bedeuten, ich müsste irgendwelche Button-Klicks simulieren.
Ja, und dann müsste ich irgendwie abfragen den Button,
hey, in welchem Zustand bist du gerade in einer Jailunit-Testklasse.
Und jedes Mal, wenn ihr diesen Test durchlaufen lasst,
ploppt auf einmal dieses Mind-Screeper-Fenster auf.
Das will man ja eigentlich auch nicht. Wenn ich einen Test durchlaufen lasse,
will ich einfach nur, du hast da zwei,
drei Sekunden rattet und das dann unten steht, alle Tests sind erfolgreich durchgelaufen.
Ich will nicht, dass da irgendwelche Swing-Fenster raufgehen.
Ja. Das war ja kein Benutzbarkeitstest oder irgendwas sein oder
wie schön sieht es aus, sondern einfach nur funktioniert es.
Ja. Also für die Testbarkeit ist es eine absolute Katastrophe,
Zustände in Buttons abzulegen. Okay, dann, ja,
jetzt wird es auch wieder ganz merkwürdig. Also,
wenn ich also festgestellt habe, der Text ist leer,
also nach dem Motto,
da hat vorher noch nie jemand draufgeklickt auf diesen Button,
dann melde ich erstmal
die Mauslüssender von Debatten ab
Ja, so nach dem Motto, es macht nur Sinn,
einmal pro Spiel auf einmal auf denselben Button zu klicken.
Ja, dann melde dich einfach mal die Listen ab.
Innerhalb dieser eigentlich fachlichen Clearmethode. Okay. Was mache ich als nächstes
? Als nächstes zähle ich die Nachbarn. Ich schaue mir
also an, hole mir die Koordinaten mal beispielhaft durchgehen.
Y minus 1 heißt ja einen über mir und x
minus 1 heißt ja nach links.
Ich scharte das mal ganz kurz, dass ihr es seht.
Also wenn ich jetzt quasi, was ich hier hinklicke,
dann ist Y 1, x minus 1 ist dann hier.
Y minus 1, x ist hier, y minus 1,
x plus 1 ist hier,
Y x minus 1 ist hier,
Y x x 1
ist hier
Plus 1, x minus 1 ist hier und
das ist da und beide plus 1 ist hier.
Also diese acht Positionen frage ich einfach jeweils, hey,
ist da eine Mine? Und wenn da eine Mine ist,
dann zähle ich meinen Zehler hoch. Und dann habe ich
am Ende eine Zahl zwischen 0 und 8. Okay, eigentlich ganz einfach.
Das ist nur die Falsche, dass hier reingehört.
Gut. Wenn da jetzt also mindestens eine Mine in der Nachbarschaft ist,
dann wandere ich diesen Int in einen String um und sage den Button,
jetzt zeig doch mal die Sitzer halt an.
Das führt also dazu, dass ihr wirklich Zahlen seht.
Ja, wenn ich keinen Pech habe
Ja, hier zum Beispiel. Diese zwei entsteht also dadurch,
dass dieses N, was am Anfang null war,
da sind also zwei Ifs, wir haben Facebook halt,
ja, da ist eine Mine,
zwei ist größer als null und dann wurden diese zwei in den String,
zwei umgewandelt und als Text bei den Button gesetzt.
Ja. Okay. Und ja, wenn es jetzt keine Nachbarn gab,
dann wird jetzt hier der String reingesetzt, der nur aus einer Leertaste besteht.
Ja, so unterscheide ich also, handelt es sich um
einen Button, wo ich noch nie raufgeklickt habe.
Ja, ich will mal kurz diese offenen,
jetzt sind wir diese Vorwürfe, ich mache da einfach mal,
dass da nur eine Miete ist.
Also dieser Button, wo ich noch nie raufgeklickt habe,
hat den leeren String und dieser Button,
wo ich schon mal raufgeklickt habe,
hat den String,
der aus einer Leertaste besteht,
ist nicht dasselbe
Ja. Ziemlich dahin gehackt. Okay,
das ist auch noch eine schönere Farbe bekommen,
dass man das auch hauptisch ein bisschen sieht.
Was ist denn das hier? Ja,
man sucht sich so rekursiv durch dieses ganze Spielfeld durch,
damit man nicht ganz oft klicken muss.
Kann ich das auch nochmal demonstrieren? Ja,
hier zum Beispiel. Also ich habe hier raufgeklickt.
Es wurde festgestellt, dass nirgendwo in der Gemominen sind
Und wenn ich jetzt nur dieses Feld freigelegt hätte,
dann hätte ich jetzt als Spieler gesagt, Moment mal,
also wenn hier keine Minen in der Umgebung sind,
dann kann ich eigentlich gefahrlos hier raufklicken und hier raufklicken und hier und hier und hier.
Ja, und das macht einfach keinen Spaß, das selber denken
zu müssen. Also macht das der Computer von alleine.
Immer wenn es keine Minen in direkter Umgebung gibt,
mache ich halt diese vier rekursiven Aufrufe.
Okay. Gut, dann wird dieses Countdown um einen runtergezählt.
Also ich bin ja gerade in dem IF,
was geprüft hat, ob ich noch nie darauf geklickt habe.
Genau, das heißt also, ich habe also ein weiteres Feld freigelegt.
Und wenn ich dann bei Null angekommen bin,
dann sage ich dem Spieler, dass er gewonnen hat.
Und hier fehlt auch noch, dass dann das System
beendet wird,
fällt mir gerade auf
Möglicherweise habe ich das nie so weit getestet,
dass ich wirklich mal gewonnen habe. Okay. Ja,
da sind auch eine riesige Methode, einigermaßen. Gut,
dann gibt es ja noch so ein paar Hilfsmethoden.
Dieses ist mein Ad, was ja quasi hier aufgerufen wurde.
Das muss ja auch damit umgehen, dass man vielleicht unsinnige Koordinaten abfragt.
Also wenn ich jetzt zum Beispiel hier raufklicke,
dann gibt es ja nur fünf Nachbarn und diese drei Nachbarn hier oben,
die gibt es ja in dem Sinne gar nicht.
Ich will aber nicht, dass das Programm abstürzt,
nur weil ich die Frage stelle, ob da eine Mine ist.
Also gibt es diese Hilfsmethode, die auch erstmal wieder prüft,
ob es die Koordinate überhaupt gibt.
Und nur wenn es die Koordinate gibt,
wird auch noch zusätzlich überprüft,
ob eine Mine in diesem Feld
drin ist
Sonst müsste ich diese Bedingungen quasi, ich meine,
da müsste ich sonst vier, acht Mal reinkopieren.
Hätte ich vielleicht machen sollen. Dann wäre es noch offensichtlicher
gewesen, wie hässlich es ist. Okay. So,
dann haben wir hier die Mail-Methode, auch in derselben Klasse drin.
Auch nicht so schön. Und hier wird etwas gemacht,
was ich letzte Woche ja leider keine Zeit mehr dazu hatte.
Und dazu habe ich nochmal ein Bild mitgebracht.
Das seht ihr immer in allen Projekten,
die irgendwie Swing-Projekte in einer Main-Methode starten.
Dazu habe ich mal dieses Bild mitgebracht. Kann ich das
mal irgendwie ein Vollbild machen? Fünf vielleicht? Nee,
S11? Nee,
auch nicht
Gibt es das hier nicht in ein Vollbild?
Doch, F11. Hä, komisch. Okay,
stellt euch vor, Swing ist eine Küche und jedes Mal,
wenn da Knöpfe gedrückt werden oder irgendwas,
ist das analog in der Küche jemand bereitet,
irgendwie eine Mahlzeit zu oder fuchtelt mit seinen Messern rum oder so.
Und jetzt stellt euch vor, diese Main-Methode ist,
keine Ahnung, der Manager von dem Restaurant oder so.
Und er will jetzt irgendwie das erste Gericht fertig haben.
Jetzt hat er zwei Möglichkeiten. Entweder macht er das selber.
Ja, dann würde ich einfach direkt in Main reinschreiben.
New UI-Komponente irgendwas oder wie heißt das? Ja,
in dem Fall ist er so, ist er sogar dieselbe Klasse.
Aber ich würde direkt dieses Objekt einfach erzeugen und sagen,
mach dich mal sichtbar und so weiter
Jetzt, wenn Manager und Küche reingeht, wo man mit Messern rumgefuchtelt,
wird das wahrscheinlich nicht so eine gute Idee.
Was also der Manager stattdessen macht,
ist, er schreibt auf so einen Zettel,
was er haben will und tut den Zettel in so eine,
ja, Q rein von Dingen, die gemacht werden sollen.
Also möglicherweise ist das hier vielleicht das, was zuerst gemacht
wird und dann hängt er das vielleicht hier rechts an.
Und die Chefs immer, wenn sie die Zeit haben,
ziehen sich dann so einen Auftrag aus der Queue und bearbeiten das.
Und das ist genau das, was wir auch machen müsst,
wenn ihr in dieser Main-Methode seid. Ihr müsst also sagen,
liebe Küche, ich habe meinen Auftrag für dich, führe,
weil diesen Auftrag irgendwann später aus, wenn du Zeit hast.
Und der Auftrag ist dieses Objekt. Das ist wie so
ein Zettel. Dieses, was ich jetzt hier markiert habe,
ist einer dieser Zettel, die da hängen,
ein Runable, also etwas,
was man ausführen kann
Okay, und dann könnt ihr in dieser Run-Methode,
das ist die einzige Methode in dem Interface,
könnt ihr dann reinschreiben, was passieren soll.
Und in diesem Fall ist das eigentlich Interessante, dass ich hier
ein Objekt von mir selbst erzeuge. Und in diesem Konstrukt,
da passieren eben ganz viele Swing-Dinge, nochmal zur Erinnerung,
hier wird ein J-Frame erzeugt, da werden Buttons erzeugt,
die Buttons werden dem J-Frame hinzugefügt und so weiter.
Das alles darf nur innerhalb der Küche passieren von geschulten Fachkräften.
Der Manager darf das nicht selber machen, okay?
Gut, und das hat noch damit zu tun.
Und ich hatte meinen Sweeper, einem Freund geschickt,
der einen Mac benutzt und komischerweise hat das dann mit
den Farben der Buttons und so alles überhaupt nicht funktioniert.
Und da habe ich gelesen, man muss dem Mac also sagen,
bitte zeig dich nicht mac-artig an auf der Oberfläche,
sondern generisch und hässlich.
Und dann sieht man zumindest die verschiedenen Farben
Okay, das als so ein kleiner Überblick,
wo ist eigentlich mein Zettel, den ich mir extra,
da ist so? Gut versteckt. Dass also,
ja, weil das Projekt auch ein bisschen größer geworden ist,
als ich eigentlich dachte, habe ich mal notfalls diesen Zettel mitgebracht.
Vielleicht schaffe ich es aber auch ohne den Zettel.
Gut, was macht man jetzt? Also um sowas zu
entzerren? Also erstmal braucht man natürlich eine Motivation dafür,
wenn man jetzt sagen würde, das Spiel ist fertig,
wir müssen es nie wieder anfassen,
dann würde ich es so lassen, es wäre Geldverschwendung,
den Code zu ändern.
Aber ich hatte jetzt ja schon gesagt,
einmal hatte ich eine Anforderung für mich,
ich will das Ding testbar machen
Also ich hatte tatsächlich am Anfang mal, es hat relativ lange gedauert,
bis ich das hinbekommen habe, dass dieser rekrusive Prozess funktioniert hat.
Ja, das hat schon vielleicht eine Stunde oder so gedauert,
dass das nach meiner Meinung fehlerfrei war.
Ich hoffe, dass es mittlerweile fehlerfrei ist.
Ich weiß es nicht. Ich habe ja keinen Test.
Also ich würde gerne alleine das System schon aus dem Grund auseinanderzerren in verschiedene Komponenten,
dass ich das besser testen kann, dass ich wirklich sicher sein kann,
dass meinem Kunden nicht irgendwelcher Spezialfälle auf die Füße fallen.
Einmal deswegen. Dann, das war eigentlich ganz nett,
dass das eben passiert ist. Vielleicht passiert es jetzt wieder nicht.
Wenn man dann beim ersten Mal auf eine Bombe klickt,
dann ist jetzt passiert es nicht.
Wenn man beim ersten Mal auf eine Bombe klickt, Okay,
also nehmen wir an, das ist der erste Klick oder das.
So, oder der hier. Oder hier. Hier. Wo sind
die Bomben? So, also unter Windows ist es so,
wenn ich das allererste Mal klicke und es ist sofort eine Bombe,
dann wird intern das Spielfeld nochmal neu gemischt.
Diese Logik will ich jetzt in diese 170 Zeilen eigentlich auch
nicht nochmal zusätzlich einbauen. Dass wir also auch eine neue Fachlöcheranforderung.
Da würde ich gerne erstmal das System aufräumen,
bevor ich diese neu fachliche Anforderung da reinbringe.
Oder zum Beispiel, ich würde gerne sagen,
ach jetzt passiert es wieder,
wenn ich es nicht brauche
So, hier zum Beispiel. Also wenn ich jetzt zum Beispiel der Annahme wäre,
es gibt jetzt keinen Grund dafür, dass hier zum Beispiel,
ich glaube, dass hier eine Bombe ist,
dann würde ich gerne mit der rechten Haustaste aufklicken und dann sollte da irgendwas passieren.
Vielleicht eine Flagge erscheinen oder es sollte orange sein oder was weiß ich.
Auch eine weitere Anforderung. Ich will das nicht auch
noch zusätzlich in diese 170 Zahlen reinmachen. Also ich will
das System irgendwie erweitern, aber ich habe den Eindruck,
im aktuellen Zustand wird das nicht so schön.
Gut, also das reicht mir eigentlich als Motivation.
Dann habe ich mir so ein paar Gedanken gemacht,
wie man das Ganze aufbauen kann und habe hier mal so ein Diagramm gemacht.
Ich habe das mal vorsichtshalber als Screenshot gemacht, weil man
ja nie weiß, ob nicht zwischendurch mal irgendwas abstürzt.
Ich hatte hier diverse Nightpointer Acceptions in dem Programm.
Okay, also ich habe mir das mal so vorgestellt
Es ist immer ganz nett, wenn das Main in einer eigenen Startup-Klasse steht.
Dann, wenn man so ein Projekt öffnet als Programmierer,
weiß man sofort, wo man suchen muss,
um zu wissen, wie starte ich überhaupt das ganze Projekt.
Das ist bei uns immer so eine Startup-Klasse.
Ihr könnt ja auch Main nennen oder so.
Weiß nicht, ob man es Main oder Startup.
Das soll also nur die Main-Methode drin sein, sonst nichts.
Habe ich schon mal die 20 Zahlen-Code in der eigenen Klasse verfrachtet.
Okay, dann würde ich jetzt mal bei diesem Interface hier vielleicht weitermachen.
Hallo, kann ich das nicht Vollbild haben und mit der Maus gleichzeitig?
Doch. Habe ich mir überlegt, ich will einmal die Tatsache,
welche Miene es gibt oder wo diese Minen sind,
dafür will ich irgendwie eigene Typen bauen.
Am Anfang sollte es erstmal nur ein Typ sein,
random Mindfield, wo also genauso zufällig
diese Minen verteilt sind
Aber man kann sich vielleicht schon vorstellen, ein Random-Mindfield ist zum Testen eher ungünstig.
Beim Testen sage ich ja, irgendwie befindet sich das Spiel
für den folgenden Zustand. Also wird in der Ecke,
hier oben ist eine Mine und dann nochmal zwei Felder weiter rechts.
Und wenn ich in die Mitte klicke,
erwarte ich das anschließendes Spielfeld so aussieht oder so.
Also für eine spätere Version würde ich mir vorstellen,
man hat hier vielleicht auch noch einen D-Terministic-Mindfield oder irgendwelche Mindfields,
die immer genau in den Ecken was haben oder so.
Ich könnte mir also, beliebig viele Untertümen dafür vorstellen,
mindestens zwei brauche ich, einen für einen Testen,
einen für das eigentliche Spiel.
Wir werden nur den für das eigentliche Spiel bauen,
einfach weil die Zeit nicht reicht.
Das heißt, es ist auf jeden Fall sinnvoll, erstmal ein Interface zu definieren.
Wie kann ich mit so einem Mainfield umgehen? Ich kann fragen,
wie hoch ist es, wie breit ist es?
Wie viele Minen sind insgesamt auf dir drauf?
Ist folgende Koordinatenangabe gültig? Also gibt es folgende Koordinate?
Das werden wir hier später brauchen. Ist an einer bestimmten
Koordinate eine Mine. Und auch zum Beispiel diese Funktionalität,
die Nachbarn zu zählen, warum sollte das irgendein Klient vom Außen machen?
Das ist ja eigentlich, passt doch einem perfekt in dieses Mainfield rein.
Also immer, wenn ihr solche Thema auseinander zerrt,
stellt euch die Frage, wo gehört eigentlich jetzt diese Methode rein,
stecke ich sie hier rein, stecke ich sie da rein?
Welche Klasse kann diese Frage eigentlich am besten beantworten?
Habe ich festgestellt, das passt hier einfach ganz gut frei.
Okay, das ist aber nur die Information,
wo die Minen sind, was eine relativ statische Angelegenheit,
wenn die das einmal erzeugt,
wird sich das
nicht mehr ändern
Und dann das Playfield,
wo jetzt Zahlen drauf dargestellt werden und verschiedene,
die Schattierung nicht, aber sozusagen das Playfield weiß,
wo wurde denn schon mal eine Zelle quasi geöffnet oder reingeschaut oder geprüft,
wie viele Nachbarn hat sie oder so.
Diese Informationen werden in diesem Playfield abgelegt. Und das Playfield
kriegt dann den Konstruktor ein Mindfield rein. Ja,
das geht so ein bisschen in die Richtung, Dependency Injection,
da wird Guido nächste Woche noch was zu sagen.
Also das Playfield erzeugt sich nicht selber, sein Mindfield,
sondern ich kann es in den Konstruktor reinstecken.
Das heißt, ich kann dem Playfield sagen,
jetzt arbeite mal mit diesem Random Mindfield und im Test kann ich sagen,
jetzt arbeite mal mit diesem Deterministic Mindfield oder mit diesem Corner Mindfield oder was auch immer.
Okay, jetzt kann ich ja genauso gut wieder fahren
wie hoch und bereit ist es,
könnt ihr schon vorstellen,
dass das einfach nur delegiert an diese Methoden
Ich kann fragen, ja, was für eine Art von Zelle
befindet sich an einer bestimmten Position und dafür habe ich mir überlegt,
könnten wir uns einen eigenen Typen definieren,
weil da gibt es gar nicht so viele Möglichkeiten.
Welche Möglichkeiten gibt es da? Entweder ich weiß nicht,
was es für eine Zelle ist,
ich habe noch nie raufgeklickt oder es sind ja überhaupt keine Nachbarn in
der Nähe oder es sind irgendwie ein bis acht Nachbarn in der Nähe oder ich weiß,
dass da eine Bombe drauf ist.
Einfach weil ich verloren habe oder weil das Spielfeld oder weil
das Spiel vorbei ist. Da konnte man sich einen eigenen
Typen vordefinieren, das machen wir gleich mal. Okay,
und das ist diese Operation, die dafür sorgt,
dass man eine Zelle aufdeckt,
die wird später aufgerufen,
wenn er mit uns
irgendwo aufklickt
Okay, und dann musste ich dieses Playfield noch merken,
in welchem Zustand befindet sich das Spiel eigentlich gerade?
Das hatten wir schon mal bei dem TikTok-Toe. Das war auch irgendwie blöd,
da haben wir einfach einen Info genommen. Wir haben gesagt,
der Zustand ist eins, wenn Spieler eins gewonnen hat,
der Zustand ist zwei, wenn Spieler zwei gewonnen hat.
Der Zustand ist null, wenn unentschieden ist und minus eins,
wenn das Spiel noch läuft.
Das ist nicht besonders selbstdokumentierend. Also ein eigener Datentyp,
der einfach sagt, es gibt folgende Werte,
gibt es für GameState, wie vielleicht drei verschiedene.
Und du kannst da nicht aus Versehen den Zustand eine Million oder so haben.
Eine Int hatte irgendwie Milliarden von verschiedenen möglichen Werten
und viele davon wären gar nicht sinnvoll in diesem Zusammenhang.
Und ich habe jetzt mal diese Klasse nicht umbenannt,
vielleicht wurde man hier noch UI oder irgendwas hinterpacken.
Hier soll dann die ganze Swing-Logik rein.
Ich habe jetzt für diese Vorlesung darauf verzichtet,
nochmal zu entzerren, das Layout und die Action-Listen da.
Ich habe das jetzt hier in dieselbe Klasse gepackt.
Das könnt ihr dann zu Hause machen,
wenn ihr nochmal ein bisschen Lust habt, dahin rumzuspielen.
Okay, das behalten wir mal im Hintergrund. Jetzt fragen
wir es mal, womit fangen wir denn mal an?
Hm. Vielleicht fangen wir mal mit diesem Mindfield an.
Das ist ein Interface, da kann ich das eigentlich relativ
stumpf einfach übernehmen, das, was ich hier geschrieben habe.
Dann schiebe ich das nochmal. Kann ich da ranzoomen,
aber das geht zum Glück
So, dann bauen wir doch vielleicht erstmal dieses Interface.
Wir haben schon wieder nur noch eine halbe Stunde,
das wird lustig. Ich werde das nächste Woche fortführen müssen.
Ich glaube, da führt kein Weg dran vorbei.
Okay, also ein neues Interface. Ein Feld.
Mal sehen, wie schnell wir das hinkriegen.
Das wäre eine höhe Bräute
Das ist die gültige Koordinate. Ich verwende übrigens immer erst
das Y und dann das X, weil das bei den RAS auch so ist.
Und ich bin immer furchtbar durcheinander gekommen,
wenn ich das mal so und mal so gemacht habe.
Ich weiß nicht, wen das hier gegen den Strich geht,
könnt ihr dann refactern und anders machen.
So, und diese Methode soll die Nachbarn zählen.
An einer bestimmten Position. Okay, das ist das Interface.
Ich weiß nicht, wo die leer taste herkommt, weg damit.
Und dann könnten wir das Interface eigentlich mal implementieren.
Das hatte ich ja hier unten. Eine Implementation,
wo natürlich diese ganzen Operationen und Methoden realisiert sind und Zufälle,
zusätzlich brauchen wir noch Konstrukturen.
Momentan ist es so, dass diese Minenfelder immer quadratisch sind.
Also will ich auch weiterhin die Möglichkeit anbieten im Klienten,
du kannst es irgendwie quadratisch, sag mal,
irgendwie acht oder zehn oder zwölf oder was auch immer.
Aber es gibt in höheren Schwierigkeitsstufen auch nicht quadratische Felder.
Deswegen dachte ich, dann bauen wir das mal gleich so,
dass man höher und breiter grundsätzlich eigentlich voneinander unterscheiden kann,
auch wenn sie manchmal dieselben sind.
Okay, neue Klasse. Random. Mindfield. Da haben
wir sie. Die implementiert, das Interview mal entfiehlt.
So, okay. Welchen Zustand brauchen wir jetzt da drin?
Ich mache nochmal hier Vollbild, wir gehen nochmal in unsere
Hauptklasse rein,
das schließe ich mal
Also, wir gucken jetzt uns hier einfach mal die Zustandsvariablen
an und überlegen mal, welche von denen wären sinnvoll,
aufgehoben in dem Random Mindfield.
Es sind ja hier nur vier Stück, die es überhaupt gibt.
Das hier oben sind ja alles irgendwelche interessanten Konstanten und Google-Kram,
das wird es garantiert nicht sein.
Also, wir müssen uns die Frage nicht hierbei stellen,
hier, hier und hier. Fangen wir mal unten an.
Wollen wir die Buttons reintun ins Mindfield? Ist keiner dafür,
oder? Den J-Frame, auch nicht. Den Countdown,
also die Information, wie viele Minen ich noch freilegen muss.
Wir schauen uns nochmal ganz kurz hier
diese Grafik an
Um diese Zuständigkeiten festlegen. Also in einem Mindfield
wird ja einfach nur gesagt, wo sind die Minen?
Das ist komplett statisch und es gibt überhaupt keine verändernden Operationen hier drin.
Und die Frage, welche Felder jetzt aufgedeckt sind und welche
nicht, sind ja in dieser Playfield-Klasse.
Also, soll ich das Countdown in das Mindfield mit reintun?
Schüttelt einfach mal die Köpfe oder nickt?
Wenn die meisten schütteln, das ist richtig. Ja,
dann wird es ja wohl diese Variable sein, oder?
Sonst hätten wir komplette Zustandslosigkeit. Also dann nehme ich immer hier raus.
Ja, ich mache es erstmal mit Steuerung C,
das ist nicht zu viel gleich rot wird und tue es mal hier rein.
Okay. Sehr schön. Und auch dann schreiben nochmal
die Konstruktoren,
Machen wir hier den Konstruktor, der eine Höhe und
eine Breite entgegennimmt und einen Number of Mainz.
So. Jetzt müsste man das natürlich alles checken,
mache ich aus Zeitmangel alles nicht.
Also es muss ja sicherlich mindestens eins sein, mindestens eins.
Es dürfen nicht mehr Minen reingesteckt werden,
also was aufs Spielfeld passen und es kriegt nur eine nette Endlosschleife.
Das macht ihr dann wieder alles zu Hause. Okay,
kann man sich da Code dreimal piepen, reicht hoffentlich.
Viermal. Ciao. Ja. Gut
Das ist, glaube ich, der Code von hier bis...
Bis hier, würde ich sagen, oder? Das ist der Code,
der sich dafür kümmert, die Minen zu setzen.
Den tue ich jetzt einfach mal hier rein.
So, was muss ich jetzt anders anpassen?
Das heißt, gibt es natürlich nicht mehr, ne?
Hier muss ich jetzt die Höhe reintun und hier muss die Breite rein.
Okay. Dann, das ist nicht mehr diese Klassenkonstante,
sondern das ist jetzt der Parameter.
Okay. Das Y ist eine zufällige Zahl, kleiner als Höhe
und das X ist eine zufällige Zeit kleiner als Breite.
Das war ja einigermaßen einfach. Dann schreiben wir noch mal
den zweiten Konstruktor. Wer eine Größe entgegennimmt und eine Number
of Mainz für den quadratischen Fall. Dann kann der Klient
einen Parameter weniger übergeben. Das ist vielleicht ganz nett.
Wie rufe ich denn jetzt hier raus, diesen Konstruktor auf?
Das will ich jetzt ja quasi tun. Ich will ja
diese Size an Haid zuweisen. Das heißt,
eine With und dieser Parameter kann dann diesen Parameter.
Wie rufe ich aus einem Konstrukt deinen anderen Konstrukt auf aus
derselben Klasse?
Ich glaube, das geht nie in Java.
Nee, auch in Java 7 geht es noch nicht.
Hat jemand einen anderen Vorschlag, was sich da stattdessen reinschreiben?
Ja. This, genau. Ganz merkwürdige Sache. Hat man
sich irgendwann zu entschieden, die sonntags ist irgendwie cool.
Dann machen wir das so. Gut. Haben wir das
auch gemacht. So, jetzt natürlich die ganzen Methoden,
da steht noch nichts Sinnvolles drin.
Halt. Wie hoch ist das Spielfeld?
Also die einzige Exemplarvariable, ich habe jetzt dieses Mindfield.
Das hatte nun mal eine gewisse Höhe und auch eine gewisse Breite.
Wie kann ich da denn rankommen? Also wie kann ich
diesem Eric sagen, sag mir doch mal,
wie hoch du bist,
sag mir
einen Vorschlag
Also unterstrich, wie heißt sie? Mein Field? Da
ist sie. Wie kann ich jetzt dieses RAI fragen?
Dieses zweidimensionale Arry, wie hoch bist du? Alle,
die fragen aus SE1-Klausur vergessen, das geht mit längs.
Okay. Ja, und wie kann ich
die Breite feststellen?
Genau, ne? Ich gehe also in die oberste Zeile
und frage, wie lang ist die oberste Zeile?
Das würde mit allen anderen Zahlen auch gehen, falls er rechteckig ist.
In diesem Fall nehme ich einfach mal diese Einfachheit halber.
Okay, oh, number of mines. Ich glaube,
das muss ich mir zusätzlich speichern. Ich meine,
ich könnte jetzt natürlich jedes Mal durch das Eric durchschaffen und zählen,
das ist mir aber ehrlich gesagt zu blöd, ich speichere mir das lieber.
Das weiß ich dann, ups, einfach mal zu.
So, ne? So, dann kann ich das
unten zurückgeben.
So, dann die Frage, ob es die Koordinate YX gibt.
Hat da jemand einen Vorschlag, wie ich das prüfen kann?
Ich weiß ja, wie hoch es ist,
ich weiß ja, wie breit es ist.
Ja. Ja. Genau. Sehr schön. Ich glaube,
unsere Quelltextformenzung sagen, dass man das irgendwie klammern muss.
Ich mache das jetzt einfach mal,
auch wenn ich mich ja nicht immer in unsere eigene Quelltextformation
hier halte,
aus Zeitgründen
Hier finde ich das tatsächlich ganz nett.
Das sieht einfach irgendwie ein bisschen einfacher zu lesen aus.
Okay. Was haben wir noch? Ja. Ist eine
Mine an einer bestimmten Stelle. Was mache ich da?
Ja, sonst noch keiner, eine Idee, okay?
Genau, wir müssen erst mal prüfen, ob sie Goethe ist.
Also gibt es das überhaupt? Ja. Ach,
nicht Mainfield, Mainfield,
Sehr schön. Okay, ah, wir sind schon fast fertig.
Diesen Countneyer-Scode klaue ich mir mal wieder hier raus, den finde ich,
glaube ich, recht schnell, der ist so hässlich.
Hier ist er. So. So, oder? Dass ich ganz ehrlich,
dass die Methode, habe ich ja gerade geschrieben, ja, cool.
Ich glaube, dann sind wir damit schon fertig,
das freut mich. Dann gehen wir wieder zurück auf
unser Bild und schauen mal, wie weit wir sind.
Also wir haben dieses Interface geschrieben, Wir haben die Random-Implementation dazu geschrieben.
Dann würde ich jetzt sagen, als nächstes schreiben wir das Playfield.
Exemplar war ja, dann machen wir uns gleich noch Gedanken drum.
Wir könnten im Prinzip schon mal, vielleicht diese ganzen Methodenbräume reinschreiben.
Ups, haben wir so eine kleine Orientierung.
Das ist schon mal ganz nett. Also, Playfield.
Gut, was will ich alles haben?
Also, ich kann es gar nicht lesen,
es ist zu klein
Ich brauche einen Konstruktor, wie immer. Es wird ein Mainfield
reingestellt. Ach, Java-Sonntags. So, ne? Und
dann werde ich irgendwas Sinnvolles damit tun, mache ich später.
Die Höhe. Mache ich später deprite mal später.
Was haben wir noch? Cell at... Ach,
da, was soll jetzt dieser neue Typ werden?
Das machen wir gleich. Cell at in Y in X.
Was haben wir noch?
Saum. Und Game State, muss man auch noch schreiben.
Okay, dann würde ich mal sagen, bauen wir mal dieses Cell.
Welche, in welchen Zuständen kann sich sowas,
wir spielen das noch mal ganz kurz,
dass es nicht so aus der Luft gegriffen wirkt.
Gut, dass sich das noch in einer spielbaren Zustand
sich befindet, genau. Also es könnte sein,
dass sich eigentlich gar nichts, ja weiß darüber,
was das für eine Zelle ist,
weil ich einfach
noch nie raufgeklickt habe
Also ich nenne das einfach mal Unknown.
Ja. Ja, Walsman, da ist es.
Nee, da ist es nicht, hier ist es.
Dann könnte es sein, ja, dass da eine Bombe ist.
Immer wenn man es nicht braucht. Okay. So,
dann könnte es sein, dass es eine der Zahlen von
1 bis 8 ist. Mal so ganz lapidar 1 bis 8.
Und was könnte es noch sein? Ja,
aber null wird halt so besonders dargestellt,
deswegen wollte ich das anders nennen
Ja, hier, dieses. Ich habe das einfach mal Open genannt,
weil das wie so ein offenes Feld irgendwie wirkt.
Das hätte aber genauso gut Zero oder MT oder irgendwas.
Ich habe es einfach mal Open genannt und nenne das jetzt mal genauso.
Open. Open 1 bis 8, Annon oder Bombe.
Das sind 8, 19, 11. Elf verschiedene Werte,
zwischen denen ich unterscheiden will. Und jetzt, ja,
zeige ich euch mal einen Sprachmechanismus von Java,
wo man eben sagen kann, ich will einen neuen Datentyp definieren,
der aus diesen elf möglichen Werten besteht.
Machen wir das doch mal. Das nennt man einen Inam
. Inam ist Abkürzung für Inummeration, also Aufzählung.
Ich definiere also ein Typ durch die Aufzählung seiner möglichen Werte.
Und ich schreibe die jetzt einfach hier rein.
Ich schreibe also Open
One two, 3, 5, 6, 7,
8. I'm known bonna. Tja. Und das ist schon
die ganze Definition des Typs. Wir werden da später noch
ein, zwei Methoden dazuschreiben. Und das bedeutet jetzt,
ich kann eine Variable vom Typ Sale definieren und ich kann zum Beispiel sagen,
Cell X gleich 3, Cell Y gleich anlauen,
Cell, Z gleich open.
Das sind jetzt also einfach Werte des Datentyps Sales.
Das finde ich irgendwie ganz nett. Okay,
dann dürfte er sich an der Stelle schon mal nicht beschweren.
Und dann diesen Game-State können wir eigentlich auch gleich machen,
wir sind ja gerade bei E-Names,
machen wir den auch kurz
Also in welchen Zuständen kann sich dieses Spiel befinden?
Da gibt es, ich glaube, drei Stück.
Also entweder man spielt es noch oder man hat gewonnen oder
man hat Followern. Mehr Möglichkeiten gibt es nicht. Gut,
vielleicht wäre es grammatikalisch sinnvoller, da One und Lost reinzuschreiben.
Ich mache es einfach mal so. Gut, Play-Win-Lose.
Dann sollte jetzt hier der Compiler sich nicht mehr beschweren über diese Typen.
Seht ihr, er akzeptiert es jetzt als Zurückhabetyp.
Ein Inam definiert also auch ein Typ. Und das akzeptiert
er auch als Zurückhabetyp. Bist du doch ganz nett.
Okay, dann gehen wir wieder zurück in die Klasse,
die ich gerade geschlossen habe
Und überlegen mal, was muss denn jetzt hier an Zustand übernommen werden in das Playfield?
Wahrscheinlich kann man das so direkt gar nicht sagen.
Also das ist ja in das Mindfield reingekommen. Das ist sicherlich sinnvoll,
dass die Klasse weiß, wie viele Felder müssen noch aufgedeckt werden.
Das tue ich mir schon mal rein, dass wir das nicht vergessen.
So. Aber jetzt gab es ja eigentlich noch keine Variante,
die fachlich sich gemerkt hat, was Sache ist.
Das wurde bis jetzt an diesen Buttons gespeichert. Ich will
jetzt aber keine Jay-Buttons in das Playfield reinschauen. Ja,
was wäre denn jetzt wahrscheinlich sinnvoll mit Hinblick auf diesen neuen Typ Cell?
Ich muss mir ja 64 mal merken, das hier ist unknown,
das ist unknown, das ist alles unknown.
Das ist eins, das ist Open, das ist zwei,
das ist eins. Das war eine Idee, wie ich
mir das jetzt schön merken kann. Also vielleicht auch mal das Mindfield,
hat sich an einem zweidimensionalen Array von Bulien gemerkt,
wo die Bomben sind, also vielleicht keine,
weil wir keine Bombe, Bombe, keine Bombe,
keine Bombe, keine Bombe, keine Bombe,
Bombe oder so.
Und jetzt muss ich mir eben 64 mal merken,
welche von diesen elf möglichen Zuständen das jeweils sein kann.
Ja, für die zweite ist es ja mein Punkt.
Genau, ein zweites, besonders Area von Typ Zell.
Sehr gut. Das baue ich jetzt also hier mal rein.
Das nennen wir mal Flayfield. Fällt mir gar nichts
besser sein. Okay. Ja, sehr schön.
Das müssen wir jetzt irgendwie sinnvoll initialisieren. Das soll ja
dieselbe Größe haben im Prinzip, wie dieses Mindfield.
Vielleicht mache ich erstmal diese beiden Methoden. Also ich kenne,
ist noch nicht, weil ich werde das mal kurz hier einfügen.
Ich muss ja irgendwie Zugriff auf dieses Mindfield später haben.
Ups, habe ich
den Typ vergessen
Und damit wünsche ich euch nicht wundert, ich werde das
natürlich zuweisen, weil ich später damit anders teilweise richtig,
weil ich später damit arbeiten muss.
Also ich kenne meinen Mindfield und ich will jetzt die Frage
mal voran, wie hoch bin ich.
Ich bin genauso hoch wie das Mindfield.
Wie kann ich diese Anfrage einfach durchleiten, ja?
Delegieren. Mein fehlt.heid. Dann muss ich das gleich nicht
an so vielen Stellen immer wieder neu delegieren.
Da habe ich es ja an einer Stelle zentral.
So, genau. Gut, das heißt also,
ich weiß, wie hoch und wie breit es sein,
habe ich es vergessen?
Nee. Ich weiß, wie bereit und wie hoch es
sein soll. Und da kann ich das ja im Prinzip
dann sinnvoll hier oben entsprechend initialisieren.
Ich könnte jetzt also sagen, Playfield ist ein neues
Cell Array der Höhe Heid
Und der breite With. Kann man so machen.
Okay. Gut. Was steht denn jetzt,
wenn ich nochmal zurückgehe, in meinen random Mindfield,
dann hat er diese Erzeugung des Erics dafür gesorgt,
dass ich 64 Mal den Wert Falls hatte.
Das war ja richtig, weil an den meisten Stellen sind
keine Bomben und da habe ich die Schuhe an die Stellen geschrieben,
nur da, wo Bomben rein sollten.
Was habe ich denn jetzt hier?
Für Default-Werte drin
Bei Bulien, Bulien ist ja ein primitiver Datentyp,
da ist ja Falls der Standard wert.
Cell ist kein primitiver Datentyp, den haben wir selbst gebaut.
Was ist denn immer so der Standardwert für Variablen von Benutzer definierenden Datentypen?
Ja, nein. Und das ist irgendwie nicht so toll.
Ich will nicht mich mit mir um Nall-Gedanken machen müssen,
sondern ich will, dass da überall der Wert unknown steht.
Ja, das könnte ich erst mit verschachtelten Fonds schlafen und so weitermachen,
aber ich glaube, eine einfache Möglichkeit ist,
wenn wir das mit einer For-It-Schleife machen.
Nennen wir das mal vielleicht Row. Was bedeutet diese For-It-Schleife
? Also, ich habe hier ein zweidimensionales Cell-Erry,
das heißt,
ist ein Array von Cell-Errays
Und ich kann also über jeden Eintrag in diesem Array rüberlaufen.
Ich kann nur so sagen, ich will einmal mit der
obersten Reihe was machen, dann mit der Reihe da drunter,
dann mit der Reihe da drunter, dann Mitarbeiter drunter.
Ich werde also in unserem Fall irgendwie achtmal durch die Schleife
durchgehen, wenn es die Höhe acht hat.
Und jetzt kann ich das erst echt füllen.
Dafür gibt es eine tolle Hilfsmethode, muss man einfach wissen.
Ansonsten hättet ihr es mit einer Vorschlafe gemacht.
Phil heißt sie, glaube ich. Und dann sage ich
, füll das doch mal mit dem Wert.
Sell.unknown. Okay. So. Gut. Habe ich also dafür
gesorgt, dass da überall dieses Annonnen drinsteht.
Gut, Countdown. Was ist denn ein sinnvoller Wertvercountdown?
Also ich habe, in unserem Fall habe ich ja
64 Felder, zehn davon sind mit Minen besetzt.
Also muss ich noch 54 aufdenken. Was ist denn mal
eine allgemeine Formel, die mir das ausrechnet?
Wie viele Felder gibt es? Und davon ziehe ich ja.
Und wie groß ist das Spielfeld? Höhemadrate, genau.
Wo sind die Bomben? Das muss ich das Meinfield fragen,
oder? Kann ich das nicht fragen, wie viele Bomben
es hat?
Da ist es
So. Okay. Gut. Weiter im Text. cell
at yxdosisol trivial, das schreibe ich jetzt einfach hin.
Ich muss ja einfach nur auf das RAI zugreifen,
an der richtigen Stelle. So. Gut, was haben wir noch?
Clear. Okay. Also ich würde jetzt vielleicht mal der
Einfache teilweise diese Sachen mit der Rekursion und dem automatischen aufploppen.
Das lassen wir jetzt mal weg mit Blick auf die Uhr.
Ich gehe jetzt also davon aus,
der Benutzer klickt darauf und jetzt muss ich ja gucken,
in dem Mindfield ist da eine Bombe oder nicht.
Das ist jetzt, glaube ich, die entscheidende Frage.
Also, frage ich doch mal, dass Mindfield Ob da
eine Bombe ist, an, ja, Parameternamenstimmen auch schon.
So. Und im anderen Fall mache ich was anderes. Okay,
was muss ich machen, wenn er auf eine Bombe geklickt hat?
Ja. Richtig, man muss also irgendwie die Bomben alle irgendwie aufdecken.
Ich sage, ich schreibe das erst mal hin,
To-do, Bomben aufdecken. Das wäre möglicherweise jetzt mit Blick
auf die Ohren nicht mehr schaffen, ja.
Und dann Es gibt ja hier noch dieses Game-State,
um das wir uns noch gar nicht gekümmert haben.
Also irgendwie muss ich doch jetzt sagen,
Game-State muss jetzt Loose sein oder so.
Ja, ich habe dann irgendwie verloren. Und
dieses Game-State habe ich mich ja noch gar nicht gekümmert.
Dafür brauchen wir noch eine eigene Variable.
Tue ich mal hier hin. Also Game-State, Game-State.
Was ist ein sinnvoller Startwert für die Variable Game-State?
Ja, Play. Das wäre sonst ein ziemlich langweiliges Spiel.
Obwohl bei mir ist es ja fast so,
Loose würde keinen großen Unterschied bei mir machen.
Genau, das heißt, das kann ich hier einfach setzen,
also Game State ist gleich los.
Okay. Ah, muss ich qualifizieren. So. Ansonsten habe
ich irgendwo raufgeklickt, wo keine Bombe ist. Ah,
ich kann ja zumindest vielleicht die Bombe aufdecken, die da war,
ne? Wollen wir das nicht mal zumindest machen?
Sag ich mal. Play fehlt an der Stelle YX.
Soll das Bombensymbol sein? So, ne? Also,
dass ich zumindest, dass es zumindest die Bombe sieht,
auf die auch aufgedrückt hat.
Wie muss ich das an der Stelle ändern,
dass Playfield, wenn da keine Bombe ist?
Also vorher wusste ich nicht,
was es ist,
da war es ja unknow
Was soll es sein, wenn ich jetzt raufklicke und
ich merke, da ist keine Bombe.
Kann ich das so direkt sagen? Oder hängt das von
irgendwas ab? Ja. Ja, das ist jetzt,
ja, tiefe, das Geld darüber, hier passiert werden.
Aber da. Wir müssen zählen, wie viele Nachbarn es gibt
, ne? Oder? Das können wir ja machen.
Da. Jetzt weiß ich, wie viele Nachbarn es gibt.
Wie geht's weiter? Und jetzt, wenn die Zahl,
die wir tun, Nö. So, ne? Und
was war das andere? Wenn es nicht neu ist?
Was einigermaßen. Ja. Also was man jetzt irgendwie will,
ist zu sagen, oder vielleicht ist es sogar noch einfacher,
als wir denken.
Also wenn es quasi, wenn dann null zurückkommt,
will ich ja das hier haben.
Und wenn es eins ist, will ich das haben.
Und wenn es zwei ist, will ich das haben.
Und wenn es drei ist, will ich das.
Und das ist ja ein Riesenzufall,
dass ich das ausgerechnet so angeordnet habe
Wäre jetzt nicht cool, wenn ich irgendwie sagen könnte,
ja, also ich übergebe dir einen Intager, ja,
und übergib mir mal das,
wenn das hier quasi so eine Aufzählung ist,
eine Aufzählung fängt dann nochmal bei Null an und dann geht es immer eins,
zwei, drei weiter.
Gib mir nochmal das Element an der Stelle und tatsächlich gibt
es dafür eine ganz nette Hilfsmethode.
Ich glaube, es gibt eine Methode Values,
die liefert euch quasi an Eric zurück mit den Einträgen des E-Namens
und dann kann ich da einfach an die Stelle entzugreifen.
Das ist einfach so eine Eigenschaft von Java,
das habe ich jetzt einfach mal ausgenutzt. Das heißt,
dann könnte ich doch einfach sagen, dann brauche ich,
glaube ich, die Unterscheideung auch möglicherweise gar nicht mehr.
So, oder
Okay, und was hier natürlich noch fehlt,
rekursives aufdecken, das fehlt dir natürlich noch, ne?
Das mache ich jetzt aus Zeitgründen auch nicht. Okay.
Was machen wir denn jetzt noch? Ich würde vorschlagen,
dass wir das jetzt einfach mal so committen und dass ich euch dann mal die Musterlösung zeige,
weil in den letzten zwei Minuten werden wir das,
glaube ich, nicht mehr hinkriegen.
Ich committe das jetzt einfach immer ganz kurz den aktuellen Stand.
Also ja, keine
besonders aussagekräftige Commit-Message
So, ich glaube, ich habe es.
Und jetzt kann ich doch hier den Branch switchen,
sonst muss ich das von der Konsole machen.
Ah, genau. Also hier habe ich jetzt quasi
die Musterlösung einmal vorbereitet. Und wir schauen uns jetzt nur
mal an, ja, was wir nicht geschafft haben.
Also wir sind eigentlich schon ziemlich weit gekommen.
In dem Playfield fehlte eigentlich fast nur noch dieser rekrusive Aufruf,
wir uns das noch mal ganz kurz angucken.
Hier waren wir vorher so ungefähr, glaube ich, ne?
Gut, die IFs sind hier ein bisschen anders.
Aber das kommt euch, glaube ich, bekannt vor.
Also ich muss fragen, ob da eine Bombe ist oder nicht.
Hier hatten wir ein To-Do, das habe ich jetzt hier implementiert.
Das Gloose hatten wir Dann waren wir so ungefähr bis hier bekommen,
wobei ich das nochmal in eine eigene Methode gepackt habe und
das Win haben wir auch nicht mehr gemacht.
Okay, aber so ungefähr bis hier waren wir gekommen.
Wollen wir uns das nochmal ganz kurz angucken,
das Reveal-Bombskonken, muss nochmal ganz kurz an vielleicht.
Was passiert hier? Ja, ich schleife einfach wieder
ganz langweilig über Höhe und Breite komplett rüber.
Und wenn da eine Bombe ist, dann sorge ich euch
für das in den Playfield auch die Bombe angezeigt wird.
Das hätten wir auch hinbekommen, das ist keine Magie.
Okay. Dann jetzt hier ist diese ganze rekursive Magie.
Ich glaube, das guckt ihr euch mal lieber zu Hause an,
weil das ist nicht eigentlich das Thema der heutigen Vorlesung.
Und die Google haben wir uns jetzt noch gar nicht angeguckt.
Die sollte jetzt also hoffentlich deutlich einfacher geworden sein.
Das waren vorher irgendwie 170 Zeilen. Ich gucke mal,
wie viel das jetzt noch übrig geblieben sind.
Naja, immerhin noch
Okay. Aber ihr werdet sehen, diese furchtbare Einrückungstiefe wird
hier nicht mehr sein. Okay, wieso sind denn jetzt hier?
Ja, genau. Also ich kenne also das Playfield,
das seht ihr auch hier in unserem Diagramm.
Ja, hier, ne? Die Goui kriegt das Playfield
in diesen Konstruktor reingesteckt und arbeitet später auch damit.
Also muss ich die sicherlich kennen. Die Goui muss das Playfield kennen.
Das seht ihr also hier. Den J-Frame gibt es natürlich
immer noch. De-Buttons gibt es natürlich auch noch.
Aber die Buttons merken sich jetzt nicht mehr irgendwelche Spiellogik,
sondern die werden einfach ständig upgedatet. Das zeige ich euch
gleich nochmal. Okay, der Konstruktor ist deutlich übersichtlicher geworden.
Ja, ich bin jetzt also nicht mehr bis Eindrückung,
ist irgendeine Elf irgendwo Spalte 45,
sondern ich bin nur noch
bis Eindruckungsebene.
Das ist doch ganz nett und der Konstruktor passt jetzt hier
auf eine Seite, das finde ich auch nicht schlecht.
Ja, und hat unter anderem damit zu tun,
dass ich die Initialisierung der Bands in der eigenen Methode gemacht habe.
Hier wird es dann wieder ein bisschen hässlicher, okay. Hier seht ihr,
wie die Google auf das Playfield zugreift,
also wenn der Knopf gedrückt würde,
dann kümmere ich mich nicht mehr selber darum,
irgendwas Logisches zu tun, sondern ich sage dem Playfield hier,
der Benutzer hat darauf geflicklikliriert,
dass man bitte an der Stelle inklusive Rekursion und allem,
dann werden die Buttons entsprechend angepasst.
Das heißt, ich frage jetzt die Spiellogik,
wie sieht es denn momentan aus und dementsprechend werden die Buttons angepasst
und dann gucke ich, dass jemand gewonnen oder verloren hat.
Das Update Buttons schauen wir uns auch nochmal ganz kurz an.
Das haben wir hier. Ja, ich würde schon wieder
völlig, langweilig über alle zählen,
Dann frage ich das Spielfeld, in welchem Zustand befindet sich
die Zelle jetzt gerade? Dann wird der Text entsprechend gesetzt und
hier wird dafür gesorgt, dass die Farbe entsprechend gesetzt wird.
Und was man hier ganz nett sieht, ist,
ich kann über solche E-Names switchen, tatsächlich,
so wie du das ja auch vorgeschlagen hattest, das geht tatsächlich.
Ich kann also sagen, wenn es eine offene Zelle ist,
dann soll es diese offene Farbe sein, diese leicht dunkle, blaue Farbe.
Ansonsten in allen anderen Fällen, das geht also hier auch,
soll es eine ganz normale Farbe sein.
Mehr Farben habe ich hier nicht unterschieden. Und dann setze
ich hier die Farbe entsprechend. Aber ich schreibe sie nur rein,
damit es schön aussieht, aber es ist nicht so,
dass ich irgendwann später nochmal aus Debattens lese,
in welcher Text steht denn gerade bei dir oder welche Farbe bist du gerade,
um herauszufinden, was der aktuelle Zustand ist.
Der wird also komplett in dem Playfield gehalten
Und das Checkstate fragt einfach das Playfield, in welchem Zustand
befindest du dich? Gerade auch hier switche ich wieder darüber,
wenn ich noch spiele, muss ich nichts Besonderes machen.
Wenn ich gewonnen habe, dann wird diese Nachricht angezeigt und
wenn ich verloren habe, wird diese Nachricht angezeigt.
Das finde ich auch ganz nett,
dass man diese Nachrichten jetzt sehr eng im Quelltext beieinander hat und
dass die nicht so völlig verstreut sind über eine riesige Klasse.
Okay, ich habe heute leider ein bisschen überzogen,
das tut mir leid. Ich hätte nicht damit gerechnet,
dass das so kompliziert ist, meins zu programmieren,
aber offenbar ist es das doch.
Ja, ich lade das alles hoch und dann sehen wir
uns nächste Woche.
Vielen Dank