Eine Aufgabe in meiner Software-Engineering-Klasse ist es, eine Anwendung zu entwerfen, die verschiedene Formen eines bestimmten Spiels spielen kann. Das fragliche Spiel ist Mancala, einige dieser Spiele heißen Wari oder Kalah. Diese Spiele unterscheiden sich in einigen Aspekten, aber für meine Frage ist es nur wichtig zu wissen, dass sich die Spiele in folgenden Punkten unterscheiden können:
- Die Art und Weise, wie das Ergebnis eines Umzugs behandelt wird
- Die Art und Weise, in der das Spielende bestimmt wird
- Die Art und Weise, in der der Gewinner ermittelt wird
Das erste, woran ich dachte, war, das Strategiemuster zu verwenden. Ich habe eine Variation der Algorithmen (die eigentlichen Spielregeln). Das Design könnte so aussehen:
Ich dachte mir dann, dass im Spiel von Mancala und Wari die Art und Weise, wie der Gewinner ermittelt wird, genau dieselbe ist und der Code dupliziert würde. Ich denke nicht, dass dies per definitionem eine Verletzung des Grundsatzes "eine Regel, ein Ort" oder "trocken" ist, da eine Änderung der Regeln für Mancala nicht automatisch bedeutet, dass die Regel auch in Wari geändert werden sollte. Trotzdem hatte ich aufgrund der Rückmeldungen meines Professors den Eindruck, ein anderes Design zu finden.
Ich habe mir dann folgendes ausgedacht:
Jedes Spiel (Mancala, Wari, Kalah, ...) hätte nur ein Attribut des Typs der Schnittstelle jeder Regel, dh WinnerDeterminer
und wenn es eine Mancala 2.0-Version gibt, die mit Mancala 1.0 identisch ist, außer wie der Gewinner bestimmt wird, kann dies nur sein Verwenden Sie die Mancala-Versionen.
Ich denke, die Implementierung dieser Regeln als Strategiemuster ist zweifellos gültig. Das eigentliche Problem ist jedoch, dass ich es weiterentwickeln möchte.
Beim Lesen des Schablonenmethodenmusters dachte ich sofort, dass es auf dieses Problem angewendet werden könnte. Die Aktionen, die ausgeführt werden, wenn ein Benutzer einen Zug ausführt, sind immer gleich und in derselben Reihenfolge:
- Steine in Löcher ablegen (dies ist für alle Spiele gleich, würde also in der Template-Methode selbst implementiert werden)
- Ermitteln Sie das Ergebnis des Umzugs
- Ermitteln Sie, ob das Spiel aufgrund des vorherigen Zugs beendet wurde
- Wenn das Spiel beendet ist, bestimmen Sie, wer gewonnen hat
Diese drei letzten Schritte sind alle in meinem oben beschriebenen Strategiemuster enthalten. Ich habe große Probleme, diese beiden zu kombinieren. Eine mögliche Lösung, die ich gefunden habe, wäre, das Strategiemuster aufzugeben und Folgendes zu tun:
Ich sehe nicht wirklich den Designunterschied zwischen dem Strategiemuster und diesem? Ich bin mir aber sicher, dass ich eine Template-Methode verwenden muss (obwohl ich mir genauso sicher war, ein Strategiemuster verwenden zu müssen).
Ich kann auch nicht bestimmen, wer für die Erstellung des TurnTemplate
Objekts verantwortlich ist, während ich mit dem Strategiemuster das Gefühl habe, dass ich Objektfamilien (die drei Regeln) habe, die ich leicht mit einem abstrakten Factory-Muster erstellen könnte. Ich hätte dann ein MancalaRuleFactory
, WariRuleFactory
usw. und sie würden die richtigen Instanzen der Regeln erstellen und mir ein RuleSet
Objekt zurückgeben.
Angenommen, ich verwende die Strategie + abstraktes Factory-Muster und habe ein RuleSet
Objekt, das Algorithmen für die drei Regeln enthält. Ich habe nur das Gefühl, dass ich das Muster der Template-Methode weiterhin verwenden kann, indem ich dieses RuleSet
Objekt an meine übergebe TurnTemplate
. Das "Problem", das dann auftaucht, ist, dass ich meine konkreten Implementierungen von den TurnTemplate
, diesen Klassen niemals brauchen würde, obsolet werden würde. Bei meinen geschützten Methoden TurnTemplate
konnte ich das einfach aufrufen ruleSet.determineWinner()
. In der Folge TurnTemplate
wäre die Klasse nicht mehr abstrakt, sondern müsste konkretisiert werden, ist sie dann noch ein Template-Methodenmuster?
Fassen wir zusammen: Denke ich richtig oder fehle ich etwas Leichtes? Wie kann ich ein Strategie- und ein Vorlagenmethodenmuster kombinieren, wenn ich auf dem richtigen Weg bin?