PROG3 - Práctica 5

Práctica 5

Plazo de entrega: Hasta el domingo 26 de diciembre de 2021 a las 23:59h
Peso relativo de está práctica en la nota de prácticas: 10%
IMPORTANTE: Todos tus ficheros de código fuente deben utilizar la codificación de caracteres UTF-8. No entregues código que use otra codificación (como Latin1 o iso-8859-1).

Aclaraciones

ImperialCommander: reflexión y genericidad

Introducción

El diseño propuesto para la práctica anterior tenía un problema que se resolverá en la actual: la factoría de cazas no estaba completamente abierta a la extensión, ya que añadir un nuevo tipo de caza implicaría añadir una nueva instrucción condicional o una nueva cláusula case a una instrucción switch. En esta práctica, este problema se arreglará introduciendo convenientemente la reflexión. Además, el modelo se ampliará con un sistema de clasificación que será capaz de reflejar las puntuaciones obtenidas durante la cada partida y clasificarlas de acuerdo con dos criterios diferentes: la cantidad de victorias y el valor de los diferentes cazas destruidos.

Diagrama de clases

El siguiente diagrama de clases UML representa las clases de nuestro modelo. Solamente se muestran las clases nuevas (que pertenecen todas al paquete model.game.score), y los cambios en las clases de la práctica anterior.

Diagrama de clases UML.
Diagrama de clases UML.

 

Hoja de ruta

El orden aconsejado para ir construyendo tu práctica es:

Recuerda, ve diseñando pruebas unitarias según vayas terminando cada clase, y utilízalas para depurar tu código antes de pasar a la siguiente clase.

Cambios en las clases de la práctica anterior

Los cambios que debes hacer en las clases de la práctica anterior son:


Reflexión

Tienes que reemplazar las instrucciones condicionales o el switch existente en FighterFactory.createFighter(-) con código que utilice la reflexión para crear una instancia de un objeto cuyo nombre de clase coincida con el parámetro type; tendrás que calificar completamente el nombre de la clase a cargar añadiendo convenientemente el nombre del paquete, es decir, si el nuevo tipo es FWing, el nombre de la clase será model.fighters.FWing

El método createFighter devolverá null como en la práctica anterior si el parámetro no contiene un nombre válido de caza; esta circunstancia se detectará cuando se lance alguna de las excepciones de los métodos de la API de reflexión, que deben capturarse e ignorarse para al final devolver null

El método createFighter está ahora abierto a la extensión (podemos añadir tipos de cazas sin modificar su código) pero cerrados a la modificación. Los nuevos tipos de cazas podrán utilizarse en la clase PlayerFile, pero no en PlayerRandom, que debe usar solamente los tipos de cazas de la práctica 3.

NOTA: si no lo has hecho ya, te recomendamos que visualices los vídeos sobre reflexión que hay en el Moodle de teoría de la asignatura

Sistema de clasificación y genericidad

Clase Score

La nueva clase abstracta Score encapsula el concepto de la puntuación de una partida. Como el objetivo es crear un sistema de clasificación, las puntuaciones deben ser comparables. Esto se logrará haciendo que Score implemente la interfaz de Java Comparable, en particular Comparable<Score<T>>, lo que obliga a la clase a implementar el método compareTo(-):

public abstract class Score<T> implements Comparable<Score<T>>{   
   ...   
}

El tipo T determinará el tipo de puntuación a definir, que será Integer para WinsScore, o Fighter para DestroyedFightersScore.

Las subclases no abstractas de Score implementarán el método score(-) que, cuando sea apropiado, incrementa el atributo score; valores más altos de esta puntuación significarán un mejor rendimiento del jugador. El atributo score se utilizará en el método Score.compareTo(-) para comparar dos puntuaciones diferentes.

Método Score(Side)

Constructor que almacena el bando recibido como argumento e inicializa el atributo score a cero.

Método toString()

Devuelve una representación en forma de cadena de caracteres del score (sin ‘\n’ al final). Para ello toma el bando del atributo side y la puntuación del atributo score. Ejemplo de salida para un jugador imperial con puntuación 7:

Player IMPERIAL: 7 

Método compareTo(Score<T>)

Este método compara dos puntuaciones por su valor. Como queremos implementar un orden descendente de las puntuaciones para la clasificación, dados dos objetos de tipo Score<T>, el que represente la mayor puntuación será considerado el más pequeño. Si ambos objetos tienen la misma puntuación el método devolverá lo que devuelva compareTo(·) al comparar los side de las puntuaciones (el bando IMPERIAL aparecerá antes que el bando REBEL). Como resultado obtendremos un orden de las puntuaciones: de la mayor a la menor. Echa un vistazo a la descripción del método compareTo(-) en la documentación de la API de Java 8 para saber lo que compareTo(-) debe devolver en cada caso (aunque igual lo recuerdas de la práctica 2).

Clase WinsScore

Esta clase representa un score basado en Integer y simplemente lleva la cuenta de las victorias obtenidas por la nave del jugador. Debe ser declarado como sigue:

public class WinsScore extends Score<Integer> {
   ...
}

Método WinsScore(Side)

Constructor que simplemente pasa el argumento recibido al constructor de su superclase.

Método score(Integer)

Este método incrementa el atributo score en 1 si el entero recibido como argumento es 1.

Clase DestroyedFightersScore

Esta clase representa una puntuación basada en Fighter y suma el valor de los diferentes cazas destruidos por la nave del jugador. Se declara de forma análoga a la de WinsScore pero usando Fighter en lugar de Integer.

Método DestroyedFightersScore(Side)

Constructor que simplemente pasa el argumento recibido al constructor de su superclase.

Método score(Fighter)

Este método incrementa el atributo score con el valor del caza recibido como argumento (si no es null), usando el método Fighter.getValue() descrito anteriormente.

Clase Ranking

Para tener un sistema de clasificación basado en las puntuaciones obtenidas por los diferentes jugadores, se añadirá una nueva clase RankingRanking es una clase genérica que tiene un parámetro de tipo restringido para evitar que puntuaciones de diferentes tipos coexistan en una clasificación particular:

public class Ranking<ScoreType extends Score<?>> {
   ...
}

Por lo tanto, un objeto de tipo Ranking tendrá que ser creado de una de dos maneras, ya sea como

Ranking<WinsScore> rh = new Ranking<>();

o como

Ranking<DestroyedFightersScore> rc = new Ranking<>();

Por consiguiente, un error del compilador impedirá que el código del cliente añada puntuaciones de diferentes criterios al mismo objeto de clasificación (pruébalo cuando ya tengas estas clases implementadas). Nótese que a partir de Java 7 los argumentos de tipo requeridos para invocar al constructor de una clase genérica pueden ser reemplazados por un conjunto vacío (el par de corchetes angulares se llama el diamante) siempre que el compilador pueda inferir los tipos a partir del contexto.

Método Ranking()

Este método sólo inicializa el atributo scoreSet (de clase TreeSet); scoreSet debe ser declarado de la siguiente manera:

private SortedSet<ScoreType> scoreSet;

y se inicializa así en el constructor:

scoreSet = new TreeSet<>();

Asegúrate de que entiendes las líneas anteriores.

Método addScore(ScoreType)

Este método añade el objeto pasado como parámetro al conjunto scoreSet. Obsérvese que scoreSet es un conjunto ordenado y, en consecuencia, se invocará el método compareTo(-) de Score para tener ordenados los elementos del conjunto.

Método getWinner()

Devuelve el primer elemento del conjunto scoreSet.

Excepciones: Si el conjunto está vacío, la excepción RuntimeException será lanzada.

Método Ranking.getSortedRanking()

Un simple getter.

toString()

Devuelve una cadena formada por las puntuaciones del ranking, rodeada con |. Por ejemplo, para un ranking de WinsScore en el que el jugador rebelde lleva 7 victorias y el imperial 6, debería devolver:

| Player REBEL: 7 | Player IMPERIAL: 6 |

Ten en cuenta que la cadena Player REBEL: 7 se genera en el método toString de la clase Score

Programa principal

Los programas principales de la práctica 4 MainP4.java y MainP4min.java son perfectamente válidos para esta práctica, lo que cambia es la salida de ambos por la introducción de los rankings: salida-MainP4-p5.txt y salida-MainP4min-p5.txt


Pruebas unitarias

El archivo prog3-ImperialCommander-p5-pretest.tgz contiene una carpeta pretestp5 con un paquete model con pruebas unitarias, algunas de ellas usan ficheros que están en la carpeta files, como en la práctica anterior.

Documentación

Debéis incluir en los ficheros fuente todos los comentarios necesarios en formato Javadoc. Estos comentarios deben definirse para:  

No se debe entregar los ficheros HTML que genera Javadoc, y tampoco debes generar la documentación automáticamente con plugins, es una buena práctica generar la documentación a mano, justo en el momento en que se empieza a escribir el método.

Estructura de paquetes y directorios

En esta práctica crearemos un nuevo paquete:

Requisitos mínimos para evaluar la práctica

Entrega de la práctica

La práctica se entrega en el servidor de prácticas del DLSI.

Debes subir allí un archivo comprimido que incluya el directorio model y toda la estructura de directorios y ficheros fuente tal y como se especifica en la práctica. En un terminal, sitúate en el directorio ‘src’ de tu proyecto Eclipse e introduce la orden

tar czvf prog3-imperialCommander-p5.tgz model

Sube este fichero prog3-imperialCommander-p5.tgz al servidor de prácticas. Sigue las instrucciones de la página para entrar como usuario y subir tu trabajo.

Evaluación 

La corrección de la práctica es automática. Esto significa que se deben respetar estrictamente los formatos de entrada y salida especificados en los enunciados, así como la interfaz pública de las clases, tanto en la signatura de los métodos (nombre del método, número, tipo y orden de los argumentos de entrada y el tipo devuelto) como en el funcionamiento de éstos. Así, por ejemplo, el método model.Coordinate(int,int) debe tener exactamente dos argumentos de tipo int.

Tienes más información sobre el sistema de evaluación de prácticas en la ficha de la asignatura.

Además de la corrección automática, se va a utilizar una aplicación detectora de plagios. Se indica a continuación la normativa aplicable de la Escuela Politécnica Superior de la Universidad de Alicante en caso de plagio:

“Los trabajos teórico/prácticos realizados han de ser originales. La detección de copia o plagio supondrá la calificación de”0" en la prueba correspondiente. Se informará la dirección de Departamento y de la EPS sobre esta incidencia. La reiteración en la conducta en esta u otra asignatura conllevará la notificación al vicerrectorado correspondiente de las faltas cometidas para que estudien el caso y sancionen según la legislación vigente".