Решая проблему if web, вы можете создать механизм правил, где каждое конкретное правило кодируется независимо. Дополнительным уточнением для этого было бы создание предметно-ориентированного языка (DSL) для создания правил, однако один только DSL перемещает проблему только из одной базы кода (основной) в другую (DSL). Без структуры DSL не будет лучше, чем родной язык (Java, C # и т. Д.), Поэтому мы вернемся к нему после того, как найдем улучшенный структурный подход.
Основная проблема заключается в том, что у вас есть проблема с моделированием. Всякий раз, когда вы сталкиваетесь с комбинаторными ситуациями, подобными этой, это явный признак того, что ваша абстракция модели, которая описывает ситуацию, является слишком грубой. Скорее всего, вы объединяете элементы, которые должны принадлежать разным моделям, в одну сущность.
Если вы продолжаете ломать свою модель, вы в конечном итоге полностью утратите этот комбинаторный эффект. Однако, выбирая этот путь, легко потеряться в своем дизайне, создавая еще большую неразбериху, перфекционизм здесь не обязательно ваш друг.
Конечные автоматы и механизмы правил являются лишь примером того, как эту проблему можно решить и сделать более управляемой. Основная идея здесь заключается в том, что хороший способ избавиться от такой комбинаторной проблемы, как эта, часто состоит в том, чтобы создать дизайн и повторять его ad-nauseam на вложенных уровнях абстракции до тех пор, пока ваша система не будет работать удовлетворительно. Сродни тому, как фракталы используются для создания сложных паттернов. Правила остаются неизменными, независимо от того, смотрите ли вы на свою систему под микроскопом или с высоты птичьего полета.
Пример применения этого в вашем домене.
Вы пытаетесь смоделировать, как коровы движутся по местности. Хотя в вашем вопросе нет подробностей, я бы предположил, что большое количество ifs включает фрагмент решения, например, if cow.isStanding then cow.canRun = true
но вы застряли, когда добавляете детали местности, например. Поэтому для каждого действия, которое вы хотите предпринять, вы должны проверить все возможные аспекты и повторить эти проверки для следующего возможного действия.
Сначала нам нужен наш повторяемый дизайн, который в этом случае будет FSM для моделирования изменяющихся состояний симуляции. Поэтому первое, что я хотел бы сделать, это реализовать эталонный FSM, определив интерфейс состояния, интерфейс перехода и, возможно, контекст переходакоторый может содержать общую информацию, которая будет доступна другим двум. Базовая реализация FSM будет переключаться с одного перехода на другой независимо от контекста, вот где появляется механизм правил. Механизм правил четко инкапсулирует условия, которые должны быть выполнены, если переход должен состояться. Механизм правил здесь может быть простым списком правил, каждое из которых имеет функцию оценки, возвращающую логическое значение. Чтобы проверить, должен ли переход произойти, мы выполняем итерацию списка правил, и если какое-либо из них оценивается как ложное, переход не происходит. Сам переход будет содержать поведенческий код для изменения текущего состояния FSM (и других возможных задач).
Теперь, если я начну реализовывать симуляцию как один большой FSM на уровне GOD, я получу МНОГО возможных состояний, переходов и т. Д. Беспорядок if-else выглядит так, как будто он исправлен, но на самом деле он просто распространяется: каждый IF Теперь правило, которое выполняет проверку на предмет конкретной информации контекста (которая на данный момент в значительной степени содержит все), и каждое тело IF находится где-то в коде перехода.
Введите разбивку по фракталам: первым шагом будет создание FSM для каждой коровы, где состояния - это собственные внутренние состояния коровы (стоя, бег, ходьба, выпас и т. Д.), И переходы между ними будут зависеть от окружающей среды. Возможно, что график неполон, например, выпас доступен только из стоячего состояния, любой другой переход запрещен, потому что просто отсутствует в модели. Здесь вы эффективно разделяете данные в двух разных моделях: корова и рельеф. У каждого свои свойства. Эта разбивка позволит вам упростить общую конструкцию двигателя. Теперь вместо единого механизма правил, который решает все, у вас есть несколько более простых механизмов правил (по одному для каждого перехода), которые определяют очень конкретные детали.
Поскольку я повторно использую тот же код для FSM, это в основном конфигурация FSM. Помните, когда мы упоминали о DSL раньше? Именно здесь DSL может принести много пользы, если у вас есть множество правил и переходов для написания.
Идти глубже
Теперь БОГУ больше не приходится сталкиваться со всей сложностью управления внутренними состояниями коровы, но мы можем продвинуть это дальше. Например, в управлении ландшафтом все еще много сложностей. Здесь вы решаете, где достаточно разбивки. Если, например, в вашем БОГе вы в конечном итоге управляете динамикой местности (длинная трава, грязь, сухая грязь, короткая трава и т. Д.), Мы можем повторить ту же схему. Ничто не мешает вам внедрить такую логику в сам ландшафт, выделяя все состояния ландшафта (длинная трава, короткая трава, грязная, сухая и т. Д.) В новый FSM ландшафта с переходами между состояниями и, возможно, простыми правилами. Например, чтобы попасть в мутное состояние, механизм правил должен проверить контекст, чтобы найти жидкости, иначе это невозможно. Теперь БОГ стал еще проще.
Вы можете завершить систему FSM, сделав их автономными и дать каждому поток. Этот последний шаг не обязателен, но он позволяет вам динамически изменять взаимодействие системы, регулируя то, как вы делегируете свое решение (запуск специализированного FSM или просто возвращение предварительно определенного состояния).
Помните, как мы упоминали, что переходы могут также выполнять «другие возможные задачи»? Давайте рассмотрим это, добавив возможность взаимодействия различных моделей (FSM) друг с другом. Вы можете определить набор событий и позволить каждому FSM зарегистрировать прослушиватель этих событий. Таким образом, если, например, корова входит в гекс местности, гекс может зарегистрировать слушателей для изменений перехода. Здесь это становится немного сложнее, потому что каждый FSM реализован на очень высоком уровне без каких-либо знаний о конкретной области, которую он скрывает. Однако вы можете добиться этого, если бы корова опубликовала список событий, и ячейка может зарегистрироваться, если увидит события, на которые она может реагировать. Хорошая иерархия семейства событий - это хорошая инвестиция.
Вы можете продвинуться еще глубже, смоделировав уровни питательных веществ и цикл роста травы, с ... как вы уже догадались ... FSM травы, встроенной в собственную модель участка местности.
Если вы продвигаете идею достаточно далеко, БОГу мало что нужно сделать, поскольку все аспекты в значительной степени управляются самостоятельно, освобождая время, чтобы тратить на более благочестивые вещи.
резюмировать
Как указано выше, FSM здесь не является решением, а просто средством для иллюстрации того, что решение такой проблемы не в коде, а в том, как вы моделируете свою проблему. Есть, скорее всего, другие решения, которые возможны и, скорее всего, намного лучше, чем мое предложение FSM. Однако подход «фракталы» остается хорошим способом справиться с этой трудностью. Если все сделано правильно, вы можете динамически распределять более глубокие уровни там, где это имеет значение, а также предлагать более простые модели, где это имеет значение. Вы можете ставить в очередь изменения и применять их, когда ресурсы становятся более доступными. В последовательности действий, возможно, не так важно рассчитывать перенос питательных веществ от коровы к травяному пятну. Однако вы можете записать эти переходы и применить изменения позднее или просто приблизить их с помощью обоснованного предположения, просто заменив механизмы правил или, возможно, заменив реализацию FSM вместе с более простой наивной версией для элементов, которые не находятся в прямой области интерес (эта корова на другом конце поля), чтобы позволить более подробные взаимодействия, чтобы получить фокус и большую долю ресурсов. Все это, не пересматривая систему в целом; Так как каждая деталь хорошо изолирована, становится проще создать замену, ограничивающую или расширяющую глубину вашей модели. Используя стандартный дизайн, вы можете опираться на это и максимизировать инвестиции, сделанные в специальные инструменты, такие как DSL, для определения правил или стандартного словаря для событий, снова начиная с очень высокого уровня и добавляя уточнения по мере необходимости. Так как каждая деталь хорошо изолирована, становится проще создать замену, ограничивающую или расширяющую глубину вашей модели. Используя стандартный дизайн, вы можете опираться на это и максимизировать инвестиции, сделанные в специальные инструменты, такие как DSL, для определения правил или стандартного словаря для событий, снова начиная с очень высокого уровня и добавляя уточнения по мере необходимости. Так как каждая деталь хорошо изолирована, становится проще создать замену, ограничивающую или расширяющую глубину вашей модели. Используя стандартный дизайн, вы можете опираться на это и максимизировать инвестиции, сделанные в специальные инструменты, такие как DSL, для определения правил или стандартного словаря для событий, снова начиная с очень высокого уровня и добавляя уточнения по мере необходимости.
Я хотел бы привести пример кода, но это все, что я могу позволить себе сделать прямо сейчас.