Estou pensando nisso há dias e ainda não tenho certeza do que fazer. Estou tentando refatorar um sistema de combate em PHP (... desculpe.) Aqui está o que existe até agora:
Existem dois tipos (até agora) de entidades que podem participar de combate. Vamos chamá-los de jogadores e NPCs. Seus dados já estão escritos muito bem.
Quando envolvidas em combate, essas entidades são envolvidas com outro objeto no banco de dados chamado a Combatant, que fornece informações sobre a luta em particular. Eles podem se envolver em vários combates ao mesmo tempo.
Estou tentando escrever o mecanismo lógico para o combate injetando combatentes nele.
Quero poder zombar de tudo para testar.
Para separar lógica e dados, quero ter duas interfaces / classes base, uma sendo ICombatantDataa outra ICombatantLogic. Os dois implementadores de dados serão um para os objetos reais armazenados no banco de dados e o outro para meus objetos simulados.
Agora estou tendo incertezas ao projetar o lado lógico das coisas. Posso ter um implementador para cada um dos jogadores e NPCs, mas tenho um problema. Um combatente precisa ser capaz de devolver a entidade que envolve. Esse método getter deve fazer parte da lógica ou dos dados? Sinto fortemente que deve estar nos dados, porque a parte lógica é usada para a execução de combate e não estará disponível se alguém estiver apenas procurando informações sobre uma luta futura. Mas as classes de dados separam apenas o mock do DB, não o player do NPC. Se eu tentar ter duas classes filho do implementador de dados do banco de dados, uma para cada tipo de entidade, como faço para arquitetar isso enquanto mantenho minhas zombarias no loop? Preciso de uma terceira interface como IEntityProvideressa que injeto nas classes de dados?
Também com algumas das idéias que estive pensando, acho que vou ter que colocar verificações para garantir que você não descasque as coisas, como fazer a lógica para um NPC acidentalmente agrupar os dados para um jogador. Isso faz algum sentido? Essa é uma situação que seria possível se a arquitetura estivesse correta ou o design correto proibiria isso completamente para que eu não precisasse verificar?
Se alguém pudesse me ajudar a traçar um diagrama de classe ou algo para isso, isso me ajudaria muito. Obrigado.
Também é útil notar que a classe de dados simulados realmente não precisa da Entity, pois apenas especificarei todos os parâmetros como estatísticas de combate diretamente. Talvez isso afete o design correto.
Meu palpite é que Combatant.entitynão é usado durante o combate e, portanto, não deveria existir. Talvez você precise de outra classe, como a EntityVsEntityCombatque envolve a lógica de combate, contém Entity <--> Combatantmapeamentos e atualiza os Entityestados após o término do combate? Talvez mais algumas informações sobre sua arquitetura atual possam ajudar.
— Torious 3/11
Parte da maneira como abordamos isso no passado é, em vez de ter representações completamente separadas para jogadores e NPCs, exigindo que ambos implementem uma interface comum, direcionando para a convergência de representação entre eles o máximo possível, como posso. subclassificando-os a partir de um Charactermodelo comum no qual pressiono tanto sobre eles quanto faz sentido generalizar. Isso ajuda a evitar problemas com a execução de operações de NPC nos jogadores, tornando as operações mais aplicáveis ​​em geral, uma vez que há menos tendência natural para as representações divergirem do que se fossem implementações completamente independentes. A alavancagem básica do polimorfismo ajuda a lidar com os casos que precisam divergir (por exemplo, se você fez o seuCombatantLogicresponsável por lidar com o que acontece quando alguém morre, você teria que digitar para ter certeza de usar a lógica correta; então não faça, jogadores e NPCs implementem die()métodos separados e apropriados ).
Concordo que você Entityfaz parte dos dados. No entanto, com base no que eu estava dizendo, eu tenderia a remover ou limitar o seu papel a CombatantDatafavor de fazer com que a lógica de combate extraísse valores diretamente dos Entity, talvez CombatantDataapenas com o armazenamento de valores calculados caros e específicos de combate único. Seus modelos de teste seriam mais orientados a fornecer Entitymodelos falsos do que a preencher CombatantData. ( CombatantDataDuplicar muitas informações Entityme incomoda da mesma maneira que um banco de dados desnormalizado. No entanto, se você acredita na Lei de Deméter, que eu não gosto apaixonadamente, não vai querer fazer as coisas da maneira que eu Estou sugerindo. Claro, se você acredita na Lei de Demeter, não tenho certeza de queCombatantDatadeve até fornecer acesso ao Entity.)
CombatantData realmente não duplica os dados da entidade, inclui o estado da entidade em combate, como a saúde atual e quaisquer efeitos de status nela.
— Tesserex 6/07/12
@Tesserex: Ah, tudo bem. Se esse estado não persistir entre os combates, isso é sensato. Desconsidere essa parte, então. :) O resto do que estou dizendo faz sentido?