Du verwendest einen veralteten Browser. Es ist möglich, dass diese oder andere Websites nicht korrekt angezeigt werden. Du solltest ein Upgrade durchführen oder ein alternativer Browser verwenden.
Ich habe eine abstrakte Klasse "Schachfigur", die von nicht abstrakten Klassen wie "König" "Bauer" usw. erweitert wird.
Nun schreibt die Klasse "Schachfigur" vor, dass jede abgeleitete Klasse eine Funktion implementiert, die ausgibt, wo die Figur überall hingehen könnte.
Mein Problem ist nun: Manche Klassen, wie zum Beispiel "Bauer" müssen den bisherigen Spielverlauf kennen, um die genannte Funktion implementieren zu können (wegen En-Passant), andere wiederum nicht. D.h. Manche brauchen in der Funktion einen zusätzlichen Parameter, andere nicht.
In der abstrakten Klasse muss ich ja nun aber entscheiden, wieviele Parameter die Funktion haben soll.
Nun kenne ich die En-Passant-Regel nicht so genau, aber afaik kann ein Bauer diese nur ausspielen, wenn er sein Spiel nicht mit einem 2-Feld-Zug begonnen und diese Regel noch nicht angewendet hat. Das könnte man in der "makeMove()"-Methode (oder wie auch immer die heisst) durch ein boolean signalisieren. Im weiteren Verlauf des Spiels benötigt auch der Bauer nur noch alle freien Felder des Schachbretts, um daraus jene zu markieren (zurück zu geben) auf welche er gehen kann.
Bei En Passant ist's noch einfach: Bauern laufen ja nur vorwärts, d.h. man kann einen En Passant Schlag machen, genau dann, wenn der Bauer noch in seiner ursprünglichen Reihe steht. Kritischer wird's bei der Rochade: Die darf nur gemacht werden, wenn weder König noch Turm bisher bewegt wurden (und sie können so bewegt werden, dass sie später wieder ihre AUsgangsstellung haben - d.h. daran kann man das nicht erkennen). Die brauchen also wirklich ein Flag, so wie Spacerat beschrieben hat - einen zuätzlichen Parameter brauchen sie aber eigentlich nicht, oder ???:L
Bei En Passant ist's noch einfach: Bauern laufen ja nur vorwärts, d.h. man kann einen En Passant Schlag machen, genau dann, wenn der Bauer noch in seiner ursprünglichen Reihe steht.
Oh Mann - es ist ja genau umgekehrt: Der, der einen Doppelzug gemacht hat, kann geschlagen werden Ich schieb' das mal darauf, dass meine Bemühungen um eine Schach-Engine eindeutig zu lange her sind, und der Morgenkaffe noch nicht gewirkt hat...
Ich bin im Moment nicht mal sicher, ob es in der Kompetenz der Figur liegen sollte, herauszufinden, welche Züge möglich ist - oder ob das nicht eine "übergeordnete" Instanz bestimmen sollte (die das Brett, alle Figuren, und ggf. den Bisheringen Spielverlauf kennt, einschließlich der Flags, die dort jetzt in den Parametern kodiert werden würden) ???:L Muss bei Gelegenheit mal schauen, was ich damals in meinem Schachprogramm verbrochen habe
Ich bin im Moment nicht mal sicher, ob es in der Kompetenz der Figur liegen sollte, herauszufinden, welche Züge möglich ist - oder ob das nicht eine "übergeordnete" Instanz bestimmen sollte (...) ???:L
es macht keinen Sinn... eine Figur sollte nicht wissen wie der aktuelle Context aussieht.
Jeder Figur hat gewisse Moeglichkeit sich zu bewegen (vor, rueck, seitwaerts, 1x, huepfen etc). Ob das nun wie im aktuellen Kontext ausfaellt ist nicht Sache der Figur (nach dem Motto - Springer huepft ueber Spielbrett)
Liegt es nicht in der Kompetenz des Soldaten (Schachfigur), einen Befehl ("makeMove()") zu verweigern, der gegen die Regeln verstösst? Natürlich muss der Soldat die Regeln kennen. Kennt er sie nicht, kann er sie ja in seinem Handbuch (Pre-Conditions) nachschlagen. Deswegen macht es auch durchaus Sinn, die Spielfigur so zu implementieren, dass sie jederzeit eine Anfrage nach möglichen Zügen wahrheitsgemäss beantworten kann. Könnte sie es nicht, bräuchte sie auch keine Methode, wie sie der TS haben möchte.
Liegt es nicht in der Kompetenz des Soldaten (Schachfigur), einen Befehl ("makeMove()") zu verweigern, der gegen die Regeln ist? Natürlich muss der Soldat die Regeln kennen. Kennt er sie nicht, kann er sie ja in seinem Handbuch (Pre-Conditions) nachschlagen. Deswegen macht es auch durchaus Sinn, die Spielfigur so zu implementieren, dass sie jederzeit eine Anfrage nach möglichen Zügen wahrheitsgemäss beantworten kann. Könnte sie es nicht, bräuchte sie auch keine Methode, wie sie der TS haben möchte.
Die Frage ist doch eben, ob dass die Verantwortung des "Soldaten" ist (Soldaten sind ja nicht gerade für eigenständige Entscheidungen bekannt, eher nur als Befehlsempfänger), oder ob das Konzept der möglichen Spielzüge nicht als eigentständige Abstraktion und damit Klasse besser umgesetzt wäre.
Bei komplexeren Regeln ist es meist nicht mehr Aufgabe des Fachobjektes diese Regeln zu prüfen, sondern die Regeln selbst stellen ein eingenständiges Konzept dar.
stell dir vor du willst ein Strassenverkehr modellieren.
Modelierst du die Funktionalitaet "fahren" des Objekts "Auto" mit dem Wissen dass es bei Stau anhalten muss ? Dass es im Fall X rueckwaerts fahren muss ? dass es in einer Spielstrasse 5KmH faehrt und auf der Autobahn vollpower ?
nein tut man nicht.
Es ist nicht die Aufgabe des Objektes selber Kontextlogik auszufuehren !
Alles andere ist Vermischung von Verantwortlichkeiten = schlechtes Design
stell dir vor du willst ein Strassenverkehr modellieren.
Modelierst du die Funktionalitaet "fahren" des Objekts "Auto" mit dem Wissen dass es bei Stau anhalten muss ? Dass es im Fall X rueckwaerts fahren muss ? dass es in einer Spielstrasse 5KmH faehrt und auf der Autobahn vollpower ?
Nö... nicht wirklich... Aber zumindest würde diese Funktionalität die Möglichkeit bekommen, den Aufruf gegen die Regeln zu prüfen und ggf. mit Exceptions um sich zu schmeissen, wenn sie, vor einer Wand stehend, weiterfahren (objektiv unmöglich) oder in der Spielstasse "vollpower" fahren (straftat) soll.
maki hat gesagt.:
Soldaten sind ja nicht gerade für eigenständige Entscheidungen bekannt, eher nur als Befehlsempfänger
Mag sein... jedoch gibt es Befehle, die Gehorsamsverweigerung (throw Exception) rechtfertigen.
Nun bewegen wir uns hier auf dem niveau der Logik und nicht der Emotionen. Und wenn der TS entscheidet, es wäre eleganter den einzelnen Figuren die jeweils relevanten Regeln bei zu bringen, statt alle Anweisungen gegenzuprüfen, soll es so sein. Natürlich könnte das Gegenprüfen aber entfallen, wenn gewährleistet ist, dass die höhere Instanz nur gültige Anweisungen liefert (sollte auch nicht all zu schwer sein). Dann wäre ein eigenständiges Reglement natürlich eleganter.
Nö... nicht wirklich... Aber zumindest würde diese Funktionalität die Möglichkeit bekommen, den Aufruf gegen die Regeln zu prüfen und ggf. mit Exceptions um sich zu schmeissen, wenn sie, vor einer Wand stehend, weiterfahren (objektiv unmöglich) oder in der Spielstasse "vollpower" fahren (straftat) soll.
ganz dumm gefragt - woher weiss die Methode fahren dass vor ihr eine Wand steht ?
mit deiner loesung erlebst du schnell eine riesen wust an code in der funktionalitaet fahren, da dies in jeden erdenklichen Kontext anders ausfaellt. Es waere unmoeglich / unsinnig jegliche Moeglichkeit in dieser Methode unterzubringen (Wand fahren und Spielstrasse sind ja nur 2 moegliche Kontexte).
Anders gesagt - dein Ansatz widerspricht dem SingleResponsibility Konzept. Eine Klasse soll eine Verantwortung haben - beim Auto zB fahren. Es ist nicht die Verantwortung des Autos zu wissen wie und wann zu fahren ist.
Bei der Funktionalitaet oel wechseln willst du auch nicht reinprogrammieren wie der Mechaniker das Oel reinschuettet etc