A ver, primero hacemos que
Carta implemente la interfaz
ComparableSi lo hacemos así:
public class Carta implements Comparable {
No estamos especificando con que clase puede compararse y por lo tanto el método compareTo() que hay que implementar, pedirá recibir un objeto de clase
ObjectObject es algo así como la superclase suprema de la que TODAS las clases Java son hijas, sí o sí...
@Override
public int compareTo(Object o) {
// Código para comparar cartas
return 0;
}
}
Se puede hacer así, si nos interesase que una
Carta pudiera compararse con cualquier otra cosa, aunque no sea una
CartaPero no es lo que nos interesa, mejor si especificamos al implementar la interfaz, que la clase
Carta se ha de comparar, pues con otras
Cartas y no con cualquier cosa...
public class Carta implements Comparable<Carta> {
Ahora sí, el método que hay que implementar, pedirá recibir un objeto
Carta, que es lo único con lo que va a poder compararse.
@Override
public int compareTo(Carta otraCarta) {
// Código para comparar cartas
return 0;
}
Bien, ahora hay que escribir el cuerpo de ese método.
Dijimos que una Carta, por defecto, se ha ordenar de forma natural, primero por orden de palo y luego por orden de valor de carta.
Es decir, usamos la misma lógica que usamos en la clase
OrdPalNumInc, solo hay que adaptar un poco el código.
Seguimos teniendo que usar el "truco" de acceder al array público de la clase
Baraja para saber el valor aritmético de cada carta, ya que el atributo "valor" de la clase
Carta es un String, y no un int/Integer.
Es un poco chapuza, la clase
Carta debería ser capaz de poder compararse sin tener que recurrir a elementos de otra clase.
Pero no nos queda otra, no hemos decidido nosotros los atributos de esta clase.
Este sería el código:
@Override
public int compareTo(Carta otraCarta) {
if (otraCarta.equals(this)) {
return 0; //Cartas son iguales
}
else {
if (this.palo.equals(otraCarta.palo)) {
//Mismo palo, el orden depende del valor de las cartas
/*
* El atributo "numero" de las Cartas es un String, no es un Integer.
* Esto significa que no podemos comparar directamente esos atributos, porque en realidad
* no son números, y necesitamos lograr un orden aritmético.
*
* Por suerte, la clase Baraja tiene un array público con los nombres de estos "números"
* en el orden correcto.
* Así que podemos usar la posición que ocupa cada "nombre de número" en el array para obtener
* unos valores enteros con los que poder comparar de forma aritmética
*/
int posiC1 = 0, posiC2 = 0;
for (int i = 0; i < Baraja.numeros.length; i++) {
if (this.numero.equals(Baraja.numeros[i]))
posiC1 = i;
if (otraCarta.numero.equals(Baraja.numeros[i]))
posiC2 = i;
}
//Tenemos sus posiciones numéricas, podemos compararlas para decidir el orden.
if (posiC1 == posiC2)
return 0; //Número es igual
else if (posiC1 < posiC2)
return -1; //c1 es menor que c2
else
return 1; //c2 es menor que c1
}
else //Los palos son distintos, aquí no importa el número de carta, el orden depende los palos
return this.palo.compareTo(otraCarta.palo);//Retornamos la comparación por defecto de Strings
}
}
Bien, gracias a esto, resulta que ahora la clase
Mazo ya puede prescindir de aquel atributo que era una clase chusquera, si se me permite el comentario, llamada
AlgoritmoOrdenacionpublic class Mazo {
List cartas;
private AlgoritmoOrdenacion algoritmo;
Podemos quitarle ese atributo y también el método que lo seteaba
public void setAlgoritmo(AlgoritmoOrdenacion algoritmo) {
this.algoritmo = algoritmo;
}
Ahora la clase
Carta ya posee su propio algoritmo de ordenación gracias a la interfaz
Comparable, así ya puede ordenarse por sí sola mediante este método:
public class Mazo {
List cartas;
public void ordena() {
cartas.sort(null);
}
Como dije antes, si al
List que contiene las cartas le pedimos que las ordene invocando su método
sort() y a este le indicamos valor null como argumento, entonces el
List aplicará el algoritmo de ordenación que tienen las propias
CartasSi lo probamos con un nuevo
Main, veremos que el mazo se ordena correctamente de forma "natural":
public class Main {
public static void main(String[] args) {
Baraja baraja = new Baraja();
Mazo mazo = baraja.getMazo();
System.out.println("Baraja original: ");
System.out.println(mazo.toString());
mazo.ordena();
System.out.println("\nOrdenado NATURAL(por palo y numero incrementando): ");
System.out.println(mazo.toString());
}
}
OK, pero esto es solo la primera parte de lo que nos piden.
Lo que también se desea, es que la clase
Mazo sobrecargue el método ordena() de forma que podamos enviarle de forma externa un objeto que implemente un
Comparator, es decir, una forma de enviarle algoritmos de ordenación distintos al que posee la clase
Cartapublic class Mazo {
List cartas;
public void ordena() {
cartas.sort(null);
}
public void ordena(Comparator comparador) {
cartas.sort(comparador);
}
Pues ahora hay que escribir estas distinas clases que implementen
Comparator.
Se pueden escribir por separado. Pero, para tener un poco más de orden, se puede crear una sola clase que en su interior tengamos anidadas estas otras clases de tipo
ComparatorPodemos empezar con la clase que ordena de forma natural, pero decreciente.
Es decir, primero ordena por palos y luego por número de carta, pero esta vez, el número de carta se ordenará de mayor a menor..
El código es prácticamente el mismo de antes, pero invirtiendo los valores que se retornan al comparar número para hacer que sea
decreciente, en lugar de
creciente:
import java.util.Comparator;
public class ComparadoresDeCartas {
//Primer algortimo alternativo de ordenacion
public static class PorPaloYNumeroDecreciente implements Comparator<Carta> {
@Override
public int compare(Carta carta1, Carta carta2) {
if (carta1.equals(carta2)) {
return 0; //Cartas son iguales
}
else {
if (carta1.getPalo().equals(carta2.getPalo())) {
//Mismo palo, el orden depende del valor de las cartas
int posiC1 = 0, posiC2 = 0;
for (int i = 0; i < Baraja.numeros.length; i++) {
if (carta1.getNumero().equals(Baraja.numeros[i]))
posiC1 = i;
if (carta2.getNumero().equals(Baraja.numeros[i]))
posiC2 = i;
}
//Tenemos sus posiciones numéricas, podemos compararlas para decidir el orden.
if (posiC1 == posiC2)
return 0; //Número es igual
else if (posiC1 < posiC2)
return 1; //c1 es menor que c2, devolvemos positivo para tener orden decreciente
else
return -1; //c2 es menor que c1, devolvemos negativoo para tener orden decreciente
}
else //Los palos son distintos, aquí no importa el número de carta, el orden depende los palos
return carta1.getPalo().compareTo(carta2.getPalo());//Retornamos la comparación por defecto de Strings
}
}
}
}
Fíjate que la clase anidada la declaramos como
static. Esto es necesario para poder invocarla sin tener que crear previamente un objeto de clase
ComparadoresDeCartas.
Podremos crear directamente objetos de la clase anidada, llamándola así en el
Mainpublic class Main {
public static void main(String[] args) {
Baraja baraja = new Baraja();
Mazo mazo = baraja.getMazo();
System.out.println("Baraja original: ");
System.out.println(mazo.toString());
mazo.ordena();
System.out.println("\nOrdenado NATURAL(por palo y numero incrementando): ");
System.out.println(mazo.toString());
mazo.ordena(new ComparadoresDeCartas.PorPaloYNumeroDecreciente());
System.out.println("\nOrdenado por palo y numero decrementando: ");
System.out.println(mazo.toString());
}
}
Siguiendo con el ejemplo, a esta clase que hemos creado, podemos añadirle una segunda clase
Comparator anidada con otro algoritmo más de ordenación:
public class ComparadoresDeCartas {
//Primer algortimo alternativo de ordenacion
public static class PorPaloYNumeroDecreciente implements Comparator<Carta> {
@Override
public int compare(Carta carta1, Carta carta2) {
if (carta1.equals(carta2)) {
return 0; //Cartas son iguales
}
else {
if (carta1.getPalo().equals(carta2.getPalo())) {
//Mismo palo, el orden depende del valor de las cartas
int posiC1 = 0, posiC2 = 0;
for (int i = 0; i < Baraja.numeros.length; i++) {
if (carta1.getNumero().equals(Baraja.numeros[i]))
posiC1 = i;
if (carta2.getNumero().equals(Baraja.numeros[i]))
posiC2 = i;
}
//Tenemos sus posiciones numéricas, podemos compararlas para decidir el orden.
if (posiC1 == posiC2)
return 0; //Número es igual
else if (posiC1 < posiC2)
return 1; //c1 es menor que c2, devolvemos positivo para tener orden decreciente
else
return -1; //c2 es menor que c1, devolvemos negativoo para tener orden decreciente
}
else //Los palos son distintos, aquí no importa el número de carta, el orden depende los palos
return carta1.getPalo().compareTo(carta2.getPalo());//Retornamos la comparación por defecto de Strings
}
}
}
//Segundo algoritmo de ordenacion
public static class PorNumeroIncrementalYPalo implements Comparator<Carta> {
@Override
public int compare(Carta carta1, Carta carta2) {
if (carta1.equals(carta2)) //Cartas son iguales
return 0;
else {
if (carta1.getNumero() == carta2.getNumero()) //Mismo número, se ordenará por palo
return carta1.getPalo().compareTo(carta2.getPalo());
else {//Distinto número de carta
//Averiguamos el valor de estas cartas según posición en el array
int posiC1 = 0, posiC2 = 0;
for (int i = 0; i < Baraja.numeros.length; i++) {
if (carta1.getNumero().equals(Baraja.numeros[i]))
posiC1 = i;
if (carta2.getNumero().equals(Baraja.numeros[i]))
posiC2 = i;
}
//Tenemos sus posiciones numéricas, podemos compararlas para decidir el orden.
if (posiC1 == posiC2)
return 0; //Número es igual
else if (posiC1 < posiC2)
return -1; //c1 es menor que c2
else
return 1; //c2 es menor que c1
}
}
}
}
}
Y en el Main volvemos a llamarlo del mismo modo:
public class Main {
public static void main(String[] args) {
Baraja baraja = new Baraja();
Mazo mazo = baraja.getMazo();
System.out.println("Baraja original: ");
System.out.println(mazo.toString());
mazo.ordena();
System.out.println("\nOrdenado NATURAL(por palo y numero incrementando): ");
System.out.println(mazo.toString());
mazo.ordena(new ComparadoresDeCartas.PorPaloYNumeroDecreciente());
System.out.println("\nOrdenado por palo y numero decrementando: ");
System.out.println(mazo.toString());
mazo.ordena(new ComparadoresDeCartas.PorNumeroIncrementalYPalo());
System.out.println("\nOrdenado por numero y palo incrementando: ");
System.out.println(mazo.toString());
}
}
Y de esta forma podríamos contener en una única clase, todos los algoritmos de ordenación que se nos ocurriesen.
Y se los podemos hacer llegar al
Mazo mediante el método
ordena() que hemos "sobrecargado"
Espero que se haya entendido la explicación.
Saludos.