Pregunta

He estado pensando en esta cuestión del diseño orientado a objetos durante un tiempo y no he podido encontrar una solución satisfactoria, así que pensé en abrirla a la multitud para obtener algunas opiniones.

tengo un Juego clase que representa un juego de mesa por turnos, podemos asumir que es similar al Monopoly para los propósitos de esta pregunta.En mi diseño tengo un Jugador clase que contiene un método Tomar turno.

El Juego recorre todo Jugadors y llama al método TakeTurn para hacer todo lo necesario para completar el turno.Quiero poder tener n números de jugadores y poder establecer un número arbitrario de ellos para que sean jugadores de computadora.Entonces, mi idea era tener una clase HumanPlayer y una ComputadoraJugador clase, los cuales derivan de Player.

El Juego sólo conoce el Jugador clase y simplemente llama al Tomar turno método en cada Jugador Sucesivamente.Mi problema viene en el hecho de que ComputadoraJugador Los objetos se pueden automatizar completamente, es decir.Siguiendo con el ejemplo del Monopoly, puede decidir comprar una propiedad usando alguna lógica.Ahora, con el Jugador humano objeto, necesita obtener una entrada del usuario real para poder comprar una propiedad, por ejemplo, lo que parece implicar una interfaz diferente y potencialmente significa que no deberían derivar

No he podido encontrar una buena solución al problema sin tener la Juego clase conoce las implementaciones reales de los distintos Jugador clases explícitamente.Siempre podría hacer la suposición en el Juego clase que solo habrá jugadores humanos y de computadora y efectivamente cerrarla para su extensión, pero no parece una buena programación orientada a objetos.

Cualquier opinión sobre esto sería apreciada.

¿Fue útil?

Solución

Creo que no deberías dejar que la clase Game maneje IO.De esta manera, el método TakeTurn (de bloqueo) ocultará del tablero de juego los medios de implementación.puede utilizar otros objetos para comunicarse con el usuario.

Lo único que debe preocupar a la clase Game es el estado del tablero y el turno.Todos los jugadores deben implementar una única interfaz de jugador y ocultar toda implementación del juego.

Otros consejos

Si el juego gestiona el estado del juego y Al hacer E/S, el Juego está haciendo demasiado.

Quieres que el juego se centre estrictamente en reglas, turnos y cambios de estado.El juego no sabe qué es un jugador;sólo sabe que tiene jugadores.

Quieres que los jugadores examinen el estado del juego y ejecuten las acciones legales durante sus turnos.

Los jugadores humanos y el juego en su conjunto ambos comparten un paquete de E/S común que muestra el estado del juego y solicita a los humanos su opinión.

Puedes hacer un buen uso de Java. Observable haciendo que el paquete de E/S sea Observer del juego.De esa manera, los cambios en el estado del juego se informan a la E/S para su visualización, registro o ambos.

Probablemente no tendría dos HumanPlayer y ComputerPlayer clases, pero una sola Player clase que se configura en el momento de la creación con la estrategia de entrada adecuada.

La forma en que el jugador obtiene información para decidir su movimiento en el siguiente turno del juego es la solo algo que varía (al menos de la descripción original del problema), así que simplemente encapsule eso en una abstracción separada.

Cualquier clase de alto nivel que configure el juego también debe crear los dos conjuntos de jugadores (uno humano, otro simulado por computadora), con la estrategia de entrada adecuada para cada uno, y luego simplemente entregar estos objetos de jugador al objeto del juego.La clase Game entonces solo llamará al TakeTurn método en la lista dada de jugadores, para cada nuevo turno.

En lugar de decirle a la clase del juego que solo hay un humano, ¿por qué no dejar que reciba esa entrada durante el menú/inicialización del juego?Si hay más jugadores, eso se puede decidir mediante algún tipo de entrada (seleccionar jugadores en el menú), antes de la inicialización de la clase de juego.

La interfaz que Jugador regalos a Juego es ortogonal al comportamiento de la derivada Jugador clases.

El hecho de que la implementación de Tomar turno varía dependiendo del tipo de concreto del Jugador El objeto no debería ser motivo de preocupación.

Pienso que el Game La clase no debe preocuparse por ninguna implementación de las clases del Reproductor y también ignorar la interfaz de usuario.

Cualquier entrada del usuario debe ser manejada por el HumanPlayer clase.

Yo diría que el Juego A la clase no debería importarle si se trata de un jugador de computadora o de un jugador humano.siempre debe llamar Tomar turno en la siguiente clase de jugador.Si se trata de un jugador humano, es responsabilidad del Jugador clase, para comunicarse con el usuario y preguntarle qué hacer.Eso significa que se bloqueará hasta que el usuario se decida.Como normalmente la interacción de la interfaz de usuario tiene lugar en el hilo principal de una aplicación, sólo es importante que se establezca un bloqueo. Tomar turno no bloqueará la aplicación en su totalidad; de lo contrario, la entrada del usuario no se podrá procesar mientras Juego espera por Tomar turno.

En vez de Juego llamada de clase Tomar turno sobre todos los jugadores los jugadores deben llamar Tomar turno sobre el Juego clase y el Juego La clase debe validar si el jugador correcto está tomando su turno.

Esto debería ayudar a resolver el Usuario y Computadora problema del jugador.

No estoy seguro si esto es lo que quieres

public abstract class Player 
{
  int position;
  DecisionMaker decisionDependency;

  ...

  public void TakeTurn()
  {
    position += RollDice();
    GameOption option GetOptions(position);
    MakeDescion(option);
  }

  protected int RollDice()
  {
    //do something to get the movement
  }

  protected abstract void MakeDecision(GameOption option);

}

Public class ComputerPlayer : Player
{
  public ComputerPlayer()
  {
    decisionDependency = new AIDecisionMaker();
  }

  protected override void void MakeDecision(GameOption option)
  {
    decisionDependency.MakeDecision(option);
    //do stuff, probably delgate toan AI based dependency
  }
}

Public class HumanPlayer : Player
{
  public HumanPlayer()
  {
    decisionDependency = new UIDecisionMaker();
  }

  protected override void void MakeDecision(GameOption option)
  {
    decisionDependency.MakeDecision(option);
    //do stuff, probably interacting with the a UI or delgate to a dependency
  }
}
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top