2010-07-02 11 views
5

Estoy implementando un juego simple "Juega tus cartas correctamente" (también conocido como juego superior/inferior). En caso de que no te hayas encontrado antes, las reglas son realmente simples. Se usa un solo palo de cartas (por ejemplo, corazones). Se saca una carta a la vez y el objetivo es adivinar correctamente si el valor facial de la siguiente carta será mayor o menor que el valor facial de la carta dibujada previamente.Java - Consejos de diseño para el juego simple

La lógica del juego no es particularmente compleja, no me preocupa eso. Se me ocurrió un diseño, pero no estoy del todo contento con él. Hay algunas áreas en las que estoy seguro de que podría mejorarse, y en eso me gustaría que me aconsejara. Aquí está una interfaz para la clase (comentarios adicionales para la comprensión, los comentarios no reales):

public interface PlayYourCardsRight { 

/** 
* Get the number of cards remaining with higher face values than the previously 
* drawn card 
* @return 
*/ 

public abstract int getNumberCardsHigher(); 

/** 
* Get the number of cards remaining with lower face values than the previously 
* drawn card 
* @return 
*/ 

public abstract int getNumberCardsLower(); 

/** 
* Get all cards that have already been drawn in the order they were drawn in 
* 
*/ 

public abstract List<Card> getPlayedCards(); 

/** 
* Simple prediction algorithm - if there are more cards left in the deck with 
* lower face values than the previous card, then predict 'Lower', if there 
* are more cards left in the deck with higher face values then predict 
* 'Higher', if there are equal numbers of higher/lower cards pick 'higher' or  'lower' 
* at random 
* 
* Prediction is an Enum (Higher/Lower/None) 
* 
*/ 

public abstract Prediction getPrediction(); 

/* 
* Draw the next card at random 
*/ 

public abstract void nextRound(); 

/** 
* Specifiy what the next card should be 
* 
* @param card 
*/ 

public abstract void nextRound(Card card); 

} 

Como se puede ver que es todo bastante explica por sí mismo y simple. Aquí están mis problemas:

No quiero que el constructor dibuje automáticamente una tarjeta. Esto significa que inicialmente no hay una "tarjeta dibujada previamente". Tengo un valor NO PREDICTION en la enumeración Prediction pero, como no hay una "tarjeta dibujada previamente", los métodos getNumberCardsHigher() y getNumberCardsLower() no pueden devolver valores sanos (tampoco pueden devolver valores sanos cuando se han dibujado todas las cartas del mazo).

Obviamente, podría simplemente lanzar una excepción, pero eso parece exagerado, especialmente porque todas las llamadas a los métodos tienen que ser envueltas en try/catch. Tampoco estoy contento con devolver un valor negativo, ya que eso podría generar fácilmente algunos errores si alguien olvida o no puede controlarlos.

Todas las sugerencias son bienvenidas!

Respuesta

4

Personalmente no piense que lanzar una excepción sin marcar en el caso de la comprobación de argumentos es exagerada en absoluto, esto es suponiendo que su código está afirmando un estado inválido (NO DEBE invocar esos métodos con el objeto en ese estado, SIEMPRE).

Normalmente utilizo una IllegalArgumentException para mostrar que se ha pasado un argumento que no se ajusta al contrato de la llamada al método, y una IllegalStateException para mostrar que el objeto no está en el estado para manejar la llamada al método en este momento .

Dado que ambas son excepciones sin marcar, no tiene que intentar/atraparlas, simplemente déjelas burbujear, hacen las excepciones que son excelentes en - le dan un seguimiento de pila y le dicen exactamente dónde está su error incluye a quien lo llamó incorrectamente.

normalmente utilizo una especie de cadena, por cierto, en su caso podría ser:

throw new IllegalStateException("You cannot call this method until a card has been drawn"); 

Lógicamente, simplemente no tiene sentido preguntar si la tarjeta es mayor o menor que una tarjeta que no existe

Ahora, si su método realmente LANZA esa excepción, entonces tiene que seguir adelante y corregir su código para que no llame a ese método hasta después de haber dibujado una tarjeta, por lo que debe averiguar cómo dibujar tu primera carta independientemente

Nota: Las excepciones son solo para la detección de errores, evite usarlas para el control de flujo. Esto significa que no deberías tratar de atrapar la excepción y usarla para robar una carta y luego volver a llamar. En su lugar, debe programar de tal manera que garantice que se dibujará una tarjeta antes de la primera vez que se invocan los métodos.

0

Argumentaría que ambos métodos deberían devolver card.count cuando no hay una tarjeta anterior que se haya dibujado. Hay la misma cantidad de cartas más bajas y más altas que quedan, y para ambas hay tarjetas con más cartas más altas/más bajas que nada. Su algoritmo funcionaría y devolvería un NO_PREDICTION.

+0

No creo que tenga ningún sentido que ambos métodos devuelvan 'card.count' en este caso. Esta solución sugeriría que hay 13 cartas más altas y 13 cartas más bajas, lo que implica 26 cartas en general, a pesar de que solo hay 13 cartas en un palo y en el juego. Aunque sabemos lo que está pasando, imaginamos presentar esta información a un usuario. Parece un comportamiento profundamente insatisfactorio. – Peter

+0

@Peter: mi razonamiento es el siguiente: una tarjeta es más baja y más alta que la ausencia de una tarjeta. Esta es una de esas situaciones donde dos estados opuestos son iguales con respecto al concepto de la nada. No parece contradictorio para mí, pero esa es solo mi opinión. Cuando no quedan cartas, ambas deberían devolver 0, por lo que también serían iguales en esa etapa. Al principio, ambos deberían devolver el opuesto de 0, en este caso card.count. – JRL

0

Personalmente, recomendaría tener una carta inicial antes de que el jugador haga algo, ya que no tiene sentido hacer que el jugador haga nada antes de que la primera carta esté activa, pero creo que "no quiero que el constructor dibujar automáticamente una carta "significaba que no quieres hacer eso. Si no quieres hacer eso, haré que las funciones arrojen excepciones, y tendré el código que los llama (la función de predicción) caso especial al comienzo del juego para devolver "sin predicción" en lugar de intentar llamarlos. El final del juego no es un caso especial; ambas funciones deben regresar 0, ya que no hay tarjetas de mayor o menor que la tarjeta hacia arriba en la baraja

Además, no hay necesidad de declarar cada función abstract en una interfaz, que es automático y requiere

+0

Interesante (y punto correcto) sobre el final del juego, ¡debería haberlo pensado! Sin embargo, estoy buscando soluciones alternativas al uso de Excepciones, incluso cambiando drásticamente mi diseño. – Peter

+0

Para que quede claro, sé que no tiene que declarar métodos de interfaz como abstractos, Eclipse lo hizo automáticamente (por alguna razón) cuando extraje la interfaz. ** desea que pueda editar los comentarios ** – Peter

+0

@Peter Puede, pero solo por cinco minutos :) –

1

No quiero que el constructor dibuje automáticamente una tarjeta. Esto significa que inicialmente no hay una "tarjeta dibujada previamente". Tengo un valor SIN PREDICCIÓN en la enumeración Predicción pero, como no hay una "tarjeta dibujada previamente", los métodos getNumberCardsHigher() y getNumberCardsLower() no pueden devolver valores sanos (tampoco pueden devolver valores sanos cuando todas las cartas del mazo se han dibujado).

creo que surja la confusión API del hecho de que su interfaz de PlayYourCardsRight está tratando de modelar dos cosas separadas: el motor del juego/reglas y la baraja de cartas. Movería el estado de la baraja de cartas y los métodos de conteo de cartas restantes a una clase Deck. Cambiaría la API a getNumberCards[Higher/Lower](Card) y dejaría que el motor del juego especificara la carta con la que desea comparar en lugar de esperar que el mazo recuerde qué carta fue extraída al final, que yo vería como un elemento del estado del juego, no del mazo.

Y recomiendo escribir algunas pruebas JUnit. TDD ayuda a producir una API cohesiva y desacoplada.

Cuestiones relacionadas