Code review bzw. "Coaching"

Liebes Forum,

ich versuche gerade, mir mit Java saubere OO Programmierung beizubringen. Ja, das wird langwierig, ich weiß. Ich habe aber das Gefühl, einfach nur im Trüben zu stochern und nicht voran zu kommen. Bisher gehe ich das so an, dass ich neben der Lektüre versch. Fachliteratur vor allem kleine Projekte umsetze und dabei versuche Tipps, die mir Leute bislang mitgegeben haben, in einem neuen Projekt zu berücksichtigen. Das führt aber dazu, dass ich für mein aktuelles, eher harmloses Programm (Implementierung eines römischen Backgammon-Vorgängers) einzelne Methoden sicher 5-6x umgeschrieben habe und inzwischen nicht schlauer, sondern nur verwirrter bin.
Was ich dringend bräuchte ist jemand/etwas, der/das mich beim Thema OO Design und Softwareentwurf mal aufgleist. Oder sich meinen Projektentwurf und ab und zu den zugehörigen Code ansieht und mir sagt, was besser zu machen ist.
Derzeit habe ich einfach das Gefühl, planlos rumzuprobieren und eher schlechteren als besseren Code zu schreiben. Könnt ihr mir helfen bzw. Tipps geben, wie ich mich hier verbessern kann?
 
Vielen Dank - das hatte ich vor, allerdings habe ich an anderer Stelle (Python) die Erfahrung gemacht, dass Review Threads schnell einschlafen. Trotzdem nehme ich jede Hilfe gerne an!
Gelesen habe ich konkret zu Java und OO und bislang:
Java von Kopf bis Fuß (zum Umstieg von Python auf Java),
Objektorientierte Programmierung (Bernhard Lahres, Gregor Rayman) - nur teilweise, da zwar verständlich geschrieben, aber für den totalen Noob etwas zu abstrakt
Entwurfsmuster von Kopf bis Fuß (ja, ich mag die vKbF Reihe, ein m.E. gut verständlicher Ansatz) - allerdings auch noch nicht ganz.
Wie man sieht setzen diese Bücher eigtl. alle voraus, dass man einen mehr oder weniger präzisen Plan seines Programms bereits hat. Ich mache das zwar auch, aber bei der Umsetzung stelle ich regelmäßig fest, dass das so nicht funktionieren wird, baue das 12345x um und am Ende ist es doch wieder ein Spaghettihaufen😡

Tante EDIT sagt: ich werde mal mein Programm-Diagramm (kein echtes UML) aufbereiten und zusammen mit dem Code posten. Der ist im aktuellen Zustand allerdings aktuell noch unkompiliert und ungetestet und müsste auch nochmal aufgehübscht werden vor dem Posten...
 
Zuletzt bearbeitet:
UML "zwingt" dich ja mehr oder weniger dazu OOD/OOP-like zu denken
Stimmt schon. Aber ich hab oft das Problem, dass ich nicht weiß, wo z.B. eine Methode am besten hingehört, vor allem wegen Abhängigkeiten zwischen den Klassen. Beispielsweise hab ich eine Methode "setzeSpielstein()", die ich in meinem Entwurf in eine allgemeine Spielklasse gepackt habe, die den Ablauf einer Runde (aber keine Nutzerinteraktion) steuert. Inzwischen bin ich der Meinung, dass die Methode in die Klasse Feld gehört, worauf der Stein gesetzt werden soll. Grund ist, dass ich in drei Methoden in drei Klassen prüfe, ob ein Boolscher Wert wahr ist, den die vorige Methode zurückgibt, nur um diesen Wert dann wiederum zurückzugeben. Das klingt nach unnötigem und verschachteltem Code. Andererseits will ich nicht kreuz und quer Abhängigkeiten zwischen den Klassen einführen...
 
Was ist denn in diesem Fall „Feld“?
Das gesamte Spielfeld (zB ein Schachbrett) oder ein einzelnes Feld auf diesem?

Das klingt nach unnötigem und verschachteltem Code. Andererseits will ich nicht kreuz und quer Abhängigkeiten zwischen den Klassen einführen...

Verschachtelter Code und viele Abhängigkeiten sind meistens zusammen und nicht gegensätzlich 😉
 
WerIstDerBoogieman? hat gesagt.:
Objektorientierte Programmierung (Bernhard Lahres, Gregor Rayman) - nur teilweise
Das solltest du ändern 😉
Da das Buch nicht für Anfänger gedacht ist (laut Autoren richtet sich das Buch an Informatikstudenten, Softwareentwickler usw), sollte man sich das Grundgerüst bereits angeeignet haben. Ebenso liest sich das Buch,
zumindest für mich, recht sperrig und vieles verstehe ich erst nach mehrmaligem Durchlesen. Jedoch würde ich ein Buch nicht nur "teilweise" lesen, das macht wenig Sinn. Nimm dir Zeit und mach zu jedem Kapitel Notizen, wirkt hier Wunder 😉

Nebenbei: hier im Forum geben einige Nachhilfe, poste dein Anliegen in der Plauderecke und ich bin mir sicher, dein PN-Fach bekommt einige Zuschriften
 
Du siehst einen Unterschied zwischen Anfängern und Informatikstudenten? 😉
Ich war noch nie ein Informatikstudent 🙂 Jedoch denke ich zu wissen was du meinst. Hier tummeln sich ja auch ständig welche, die im dritten Semester sagen wir, ausbaufähige Programmierkenntnisse aufweisen.

Man denkt aber auch ganz automatisch, dass ein Informatikstudent sich bereits im Vorfeld für das Thema interessiert hat. So einer wäre ich 😉
 
Da das Buch nicht für Anfänger gedacht ist (laut Autoren richtet sich das Buch an Informatikstudenten, Softwareentwickler usw), sollte man sich das Grundgerüst bereits angeeignet haben. Ebenso liest sich das Buch,
zumindest für mich, recht sperrig und vieles verstehe ich erst nach mehrmaligem Durchlesen
Exakt, und deswegen hab ich irgendwann mit der Lektüre aufgehört. Es hörte sich zu Beginn gut an und die ersten Kapitel, die ich probehalber gelesen hatte, fand ich gut. Aber gerade der Ansatz zu so substanziellen Bereichen wie den 5 Prinzipien ist dann m.E. doch zu theoretisch bzw. schwer auf die Praxis übertragbar geraten. Entwurfsmuster vKbF ist da besser (hier hab ich einiges erst verstanden, was bereits im Buch von Lahres/Rayman erwähnt wurde), sagt aber nix zur Analyse. Ich finde es besser, ein Buch abzubrechen wenn es mir nix bringt als die begrenzte und daher wertvolle Zeit damit zu verbringen, die anderswo besser angelegt wäre. An den anderen Büchern lese ich weiter bzw. lese Kapitel erneut, um mit den Inhalt wieder zu vergegenwärtigen.

Danke für den Tipp mit der Nachhilfe, das probiere ich auf jeden Fall aus!

Was ist denn in diesem Fall „Feld“?
Das gesamte Spielfeld (zB ein Schachbrett) oder ein einzelnes Feld auf diesem?
Ich bin noch dabei, ein sauberes UML Diagramm zu erstellen (teste ein anderes Tool dafür aus und muss mich erst eingewöhnen), das will ich noch posten. Daher in Kürze: das Spiel folgt im Wesentlichen den Backgammon Regeln:
24 Felder, 2 Spieler, jeweils 12 Steine, 2 Würfel (die Römer haben mit 3 gespielt, deswegen will ich die Option auf 3 Würfel offen für später offen halten). Jeder würfelt und kann hat dann die Wahl: Neuen Stein setzen oder bestehenden bewegen. Man kann in beiden Fällen beide Augenzahlen kombinieren und so einzelne Steine weiter voranbringen oder zwei Steine setzen/ziehen, jeweils um die Augenzahl eines Würfels. Schlagen ist möglich, solange nicht 2 gegnerische Steine auf einem Feld stehen (=blockiert/gesichert).
Mein Entwurf sieht aktuell (ohne GUI) folgende Klassen vor:
Controller: enthält main(), erzeugt Spieler- und Spiel-Instanzen. Mehr (noch) nicht.
Game: enthält die Rundenlogik, also eine würfeln() Mehtode, und bislang auch das Platzieren oder Ziehen von Steinen, sowie das Erzeugen von 24 Feld-Objekten. Speichert den gerade aktiven Spieler.
Feld: ein einzelnes Feld. Hält die darauf positionierten Steine fest, gibt Auskunft darüber, ob es blockiert ist und kann einen Stein setzen oder entfernen.
Spieler: hat Name, vorrätige Steine und kann diese ändern.
Stein: hat bislang nur eine Eigenschaft, nämlich Besitzer. Hab lange rumüberlegt, wie man diese zu kleine Klasse ersetzen könnte, aber die anderen Lösungen fand ich sehr umständlich. Ich hab die mal implementiert, weil vermutlich weitere Methoden/Attrivute dazukommen.

Frage ist aktuell, ob die ganze "ziehen/setzen"-Logik nicht komplett in die Feld-Klasse gehört. Bislang ist sie zwischen Spiel und Feld aufgeteilt. Grund: ein Teil ist von Eigenschaften der Spielklasse abhängig (wie Augenzahlen der Würfel, aktiver Spieler). Ein anderer Teil spielt sich dann logisch auf dem/den betroffenen Feld(ern) ab.
 
Ich bin noch dabei, ein sauberes UML Diagramm zu erstellen
Was denn für eins, uml ist der Oberbegriff für knapp 20 völlig verschiedene ;P

Frage ist aktuell, ob die ganze "ziehen/setzen"-Logik nicht komplett in die Feld-Klasse gehört. Bislang ist sie zwischen Spiel und Feld aufgeteilt. Grund: ein Teil ist von Eigenschaften der Spielklasse abhängig (wie Augenzahlen der Würfel, aktiver Spieler). Ein anderer Teil spielt sich dann logisch auf dem/den betroffenen Feld(ern) ab.
Die Aufteilung klingt bisher am sinnvollsten 😉

Stein: hat bislang nur eine Eigenschaft, nämlich Besitzer. Hab lange rumüberlegt, wie man diese zu kleine Klasse ersetzen könnte, aber die anderen Lösungen fand ich sehr umständlich. Ich hab die mal implementiert, weil vermutlich weitere Methoden/Attrivute dazukommen.
Da bietet sich uU ein Enum an 😉
 
Die Aufteilung klingt bisher am sinnvollsten 😉
Durchaus, allerdings führt das bisher zu einigen merkwürdigen Verrenkungen im Code. Ich geb mir bis heute Abend noch Zeit, eine schöne Lösung zu finden, dann poste ich den Code 😎
Da bietet sich uU ein Enum an 😉
Irgendwie bin ich davon ausgegangen, dass ein Enum was einzigartiges ist... in dem Sinn, dass man nur eine Referenz drauf halten sollte. Wenn man drüber nachdenkt, ist das aber eigtl. Unsinn - von daher: ja, das ist die beste Lösung. Jedes Feld-Objekt enthält dann ein Stein-enum-Array, das Enum sieht ganz simpel aus
Code:
private enum token {PLAYER1, PLAYER2}
Was mich zur Frage bringt: gesetzt den Fall, dass ich mehr als 2 Spieler habe und aus einem Spieler Array ein Spieler Enum machen will - kann ich das Casten oder ein Enum dynamisch aufbauen?
 
Tatsache, es sind acht aufgeführt. Dachte, es würde dort ebenfalls über SOLID gesprochen, aber dan hab ich das verwechselt.
Übrigens geht ein Enum für die Steine nicht: der jeweilige Besitzer ist ein Objekt der Klasse Spieler, und wenn ich in der Enum einen neuen Typ "Spieler1" erzeuge, funktioniert die Zuordnung nicht.
 
Übrigens geht ein Enum für die Steine nicht: der jeweilige Besitzer ist ein Objekt der Klasse Spieler, und wenn ich in der Enum einen neuen Typ "Spieler1" erzeuge, funktioniert die Zuordnung nicht.
Ich habe ehrlich gesagt keine Ahnung was du damit meinst 😀

Ich bin davon ausgegangen, dass es zwei Arten von Steinen gibt - einen für Spieler 1 und einen für Spieler 2, quasi Schwarz und weiß. Ist das etwa groß anders?
 
Ah sorry, ist immer leichter mit Code vor Augen. Ich bin mit Diagramm und Codeüberarbeitung noch nicht durch, hoffe aber, dass ich beides heute Abend posten kann. Dann wird deutlicher, was ich meine.
 
Sind hier noch offene, nicht geklärte Fragen?

Die OO-Denke verstehst de am besten, wenn du nach objektorientierung suchst. (Das ist das paradigma, so ähnlich wie ne Doktrin in der Katholischen Kirche)

Mal etwas Butter zu: Prähistorisches, römisches Backgammon versteh ich nicht.

Aber was die Erweiterbarkeit der Spielerzanzahl anbelangt: YAGNI ...

Dannnoch ... Mit UML (2) meint man üblicherweise Klassendiagramme,
im gesetzten Kontext überdas ohnehin.

Schönen Abend
 
Ja, vielleicht wäre deine Antwort nicht falsch, vielleicht wäre deine antwort nicht unpassend. ......

Halt dich doch einfach raus, sobald ich etwas geschrieben hatte, das hatte ich dir schonmal.

So schwer nicht zu begreifen.
 
So. Hab jetzt ewig rumgetestet und Fehler beseitigt, der Code kompiliert jetzt und tut soweit, was er soll. Daher hier zuerst mal das Diagramm und eine Erläuterung der Spielregel:
Das Spiel (Tabula) ist wie gesagt eine (einfachere) Vorform von Backgammon. Zwei Spieler versuchen, jeweils 12 Steine über das Spielfeld ins Ziel zu bringen und so vom Brett zu entfernen. Es gibt 24 Felder, man muss nicht genau Feld 24 oder 25 als Zielfeld erreichen, nur drüberkommen. Im Gegensatz zu Backgammon sind die Steine zu Beginn noch nicht platziert - man setzt sie erst. Gespielt wird mit zwei Würfeln - eine Erweiterung auf drei ist angelegt, da das Spiel klassisch vermutlich mit drei Würfeln gespielt wurde. Nach dem Wurf hat man zwei Optionen, von denen wiederum zwei weitere Optionen abhängen: man kann zuerst entscheiden, ob man einen Stein setzen oder ziehen will. Hat man sich hier entschieden, kann man wählen, ob man für alle Würfel separat ziehen will oder die Augenzahlen addiert, was einen einzelnen, aber mächtigen Zug ermöglicht.
Bei der Variante "Stein setzen" wird der Stein immer auf ein Feld mit Augenzahl des Würfels gesetzt - also bei einer 5 und einer 2 beispielsweise einer auf Feld 5 und auf Feld 2. Wählt man die Kombi wäre es in diesem Fall Feld 7.
Bei der Variante "Stein ziehen" kann man sich ein oder mehrere Feld(er) mit einem eigenen Stein aussuchen und analog ziehen (also zwei Steine für zwei Würfel oder einen für die Kombi).
Schlagen ist dabei wie beim Mensch ärgere dich nicht möglich. Als Einschränkung gilt noch, dass ein Feld mit mindestens zwei Steinen eines Spielers für diesen "sicher" ist; hier kann der Gegner also weder schlagen noch selber hinziehen.

Zu erwähnen ist noch, dass ich bislang nur die "Spielmechnik" implementiert habe; also Zeug, das für das Ausführen eines Zuges nötig ist. Alles, was mit Spielerentschiedungen zu tun hat, fehlt noch; die Prüfung auf Spiel=gewonnen bau ich gerade ein.
tabula_klassen-png.10640

Den Code poste ich später nach.
Interessieren wprde mich wie gesagt, ob der Entwurf passt, vor allem im Hinblick auf das später zu ergänzende Material wie GUI, Spiellogik/Spieleretscheidungen etc. Vielleicht kann man auch mal ne primitive KI implementieren...
 

Anhänge

  • tabula_klassen.png
    tabula_klassen.png
    58,8 KB · Aufrufe: 447
Zuletzt bearbeitet:
Ich würde Game noch aufspalten - in eine, die das Spielfeld darstellt, eine für Würfel (zB Würfelbecher) und eine für die Spiellogik (das, was Game jetzt ist, abzüglich der beiden neuen Klassen).

Warum muss Token denn seinen Besitzer kennen - reicht es nicht, wenn es zwei Arten von Token gibt, und der Spieler weiß, welcher der beiden Arten seine ist?

außerdem würde ich ein paar Rückgabetypen anpassen (zb von setNewToken) und Methoden anders benennen (zb changeStoredTokens eher sowas wie decreaseToken) - ist aber zT Geschmackssache.


Ich finde btw ein Domänenmodell für sowas deutlich besser geeignet 😉
 
Interessante Denkanstöße...

Ich würde Game noch aufspalten - in eine, die das Spielfeld darstellt, eine für Würfel (zB Würfelbecher) und eine für die Spiellogik (das, was Game jetzt ist, abzüglich der beiden neuen Klassen).
Hier bin ich nicht sicher, welchen konkreten Vorteil außer der besseren Übersichtlichkeit von Game das bringt. Die neuen Klassen (vor allem Spielfeld) wären doch ziemlich klein - Spielfeld macht wenig mehr als 24 Feld Instanzen zu erzeugen und in einem Array bereitzuhalten. Oder verstehe ich dich da falsch?

Warum muss Token denn seinen Besitzer kennen - reicht es nicht, wenn es zwei Arten von Token gibt, und der Spieler weiß, welcher der beiden Arten seine ist?
Stimmt... mal wieder zu kompliziert gedacht.🙄 Ich bau das zu einem Enum um
 
Hier bin ich nicht sicher, welchen konkreten Vorteil außer der besseren Übersichtlichkeit von Game das bringt. Die neuen Klassen (vor allem Spielfeld) wären doch ziemlich klein - Spielfeld macht wenig mehr als 24 Feld Instanzen zu erzeugen und in einem Array bereitzuhalten. Oder verstehe ich dich da falsch?
Wie auch schon von @SchwarzWeiß gesagt gibts keine zu kleinen Klassen 😉
Aktuell kümmert sich eine Klasse um das Würfeln und um das Anordnen des Feldes - obwohl das zwei Grundverschiedene Dinge sind, kann man also wunderbar trennen. Als Stichworte zB Separation of Concerns und Single Responibility Principle

Außerdem: sollte bessere Übersichtlichkeit nicht schon Grund genug sein? 😉
 
OK, überzeugt😀
Ich hab nochmal nachgeschaut (hier): da ging es um GUI-Klassen für Buttons, die nur nen Konstruktor und eine Methode hatten, also gar kein Attribut. Das ist dann schon grenzwertig, weil Klassen sich ja über Verhalten UND Zustände definieren.
 

Zurück
Oben