Я предложу несколько предложений. Некоторые из них противоречат друг другу. Но, возможно, некоторые из них полезны.
Рассмотрите списки против флагов
Вы можете перебирать мир и проверять флаг на каждом предмете, чтобы решить, стоит ли делать флаг-вещь. Или вы можете сохранить список только тех предметов, которые должны делать пометку.
Рассмотрим списки и перечисления
Вы можете продолжать добавлять логические поля в свой класс элементов isAThis и isAThat. Или вы можете иметь список строк или перечислимых элементов, таких как {«isAThis», «isAThat»} или {IS_A_THIS, IS_A_THAT}. Таким образом, вы можете добавлять новые в перечисление (или строковые значения) без добавления полей. Не то чтобы с добавлением полей что-то было не так ...
Рассмотрим функциональные указатели
Вместо списка флагов или перечислений может быть список действий, выполняемых для этого элемента в разных контекстах. (Entity-иш ...)
Рассмотреть объекты
Некоторые люди предпочитают подходы на основе данных, сценариев или компонентов. Но стоит рассмотреть и старомодную иерархию объектов. Базовый класс должен принять такие действия, как «разыграть эту карту для фазы B хода» или что-то еще. Тогда каждый вид карты может переопределить и ответить соответствующим образом. Возможно, есть и объект игрока, и игровой объект, поэтому игра может делать что-то вроде if (player-> isAllowedToPlay ()) {do the play…}.
Рассмотреть возможность отладки
Еще одна приятная вещь о куче полей флагов в том, что вы можете одинаково проверять и распечатывать состояние каждого элемента. Если состояние представлено различными типами, или пакетами компонентов, или указателями на функции, или находится в разных списках, может быть недостаточно просто просмотреть поля элемента. Это все компромиссы.
В конце концов, рефакторинг: рассмотрим модульные тесты
Независимо от того, насколько вы обобщаете свою архитектуру, вы сможете представить вещи, которые она не охватывает. Тогда вам придется рефакторинг. Может немного, может много.
Способ сделать это более безопасным - с помощью модульных тестов. Таким образом, вы можете быть уверены, что даже если вы переставили вещи под (может быть, намного!), Существующая функциональность все еще работает. Каждый юнит-тест выглядит, как правило, так:
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
}
Как видите, поддержание стабильности этих вызовов API верхнего уровня для игры (или игрока, карты и т. Д.) Является ключом к стратегии модульного тестирования.