Ich werde eine Handvoll Vorschläge machen. Einige von ihnen widersprechen sich. Aber vielleicht sind einige nützlich.
Betrachten Sie Listen im Vergleich zu Flags
Sie können über die ganze Welt iterieren und bei jedem Gegenstand eine Flagge ankreuzen, um zu entscheiden, ob Sie die Flaggensache ausführen möchten. Oder Sie können eine Liste nur der Elemente führen, die die Flaggensache ausführen sollen.
Berücksichtigen Sie Listen und Aufzählungen
Sie können Ihrer Artikelklasse isAThis und isAThat weiterhin Boolesche Felder hinzufügen. Oder Sie können eine Liste von Zeichenfolgen oder Aufzählungselementen haben, z. B. {“isAThis”, “isAThat”} oder {IS_A_THIS, IS_A_THAT}. Auf diese Weise können Sie der Enumeration (oder den String-Konstanten) neue hinzufügen, ohne Felder hinzuzufügen. Nicht, dass beim Hinzufügen von Feldern wirklich etwas nicht stimmt ...
Betrachten Sie Funktionszeiger
Anstelle einer Liste von Flags oder Aufzählungen könnte eine Liste von Aktionen für dieses Element in verschiedenen Kontexten ausgeführt werden. (Entity-ish ...)
Betrachten Sie Objekte
Einige Leute bevorzugen datengesteuerte oder skriptgesteuerte Ansätze oder Ansätze mit Komponenten. Aber auch altmodische Objekthierarchien sind eine Überlegung wert. Die Basisklasse muss die Aktionen akzeptieren, z. B. "Diese Karte für Phase B spielen" oder was auch immer. Dann kann jede Art von Karte überschreiben und entsprechend reagieren. Es gibt wahrscheinlich auch ein Spielerobjekt und ein Spielobjekt, so dass das Spiel Dinge tun kann wie: if (player-> isAllowedToPlay ()) {mache das Spiel…}.
Betrachten Sie Debug-Fähigkeit
Das Schöne an einem Stapel von Flaggenfeldern ist, dass Sie den Status jedes Elements auf dieselbe Weise prüfen und ausdrucken können. Wenn der Status durch verschiedene Typen oder Beutel mit Komponenten oder Funktionszeigern dargestellt wird oder sich in verschiedenen Listen befindet, reicht es möglicherweise nicht aus, nur die Felder des Elements zu betrachten. Es sind alles Kompromisse.
Letztendlich Refactoring: Betrachten Sie Unit-Tests
Egal wie sehr Sie Ihre Architektur verallgemeinern, Sie können sich Dinge vorstellen, die sie nicht abdeckt. Dann müssen Sie umgestalten. Vielleicht ein bisschen, vielleicht viel.
Eine Möglichkeit, dies sicherer zu machen, sind zahlreiche Unit-Tests. Auf diese Weise können Sie sicher sein, dass die vorhandene Funktionalität auch dann noch funktioniert, wenn Sie die darunter liegenden Elemente (möglicherweise um ein Vielfaches!) Neu angeordnet haben. Jeder Komponententest sieht im Allgemeinen so aus:
void test1()
{
Game game;
game.addThis();
game.setupThat(); // use primary or backdoor API to get game to known state
game.playCard(something something).
int x = game.getSomeInternalState;
assertEquals(“did it do what we wanted?”, x, 23); // fail if x isn’t 23
}
Wie Sie sehen können, ist es für die Unit-Test-Strategie von entscheidender Bedeutung, die API-Aufrufe der obersten Ebene für Spiele (oder Spieler, Karten usw.) stabil zu halten.