2009-12-07 29 views
15

Usted está escribiendo un programa Tetris en Java. ¿Cómo configuraría su diseño de clase con respecto a los siguientes aspectos?Preguntas de diseño filosófico para OOP-Tetris

  • clase Piece: Tener uno Piece clase, con una matriz interna que determina la forma de la pieza, frente a tener siete Piece clases, una para cada una de las piezas. Todas son subclases de una clase genérica Piece.
  • representación de la clase Piece: tienen una serie de 4 casos de Block, lo que representa un cuadrado de una pieza, y cada Block contiene su ubicación en la Junta (en coordenadas gráficas) frente a tener una matriz de 4x4, donde null significa que hay no hay bloque allí, y la ubicación está determinada por la forma de la matriz.
  • Ubicación: Cada BlockPiece en la matriz o en la matriz Board almacena su ubicación frente a la Piece y la Board conocer las ubicaciones de la Blocks que los componen.
  • Generación de una pieza: tener un método estático de la clase pieza getRandomPiece, o tener un PieceFactory que hacer una instancia de que tiene el método genRandomPiece en la instancia.
  • La manipulación de la pieza actual: Utilice el patrón Proxy, por lo que todo lo que necesita tener acceso a ella sólo utiliza el proxy, o tener un método getCurrentPiece en la clase Board y llamar a que cada vez que quiere hacer algo con la corriente pieza.

Esto no es tarea. Estoy en desacuerdo con lo que el curso introductorio de CS enseña en mi universidad y quiero ver lo que la gente en general cree. ¿Qué se consideraría como un "buen" diseño OOP? Ignore el hecho de que es para un curso introductorio: ¿cómo lo haría ?

+2

debería ser wiki de la comunidad – Malfist

+1

Todas estas clases y esas cosas ... podría estar haciendo que el problema sea demasiado abstracto para lo que realmente es. Muchas formas diferentes de representar piezas de tetris (http://stackoverflow.com/questions/233850/tetris-piece-rotation-algorithm) y muchas formas diferentes de manipularlas. Si es para un curso de * introducción, no me preocuparé por OOP. Solo mi opinión, no es una respuesta real a tu pregunta. –

+0

@roygbiv: publique este comentario como una respuesta! Creo que al menos tendrías una o dos clases – Claudiu

Respuesta

10

En primer lugar, no subclase la clase Piece porque no es necesario. La clase Piece debe ser capaz de describir cualquier forma sin usar herencia. En mi humilde opinión, esto no es para lo que se hizo la herencia y simplemente complica las cosas.

En segundo lugar, no almacenaría las coordenadas x/y en los objetos Block porque permite que existan dos bloques en el mismo lugar. Las clases Piece mantendrían una cuadrícula (es decir, una matriz 2D) que contiene los objetos de bloque. Las coordenadas x/y serían los índices de la matriz 2D.

En cuanto al método estático vs objeto de fábrica para obtener una pieza al azar, iría con el objeto de fábrica por el simple hecho de que el objeto de fábrica puede ser burlado para la prueba.

Yo trataría el tablero como un gran objeto Piece. La clase Board mantendría el objeto grande Piece como una variable miembro, y podría mantener otros objetos Piece tales como la pieza actual que se está reproduciendo y la siguiente pieza que se reproducirá. Esto se hace usando la composición para evitar la herencia.

+3

+1 La herencia es innecesaria, incluso dañina, porque queremos que todas las piezas tengan el mismo comportamiento. Las piezas solo difieren en su forma y color. La única instancia en la que puedo pensar que desearía un comportamiento especial es algo así como la puntuación extra de "t-spin" en Tetris DS, pero podría tratarse mejor como un caso especial en el código de puntuación. No use la jerarquía de clases como sustituto de la instrucción if() {}. – Theran

+0

¿Puedes explicar la última oración? Cuando dijiste que el tablero sería una Pieza grande que contendría otra Pieza, asumí automáticamente la herencia – Claudiu

+1

Tienes razón, no está nada claro. La junta mantendría la "una pieza grande" como variable miembro. –

3
  • Una Piece interfaz, con siete clases que implementan la interfaz de las piezas individuales (que también permitiría el curso programación orientada a objetos para discutir las interfaces) (EDIT:. Una Piece clase Véanse los comentarios)
  • Tendría una clase BlockGrid que se puede usar para cualquier mapa de bloques, tanto el tablero como las piezas individuales. BlockGrid debe tener métodos para detectar las intersecciones - por ejemplo, boolean intersects(Block block2, Point location) -, así como para girar una rejilla (punto interesante discusión para el curso:? Si el Board no tiene que girar, debe ser un método rotate() en BlockGrid). Para una Pieza, BlockGrid representaría una cuadrícula de 4x4.
  • me gustaría crear un PieceFactory con un método getRandomShape() para obtener una instancia de una de las siete formas
  • Para la manipulación de la pieza, me gustaría conseguir en una arquitectura Modelo-Vista-Controlador. El modelo es la pieza. El controlador es quizás un PieceController, y también permitiría o no permitir movimientos legales/ilegales.Lo que mostraría la pieza en la pantalla es una PieceView(gestión de recursos humanos, o es una que puede mostrar Piece.getBlockGrid()? Otro punto de discusión!)

Existen múltiples maneras legítimas de arquitecto esta. Sería beneficioso para el curso tener discusiones sobre los pro y los contras de los diferentes principios de OOP aplicados al problema. De hecho, podría ser interesante comparar y contrastar esto con una implementación no OOP que solo usa matrices para representar el tablero y las piezas.

EDIT:Claudiu ayudó a darme cuenta de que el BlockGrid sería suficientemente diferenciar piezas, así que no hay necesidad de una interfaz Piece con múltiples subclases; más bien, una instancia de Piececlase puede diferir de otras instancias según su BlockGrid.

+2

+1 para la idea de comparar y contrastar con una solución que no sea de OO en lugar de solo insistir en el diseño de OO sin una discusión seria de las compensaciones involucradas. – dsimcha

+0

¿Se da cuenta de que dado que BlocKGrid es solo una interfaz, escribirá 7 funciones de detección de colisiones separadas con el diseño que ha presentado aquí? ¿Además de 7 funciones de rotación separadas? ¿Realmente lo harías de esta manera? – Claudiu

+0

Quizás no estaba claro al definir BlockGrid. BlockGrid es esencialmente una n * n matriz de bits. La función de detección de colisión sería similar a decir, "if ((array1 (x, y) == TRUE) && (array2 (x, y) == TRUE)) {colisión = TRUE;}" (con la matemática adecuada para la compensación) la ubicación de un BlockGrid sobre otro) –

2

Clase de pieza: Creo que una sola clase para todas las piezas es suficiente. Las funciones de clase deberían ser lo suficientemente generales como para funcionar para cualquier pieza, por lo que no es necesario crear una subclase.

Pieza Representación de clase: Creo que una matriz de 4x4 es probablemente una mejor manera, ya que entonces le resultará mucho más fácil rotar la pieza.

Ubicación: La ubicación definitivamente debe ser almacenada por la placa, no la pieza, ya que de lo contrario tendría que pasar por todo el conjunto de bloques para asegurarse de que no haya dos bloques en la misma posición.

Generando una Pieza: Honestamente para esta, no creo que vaya a marcar una gran diferencia. Habiendo dicho eso, preferiría una función estática ya que realmente no es tanto para esta función que merece su propia clase.

Manipulando la pieza actual: Simplemente implementaría una función getCurrent ya que creo que no hay necesidad de complicar demasiado el problema agregando una clase extra para servir como proxy.

Así es como lo haría, pero hay muchas maneras diferentes, y al final del día, lo que debe centrarse es simplemente poner en marcha el programa.

3

Todas estas clases y esas cosas ... podría estar haciendo que el problema sea demasiado abstracto para lo que realmente es. Muchas formas diferentes de representar piezas de tetris (stackoverflow.com/questions/233850/...) y muchas formas diferentes de manipularlas. Si es para un curso introductorio, no me preocuparía por OOP. Solo mi opinión, no es una respuesta real a tu pregunta.

Una vez dicho esto, uno podría ser suficiente con una simple pieza de la Junta y de clase.

Clase de placa: Encapsula una matriz simple de 2d de rectángulos. Propiedades como pieza actual, accesorio. Rutinas como draw(), fullrows(), drop(), etc. que manipulan la pieza actual y los cuadrados de la tabla rellenos.

Clase de pieza: Encapsula una matriz de números de 16 bits sin signo que codifica las piezas en sus diversas rotaciones. Haría un seguimiento del color, la ubicación actual y la rotación. Quizás una rutina, rotar() sería necesaria.

El resto, sería, en función del entorno, el manejo de eventos de teclado, etc ...

que he encontrado que la colocación de también mucho énfasis en el diseño tiende a hacer que la gente se olvida de que lo que realmente necesitan hacer es obtener algo ejecutándose. No digo que no diseñe, estoy diciendo que la mayoría de las veces, hay más valor en hacer que algo funcione, dándole tracción y motivación para seguir adelante.

Diría que para la clase, tienes X horas para hacer un diseño para un juego de tetris. Entonces tendrían que entregar ese diseño. Entonces yo diría que tiene X días para obtener algo ejecutándose según el diseño que entregó o incluso no según el diseño.

Cuestiones relacionadas