Что лучший способ состоит в том, чтобы разрешить комбинаторный взрыв взаимодействий?

Одна из вещей, я продолжаю работать прямо сейчас, имеет некоторые общие черты игре. В целях иллюстрации я собираюсь объяснить свою проблему с помощью примера, оттянутого из фиктивной, гипотетической игры.

Давайте назовем это DeathBlaster 4: Deathening. В DB4 у Вас есть много Ship объекты, с которыми периодически и случайным образом встречаются Phenomena как они перемещаются. Данный Phenomenon может иметь нуль, один, или больше Effects на a Ship это встречается с ним. Например, у нас могло бы быть четыре вида Ships и три вида Phenomena.

                              Phenomena
              ==========================================
Ships         GravityWell     BlackHole      NebulaField
------------  ------------------------------------------
RedShip       +20% speed      -50% power     -50% shield
BlueShip no effect       invulnerable   death              Effects of Various
GreenShip     -20% speed      death          +50% shield        Phenomena on Ships
YellowShip    death           +50% power     no effect    

Кроме того, Effects может взаимодействовать друг с другом. Например, a GreenShip это находится в обоих a GravityWell и a NebulaField может получить некоторые совместные действия между сгенерированным SpeedEffect и ShieldEffect. В таких случаях синергетический эффект самостоятельно Effect - например, мог бы быть a PowerLevelSynergyEffect это следует из этого взаимодействия. Никакая информация кроме набора Effects действие на a Ship необходим для разрешения, каков конечный результат должен быть.

Можно начать видеть, что проблема появляется здесь. Как наивный первый подход, любой каждый Ship должен будет знать, как обработать каждый Phenomenon, или каждый Phenomenon должен будет знать о каждом Ship. Это очевидно недопустимо, таким образом, мы хотели бы переместить эти обязанности в другое место. Очевидно существует по крайней мере один внешний класс здесь, возможно, a Mediator или Visitor какой-то.

Но что лучший способ состоит в том, чтобы сделать это? Идеальное решение будет, вероятно, иметь эти свойства:

  • Столь же легкий добавить новое Ship поскольку это должно добавить новое Phenomenon.
  • Взаимодействия, которые не производят эффекта, являются значением по умолчанию и не требуют, чтобы дополнительный код представил. Конвенция по конфигурации.
  • Понимает как Effects взаимодействуйте друг с другом, и способно к управлению этими взаимодействиями для решения, каков конечный результат будет.

Я уже решил, каков мой подход будет, я думаю, но мне интересно слышать, каково согласие лучшего дизайна. Где Вы запустили бы? Какие проспекты Вы исследовали бы?



Последующее обновление: Спасибо за Ваши ответы, всех. Вот то, что я волновал выполнение. Мое основное наблюдение состояло в том что количество различных Effects кажется, является маленьким относительно количества возможных Phenomena × Ships взаимодействия. Таким образом, хотя существует много возможных комбинаций взаимодействий, количество видов результатов тех взаимодействий является меньшим числом.

Вы видите, что, например, хотя существует 12 комбинаций взаимодействия в таблице, существует только пять видов эффектов: модификации для ускорения, модификации к питанию, модификации для защиты, неуязвимость, смерть.

Я представил третий класс, InteractionResolver, определить результат взаимодействий. Это содержит словарь, который отображается Ship-Phenomenon пары к Effects (которые являются в основном делегатом, который выполняет эффект и некоторые метаданные). Каждый Ship вручен EffectStack соответствие Effects это испытывает, когда результат вычислений взаимодействия завершен.

Ships затем используйте EffectStack определить фактический результат Effects на них, путем добавления модификаторов к их существующим атрибутам и свойствам.

Мне нравится это потому что:

  1. Поставки никогда не должны знать о Явлениях.
    • Сложность отношений Явлений Поставки абстрагирована в InteractionResolver.
    • Детали того, как разрешить несколько и возможно сложные эффекты, абстрагированы далеко InteractionResolver. Поставки только должны применить эффекты по мере необходимости.
    • Это включает дополнительные полезные рефакторинги. Например, путь, которым поставка обрабатывает эффекты, мог дифференцироваться путем создания EffectProcessorStrategy. Значение по умолчанию могло бы быть должно обработать все эффекты, но, скажем, a BossShip мог бы проигнорировать незначительные эффекты при наличии другого EffectProcessorStrategy.
10
задан John Feminella 18 November 2019 в 17:24
поделиться

7 ответов

Интересная потенциальная опция состояла бы в том, чтобы использовать вариант Шаблона "посетитель".

Judith Bishop и R. Nigel Horspool написал работу об эффективности шаблона разработки, в которой они объяснили различные варианты на классическом шаблоне "посетитель" с помощью C# 3 функции.

В частности, я смотрел бы на то, как они работают с делегатами для обработки шаблона "посетитель". Используя список или стопку делегатов мог potentally дать Вам интересный способ обработать несколько эффектов от нескольких объектов, и быть намного легче расширить или сторону иерархии классов (добавьте поставки или добавьте эффекты) без огромных изменений кода повреждения.

1
ответ дан 4 December 2019 в 04:53
поделиться

Походит на классика, несколько отправляют проблему мне.

0
ответ дан 4 December 2019 в 04:53
поделиться

Не совсем ответ, но мне это справедливо кричит "шаблон свойств". Существует известная yegge напыщенная речь об этом, я думаю, что она предложит Вам некоторые достойные указатели.

http://steve-yegge.blogspot.com/2008/10/universal-design-pattern.html

0
ответ дан 4 December 2019 в 04:53
поделиться

или каждая Поставка должна будет знать, как обработать каждое Явление, или каждое Явление должно будет знать о каждой Поставке.

Я думаю, что это - ключ к Вашей проблеме, и это верно, если каждое взаимодействие явлений поставки уникально. В таблице Вы создали, который, кажется, имеет место, таким образом, для поставок n и m явлений, необходимо указать n*m взаимодействие. Вы правы чувствовать запах проблемы обслуживания.

Единственный выход должен сделать взаимодействия явлений поставки не как уникальные, заставив эффект явлений зависеть от свойств поставки. Например, мы могли сказать только, что поставки, созданные со странной окисью алюминия, переживут черную дыру.

Но наличие только одного свойства не покупает Вас ничто, Вы, возможно, столь же легко указали, какие поставки затронуты черными дырами. Ключ - то, что несколько свойств показывают тот же комбинаторный взрыв.

Таким образом, поставки, созданные со странной окисью алюминия, переживут черные дыры, и поставки, созданные без, могут пойти быстрее. 1 Свойство позволяет Вам указывать 2 вещи (1 бит = 2 возможности). Поставки, созданные с corbite механизмами, пойдут быстрее в зоне деформации. Поставки и с corbite механизмами и со странной окисью алюминия получат 50%-й щит в поле туманности и т.д.

Добавление свойств к поставкам позволяет Вам стараться не указывать, как каждый явления взаимодействуют с каждой поставкой, и все же все еще имейте каждый, явления и каждая поставка показывают соответствующее поведение.

Если существуют поставки M, то Вам только нужны log2 свойства (M), чтобы дать каждой поставке уникальное поведение.

0
ответ дан 4 December 2019 в 04:53
поделиться

Это похоже на классическую дилемму полиморфизма/посетителя ООП. Однако Ваши требования помогают.

В основном я создал бы базовый класс Ship тот весь бетон Поставки происходит из. Этот класс имел бы методы:

class Ship
{
  void encounterBlackHole() {}
  void encounterNebula() {}
  ... etc. ...
};

с пустыми телами по умолчанию. Когда Вы добавляете новое Явление, Вы просто добавляете новый метод с пустым телом. (Методы могут иметь аргументы, как координаты или вес черной дыры и т.д.),

Для Эффектов и их взаимодействия - я думаю, что необходимо добавить больше информации о том, как Вы хотите это, например, являетесь взаимодействиями, редкими или обычными, они кумулятивный в некотором виде, они ограниченный ограниченным набором переменных, которыми они управляют...

0
ответ дан 4 December 2019 в 04:53
поделиться

Интересный вопрос

В некотором роде или другой, поставка должна будет знать, какие явления могут влиять на нее и явления, какие эффекты она имеет на который поставка.

Это могло быть сохранено в XML-файле, проанализированном во времени выполнения.

Возможно, Вы могли использовать Шаблон "декоратор" для вычисления эффектов. Вы генерируете различный phenomenas во времени выполнения.

Предположим, что Ваши поставки реализуют Интерфейсный IShip и везде в Вашем коде, Вы используете IShips.

Теперь, предположите, что все Ваши явления также реализуют Интерфейсный IShip (требуемый шаблоном разработки декоратора).

IShip myShip = myShip.AddPhenomena(PhenomenaGeneratedByAFactoryForThisShip);

В явлениях Вы переносите методы от исходной поставки, таким образом, можно выполнить модификацию к свойствам и так далее.

Кроме того, при использовании стратегической модели, можно генерировать любой вид явлений, которые Вы хотели бы.

При удалении явлений, может использоваться путем обхода груды украшенных поставок, которые Вы имеете, и переобертывание ее, таким образом, я не вижу проблемы там.

Что касается совместных действий, я думаю, что использовал бы немного измененные явления, который работает, только если целевая поставка имеет весь phenomenas на себе.

0
ответ дан 4 December 2019 в 04:53
поделиться

Я думаю, что ответ проблемы, зависят от того, как хороший вопрос спрашивает.

Я думаю, что способ разработать, зависят от того, что вопрос (или вопрос будет входить в будущее),

Вы даете таблицу, затем я думаю, что решение, поддерживают таблицу и запрашивают его.

код Python здесь: (не протестированный и просто показывает для примера),

class Ship():
     def __init__(self,type):
         self.type=type
     def encounterPhenomena(self,type): # let Phenomena to process ship
         p = Phenomena(type)
         p.process(self)

class Phenomena():
     processTable = {}
     def __init__(self,type):
         self.type=type
     def process(self,ship):
         try:
             self.processTable[self.type](ship.type) #query the internal table to process ship
         except:
             pass #if Phenomena don't know this ship type then no process..
     def addType(type,processMethod):
         processTable[type]=processMethod #add new Phenomena, and add processMethod

def run():
    A = Ship(type = 'RedShip')
    A.encounterPhenomena(type='GravityWell');

Если измененный метод процесса, просто измените метод процесса в классе Явлений.

Если Вы думаете, что поставка должна знать, как обработать Явления, то измените метод процесса в класс поставки.

или Вы думаете, что существуют другие вещи не, только Явления должны изменить состояние поставки (как другие поставки, скала мелководья), необходимо поддержать таблицу процессов в классе поставки и сделать Явления одним из него,

говорите снова, как разработать, зависят от вопроса сам.

0
ответ дан 4 December 2019 в 04:53
поделиться
Другие вопросы по тегам:

Похожие вопросы: