He estado pensando esto durante días y todavía no estoy seguro de qué hacer. Estoy tratando de refactorizar un sistema de combate en PHP (... lo siento). Esto es lo que existe hasta ahora:
- Hay dos (hasta ahora) tipos de entidades que pueden participar en el combate. Vamos a llamarlos jugadores y NPC. Sus datos ya están escritos bastante bien.
- Cuando participan en el combate, estas entidades se envuelven con otro objeto en el DB llamado a
Combatant
, que les da información sobre la lucha en particular. Pueden participar en múltiples combates a la vez. - Estoy tratando de escribir el motor lógico para el combate inyectando combatientes en él.
- Quiero poder burlarme de todo para las pruebas.
Para separar la lógica y los datos, quiero tener dos interfaces / clases base, una siendo ICombatantData
y la otra ICombatantLogic
. Los dos implementadores de datos serán uno para los objetos reales almacenados en la base de datos y el otro para mis objetos simulados.
Ahora me encuentro con incertidumbres con el diseño del lado lógico de las cosas. Puedo tener un implementador para cada jugador y NPC, pero tengo un problema. Un combatiente necesita poder devolver la entidad que envuelve. ¿Debería este método getter ser parte de la lógica o los datos? Creo firmemente que debería estar en los datos, porque la parte lógica se usa para ejecutar el combate, y no estará disponible si alguien solo está buscando información sobre una próxima pelea. Pero las clases de datos solo separan el simulacro de DB, no el jugador de NPC. Si trato de tener dos clases secundarias del implementador de datos DB, una para cada tipo de entidad, ¿cómo puedo diseñar eso mientras mantengo mis simulaciones en el bucle? ¿Necesito una tercera interfaz como IEntityProvider
esa que inserto en las clases de datos?
Además, con algunas de las ideas que he estado considerando, siento que tendré que poner controles en su lugar para asegurarme de que no coincidan las cosas, como hacer que la lógica de un NPC envuelva accidentalmente los datos de un jugador. ¿Eso tiene algún sentido? ¿Es esa una situación que incluso sería posible si la arquitectura es correcta, o el diseño correcto lo prohibiría por completo para que no necesite verificarlo?
Si alguien pudiera ayudarme a diseñar un diagrama de clase o algo para esto, me ayudaría mucho. Gracias.
editar
También es útil tener en cuenta que la clase de datos simulados realmente no necesita Entity
, ya que solo especificaré todos los parámetros como estadísticas de combate directamente. Entonces, tal vez eso afecte el diseño correcto.
fuente
Combatant.entity
que no se usa durante el combate y, por lo tanto, no debería existir. ¿Quizás necesites otra clase como laEntityVsEntityCombat
que envuelve la lógica de combate, contieneEntity <--> Combatant
mapeos y actualizaEntity
estados una vez que el combate ha terminado? Tal vez algo más de información sobre su arquitectura actual podría ayudar.Respuestas:
Parte de la forma en que he abordado esto en el pasado es, en lugar de tener representaciones completamente separadas para los jugadores y los NPC, al tiempo que requiero que ambos implementen una interfaz común, conduciendo hacia la convergencia de la representación entre ellos en la mayor medida que pueda, como subclasificándolos de un
Character
modelo común en el que presiono tanto sobre ellos como tiene sentido generalizar. Esto ayuda a evitar problemas con la ejecución de operaciones de NPC en jugadores y similares al hacer que las operaciones sean más aplicables en general, ya que las representaciones tienen una tendencia menos natural a divergir que si fueran implementaciones completamente independientes. El apalancamiento básico del polimorfismo ayuda a manejar los casos que tienen que divergir (por ejemplo, si realizó suCombatantLogic
responsable de manejar lo que sucede cuando alguien muere, tendrías que hacer una verificación de tipo para asegurarte de usar la lógica correcta; así que no, haga que los jugadores y los NPC implementendie()
métodos separados y apropiados ).Estoy de acuerdo en que tu
Entity
es parte de los datos. Sin embargo, sobre la base de lo que estaba diciendo, en realidad tendería a eliminar o limitar el papel de ustedCombatantData
a favor de que la lógica de combate extraiga valores directamente deEntity
, quizásCombatantData
solo almacenando valores calculados costosos y específicos de combate único. Sus maquetas de prueba estarían más orientadas a proporcionarEntity
modelos falsos que a poblarseCombatantData
. (HabiendoCombatantData
duplicado mucha información delEntity
me molesta de la misma manera que lo hace una base de datos desnormalizada. Sin embargo, si crees en la Ley de Demeter, que apasionadamente no, no querrás hacer las cosas como yo Estoy sugiriendo. Por supuesto, si crees en la Ley de Demeter, no estoy seguro de que tuCombatantData
incluso debería proporcionar acceso a laEntity
.)fuente