Qual é a melhor maneira de resolver uma explosão combinatória de interações?
Uma das coisas em que estou trabalhando agora tem algumas semelhanças com um jogo. Para fins de ilustração, vou explicar meu problema usando um exemplo retirado de um jogo hipotético e fictíci
Vamos chamá-loDeathBlaster 4: O Morte. No DB4, você tem um número deShip
bjetos que periodicamente e aleatoriamente encontrPhenomena
enquanto viajam. Um dadoPhenomenon
pode ter zero, um ou maisEffects
com umShip
que encontra. Por exemplo, podemos ter quatro tipos deShips
e três tipos dePhenomena
.
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
Além disso,Effects
podem interagir um com o outro. Por exemplo, umGreenShip
que está em umGravityWell
eNebulaField
pode derivar algum tipo de sinergia entre o @ geraSpeedEffect
eShieldEffect
. Nesses casos, o efeito sinérgico é em si umEffect
- por exemplo, pode haver umPowerLevelSynergyEffect
que resulta dessa interação. Nenhuma informação além do conjunto deEffects
atuando em umShip
é necessário para resolver qual deve ser o resultado fina
Você pode começar a ver um problema surgindo aqui. Como uma primeira abordagem ingênua, caShip
precisará saber como lidar com cadaPhenomenon
ou todos osPhenomenon
terá que saber sobre cadaShip
. Isso é obviamente inaceitável, então gostaríamos de mudar essas responsabilidades para outro lugar. Claramente, há pelo menos uma classe externa aqui, talvez umMediator
ouVisitor
de algum tipo
Mas qual é a melhor maneira de fazer isso? A solução ideal provavelmente terá essas propriedades:
Tão fácil quanto adicionar um novoShip
como é adicionar um novoPhenomenon
. Interações que não produzem efeito são o padrão e não exigem código adicional para representar. Convenção sobre configuração. Compreende comoEffects
interagem entre si e é capaz de gerenciar essas interações para decidir qual será o resultado finacho que já decidi qual será minha abordagem, mas estou interessado em saber qual é o consenso de melhor design. Por onde você começaria? Que avenidas você exploraria?
Atualização de acompanhamento: Obrigado por suas respostas, pessoal. Aqui está o que eu acabei fazendo. Minha principal observação foi que o número de diferentesEffects
parece pequeno em relação ao número possível dePhenomena
× Ships
interações. Ou seja, embora existam muitos possíveis combinações de interações, o número de tipos de resultados dessas interações é um número menor.
Você pode ver que, por exemplo, embora existam 12 combinações de interação na tabela, existem apenas cinco types de efeitos: modificações na velocidade, modificações no poder, modificações no escudo, invulnerabilidade, mort
Eu introduzi uma terceira classe, oInteractionResolver
, para determinar o resultado das interações. Ele contém um dicionário que mapeiaShip-Phenomenon
pares paraEffects
(que são basicamente um delegado que executa o efeito e alguns metadados). CadaShip
recebe umEffectStack
correspondente aEffects
stá ocorrendo quando o resultado do cálculo da interação é concluíd
Ships
, use oEffectStack
para determinar o resultado real doEffects
adicionando modificadores aos seus atributos e propriedades existente
Eu gosto disso porque:
s naves nunca precisam saber sobre os fenômeno complexidade do relacionamento Ship-Phenomena é abstraída no InteractionResolve Os detalhes de como resolver efeitos múltiplos e possivelmente complexos são abstraídos peloInteractionResolver
. Os navios apenas precisam aplicar os efeitos conforme necessáriIsto permite refatorações úteis adicionais. Por exemplo, omaneir na qual um navio processa efeitos pode ser diferenciado criando umEffectProcessorStrategy
. O padrão pode ser processar todos os efeitos, mas, digamos, umBossShip
pode ignorar efeitos secundários ao ter umEffectProcessorStrategy
.