Autor Tema: Interfaces  (Leído 3347 veces)

drate

  • Sin experiencia
  • *
  • APR2.COM
  • Mensajes: 24
    • Ver Perfil
Interfaces
« en: 23 de Mayo 2023, 19:37 »
Buenas tardes. Estoy tratando de implementar el apartado del método que devuelve la subsecuencia pero no consigo retornar un array de char vacío en caso de igualdad de índices. Dejo copia de ejercicio.
Muchas gracias, un saludo.

public interface CharSequenceTokio {
   
   
    int length();

    /**
     * Devuelve el char que se situa en el índice indicado por index.
     * Un índice válido toma valores entre 0 y length() - 1.
     * Si el índice no es válido se devuelve el caracter cero (char con valor cero)
     *
     * @param   index   índice del char a ser devuelto.
     * @return  el char localizado en index o el char con valor cero si el índice es incorrecto.
     */
    char charAt(int index);

    /**
     * Devuelve una nueva CharSequenceTokio que es un subsecuencia de esta secuencia.
     * La subsecuencia empieza en el caracter situado en la posición start y acaba
     * en el caracter situado en la posición end - 1.
     * Si start == end se devuelve un CharSequenceTokio sin caracteres.
     * Si start no es una posición válida o si end no es una posición válida o si
     * start > end se devuelve un objeto nulo (null).
     *
     * @param   start   el índice de comienzo, incluído.
     * @param   end     el índice de fin, excluído
     * @return  La subsecuencia especificada o null si los índices no son válidos.
     */
    CharSequenceTokio subSequence(int start, int end);

    /**
     * Devuelve una representación con forma de String de la secuencia de caracteres.
     * La longitud del String será igual a la longitud de la secuencia.
     * @return  Un String que contiene exactamente la secuencia de caracteres.
     */
    public String toString();

}



CharSequenceTokio es un interfaz que representa el comportamiento de una secuencia leíble de elementos de tipo char. Su
funcionamiento es similar a la clase CharSequence de Java, pero como hemos cambiado ligeramente su comportamiento
preferimos renombrarla a CharSecuenceTokio.
Los métodos que incluye CharSequenceTokio son:

• int length()  Devuelve la longitud de esta secuencia de caracteres.
• char charAt(int index)  Devuelve el char que se sitúa en el índice indicado por index. Si el índice no es válido se
devuelve el valor cero directamente
• CharSequenceTokio subSequence(int start, int end)  Devuelve una nueva CharSequenceTokio que es un subsecuencia
de esta secuencia. La subsecuencia empieza en el carácter situado en la posición start y acaba en el carácter situado
en la posición end - 1. Si las posiciones no son válidas devuelve un objeto nulo (null).
• public String toString()  Devuelve una representación con forma de String de la secuencia de caracteres.
 CharSequenceTokio
Define dos clases implementadoras del interfaz CharSequenceTokio: ArrayCharSequenceTokio y BackwardsStringSequenceTokio
• ArrayCharSequenceTokio: Admite en el constructor un array de chars e implementa CharSequenceTokio con dicho array de chars.
• BackwardsStringCharSequenceTokio: Admite en el constructor un String e implementa CharSequenceTokio de dicho String pero
dado la vuelta (leído del final al principio).

Kabuto

  • Moderador Global
  • Experto
  • *******
  • Mensajes: 988
    • Ver Perfil
Re: Interfaces
« Respuesta #1 en: 24 de Mayo 2023, 12:01 »
Hola.

Puedes retornar un array de char vacío así:
Código: [Seleccionar]
return new char[] {};
O también:
Código: [Seleccionar]
return new char[0]
Sin embargo, en ese método no puedes retornar ningún array char, ya que su tipo es CharSequenceTokio
Citar
CharSequenceTokio subSequence(int start, int end);

Así que has de devolver un objeto de tipo CharSequenceTokio.

Pero, la cosa se complica un poco más, porque CharSequenceTokio es solo una interfaz, en su interior no contiene ningún array de char.
Por lo tanto, lo que has de retornar es algún tipo de clase que sí contenga como atributo un array de char, y además, implemente la interfaz CharSequenceTokio

Por tanto, lo que puedes retornar es un objeto de la clase ArrayCharSequenceTokio, que es la misma clase donde estás implementando dicho método.
A este objeto le pasarás por su constructor un array de char vacío en caso de igualdad de índices, o un array de con una secuencia de char si los índices de inicio y fin son correctos.

Te dejo aquí como he escrito yo la clase ArrayCharSequenceTokio por si quieres verla, aunque antes lo ideal es que hagas tú un par de intentos por tu cuenta a ver si lo consigues:
Código: [Seleccionar]
public class ArrayCharSequenceTokio implements CharSequenceTokio {

private char[] secuencia;

public ArrayCharSequenceTokio(char[] secuencia) {
this.secuencia = secuencia;
}

@Override
public int length() {
return secuencia.length;
}

@Override
public char charAt(int index) {
if (index < 0 || index >= length())
return '0';
else
return secuencia[index];
}

@Override
public CharSequenceTokio subSequence(int start, int end) {
//Start no valido
if (start < 0 || start >= length())
return null;
//End no valido
if (end < 0 || end >= length())
return null;
//Start mayor que end
if (start > end)
return null;
//Start es igual que end
if (start == end) {
return new ArrayCharSequenceTokio(new char[0]);//Array sin caracteres
}
//Indices válidos
char[] subSecuencia = new char[end+1 - start];
for (int i = start; i < end; i++)
subSecuencia[i] = secuencia[i];

return new ArrayCharSequenceTokio(subSecuencia);
}

@Override
public String toString() {
StringBuilder cadena = new StringBuilder();
for (char caracter: secuencia)
cadena.append(caracter);

return cadena.toString();
}

}

Y aquí una clase main() de prueba para comprobar su funcionamiento.
Fíjate que para obtener la subsecuencia, es necesario hacer un casting, ya que el tipo del método es CharSequenceTokio(interfaz) pero el objeto con el que se puede trabajar es ArrayCharSequenceTokio(clase)
Código: [Seleccionar]
public class Prueba {

public static void main(String[] args) {

Scanner teclado = new Scanner(System.in);
ArrayCharSequenceTokio secuencia = new ArrayCharSequenceTokio(new char[] {'v','e','l','o','z'});

System.out.println("Secuencia original: " + secuencia);

System.out.print("\nElija una posicion de la secuencia entre 0 y " + (secuencia.length()-1) +  ": ");
int c1 = teclado.nextInt();
System.out.println("Caracter obtenido: " + secuencia.charAt(c1));

System.out.println("\nElija ahora posiciones de inicio y fin para hacer una subcadena.");
System.out.print("Inicio: ");
int start = teclado.nextInt();
System.out.print("Fin: ");
int end = teclado.nextInt();

ArrayCharSequenceTokio subCadena = (ArrayCharSequenceTokio) secuencia.subSequence(start, end);
if (subCadena == null)
System.out.println("Indices no validos");
else {
System.out.println("Subcadena obtenida: " + subCadena);
System.out.println("Longitud de subcadena: " + subCadena.length());
}

System.out.println("\n\t\tFIN DE PROGRAMA");
teclado.close();
}

}

Un saludo.
« Última modificación: 24 de Mayo 2023, 12:04 por Kabuto »
NO respondo dudas por mensaje privado
Publicando vuestras dudas en el foro público conseguimos:
- Que más gente aporte respuestas mejores o complementarias.
- Que otras personas puedan aprender de vuestras dudas.

Mejor en PÚBLICO que en privado. Gracias

drate

  • Sin experiencia
  • *
  • APR2.COM
  • Mensajes: 24
    • Ver Perfil
Re: Interfaces
« Respuesta #2 en: 06 de Junio 2023, 12:54 »
Buenos días.
Haciendo la segunda parte de este ejercicio no consigo devolver la subcadena usando la interfaz BackwardsStringSequenceTokio.
Dejo el código. Muchas gracias, un saludo.

public class Prueba2 {

   public static void main(String[] args) {
      Scanner teclado = new Scanner(System.in);
      System.out.print("Escriba un string: ");
      String entrada = teclado.nextLine();
      System.out.print("Entrada original: "+ entrada);
      System.out.println();
      System.out.print("Cadena invertida: ");
      BackwardsStringSequenceTokio p= new BackwardsStringSequenceTokio(entrada);
      System.out.println(p.salida);
      System.out.print("\nElija una posicion de la secuencia entre 0 y " + (entrada.length() - 1) + ": ");
      int c1 = teclado.nextInt();
      System.out.println("Caracter obtenido: " + p.salida.charAt(c1));
      
      System.out.println("\nElija las posiciones de inicio y fin para hacer una subcadena.");
      System.out.print("Inicio: ");
      int start = teclado.nextInt();
      System.out.print("Fin: ");
      int end = teclado.nextInt();
      String aux= p.salida;

      BackwardsStringSequenceTokio subCadena=p.salida.subSequence(start, end);
      if (subCadena == null)
         System.out.println("Indices no validos");
      else {

         System.out.println("Subcadena obtenida: " );
         System.out.println("Longitud de subcadena: " + subCadena.length());
      }

      System.out.println("\n\t\tFIN DE PROGRAMA");
   
   }

Kabuto

  • Moderador Global
  • Experto
  • *******
  • Mensajes: 988
    • Ver Perfil
Re: Interfaces
« Respuesta #3 en: 06 de Junio 2023, 18:49 »
Bien, hay que crear una clase BackwardsStringSequenceTokio que será similar a la anterior pero esta vez invertirá el orden de los caracteres.

Dice que el constructor recibe un String. No me queda claro si por tanto, su atributo deberá ser también un String o un array de chars como su clase "hermana".

Yo lo voy a hacer con un String.
En el constructor, lo que hago es construir una cadena invertida a partir del String recibido y es lo que asigno al atributo. Así directamente este objeto ya tiene una cadena invertida.

El resto de métodos que hereda de la interfaz CharSequenceTokio son casi iguales a los de su clase "hermana", solo que adaptados para trabajar con String en lugar de un array de chars.

Hay un detalle importante en el método subSequence().
Al igual que hicimos en la clase "hermana", construimos una subsecuencia a partir del start y end que nos indican y retornamos un objeto de esta misma clase.

Pero está el problema de que en este caso, la clase BackwardsStringSequenceTokio invierte automáticamente la cadena que pide para ser construido.
Por tanto, estaremos retornando una subsecuencia con un orden distinto a la de la cadena de la que estamos extrayendo la subsecuencia.

Para evitarlo, lo que hago es construir esa subsecuencia en orden invertido, para que luego al retornar el objeto, se vuelva a invertir el orden y entonces ya sí la subcadena es retornada en el orden deseado
(Espero haberme explicado bien, es un poco lioso...)
Código: [Seleccionar]
public class BackwardsStringSequenceTokio implements CharSequenceTokio {

private String cadena;

public BackwardsStringSequenceTokio(String cadena) {
//Construimos una cadena invertida a partir del argumento recibido
StringBuilder invertida = new StringBuilder();
for (int i = cadena.length()-1; i >= 0; i--)
invertida.append(cadena.charAt(i));

//La asignamos al atributo
this.cadena = invertida.toString();
}

@Override
public int length() {
return cadena.length();
}

@Override
public char charAt(int index) {
if (index < 0 || index >= length())
return '0';
else
return cadena.charAt(index);
}

@Override
public CharSequenceTokio subSequence(int start, int end) {
//Start no valido
if (start < 0 || start >= length())
return null;
//End no valido
if (end < 0 || end >= length())
return null;
//Start mayor que end
if (start > end)
return null;
//Start es igual que end
if (start == end) {
return new BackwardsStringSequenceTokio("");//String vacío
}
//Indices válidos
/*
* Ahora construiremos una sub cadena y a partir de ella retornaremos
* un objeto BackwardsStringSequenceTokio.
* Sin embargo, estos objetos al crearse automáticamente invierten
* la cadena recibida, así que estaremos retornando una sub cadena
* con un orden distinto del deseado.
* Para evitarlo, vamos a crear la sub cadena usando un bucle invertido
* así al construir el objeto BackwardsStringSequenceTokio
* la subcadena será retornada con el orden deseado.
*/
String subCadena = "";
for (int i = end -1; i >= start; i--)
subCadena += cadena.charAt(i);

return new BackwardsStringSequenceTokio(subCadena);
}

@Override
public String toString() {
return cadena;
}

}


Si la ponemos a prueba con un main como el anterior, veremos que funciona.
La cadena original que le pasamos es invertida automáticamente y las subcadenas que extraemos conservan este orden invertido.
Código: [Seleccionar]
public static void main(String[] args) {

Scanner teclado = new Scanner(System.in);
BackwardsStringSequenceTokio secuencia = new BackwardsStringSequenceTokio("invertida");

System.out.println("Secuencia original: " + secuencia);

System.out.print("\nElija una posicion de la secuencia entre 0 y " + (secuencia.length()-1) +  ": ");
int c1 = teclado.nextInt();
System.out.println("Caracter obtenido: " + secuencia.charAt(c1));

System.out.println("\nElija ahora posiciones de inicio y fin para hacer una subcadena.");
System.out.print("Inicio: ");
int start = teclado.nextInt();
System.out.print("Fin: ");
int end = teclado.nextInt();

BackwardsStringSequenceTokio subCadena = (BackwardsStringSequenceTokio) secuencia.subSequence(start, end);
if (subCadena == null)
System.out.println("Indices no validos");
else {
System.out.println("Subcadena obtenida: " + subCadena);
System.out.println("Longitud de subcadena: " + subCadena.length());
}

System.out.println("\n\t\tFIN DE PROGRAMA");
teclado.close();
}


Resultado en pantalla:
Citar
Secuencia original: aditrevni

Elija una posicion de la secuencia entre 0 y 8: 4
Caracter obtenido: r

Elija ahora posiciones de inicio y fin para hacer una subcadena.
Inicio: 4
Fin: 8
Subcadena obtenida: revn
Longitud de subcadena: 4

      FIN DE PROGRAMA
NO respondo dudas por mensaje privado
Publicando vuestras dudas en el foro público conseguimos:
- Que más gente aporte respuestas mejores o complementarias.
- Que otras personas puedan aprender de vuestras dudas.

Mejor en PÚBLICO que en privado. Gracias

drate

  • Sin experiencia
  • *
  • APR2.COM
  • Mensajes: 24
    • Ver Perfil
Re: Interfaces
« Respuesta #4 en: 13 de Junio 2023, 18:18 »
Buenas tardes.
Se me plantea ahora modificar una práctica anterior haciendo uso de interfaces pero no veo claro el planteamiento. Dejo el código.
Muchas gracias, un saludo.

Siguiendo el ejemplo visto de las Cartas, las Barajas y los Mazos, modificamos Carta para que implemente Comparable
definiendo un “orden natural” para las cartas.
Un posible orden natural sería un orden primero por palos (por orden de lista) y luego por números (de forma ascendente).
Creamos clases que implementen Comparator para crear órdenes distintos al natural. Por ejemplo primero por números
(de forma ascendente) y luego por palos (por orden de lista).
Desde Mazo tendremos ahora dos métodos ordena. Uno que ordena según el orden natural de las cartas y otro que
ordena según un un comparator que se pasa por parámetro. Ambos métodos harán uso de los métodos sort de la clase
Collection.
public class Carta {

   private final  String numero;
   private final  String palo;
      
   public Carta(String numero, String palo) {
      this.numero = numero;
      this.palo = palo;
   }
   /**
    * @return the numero
    */
   public String getNumero() {
      return numero;
   }

   /**
    * @return the palo
    */
   public String getPalo() {
      return palo;
   }

   @Override
   public int hashCode() {
      int hash = 5;
      hash = 47 * hash + (this.numero != null ? this.numero.hashCode() : 0);
      hash = 47 * hash + (this.palo != null ? this.palo.hashCode() : 0);
      return hash;
   }

   @Override
   public boolean equals(Object obj) {
      if (this == obj) {
         return true;
      }

      if (obj == null) {
         return false;
      }
      if (getClass() != obj.getClass()) {
         return false;
      }
      final Carta other = (Carta) obj;
      if (this.numero != other.numero) {
         return false;
      }
      if (this.palo != other.palo) {
         return false;
      }
      return true;
   }

   @Override
   public String toString() {
      
      return numero + " " + palo;
   }

}

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class Mazo {

   List cartas;
   private AlgoritmoOrdenacion algoritmo;
   
   public void setAlgoritmo(AlgoritmoOrdenacion algoritmo) {
      // Establece el algoritmo de ordenación
      this.algoritmo = algoritmo;

   }

   public void ordena() {
      // Le pide al algoritmo que ordene
      if (algoritmo == null)
         System.out.println("No se ha establecido ningún algoritmo de ordenación");
      else
         algoritmo.ordena(cartas);

   }

   /**
    * Crea un mazo de cartas vacío
    */
   public Mazo() {
      cartas = new ArrayList();
   }

   /**
    * Devuelve la carta de una posición dada
    *
    * @param posicion La posición de la carta
    * @return La carta de dicha posición
    * @exception IllegalArgumentException si la posición no es válida en la lista
    */
   public Carta getCarta(int posicion) {
      return (Carta) cartas.get(posicion);
   }

   /**
    *
    * Añade una carta en el mazo en la posición dada. Las cartas que están después
    * de la posición dada avanzan una posición
    *
    * @param posicion Posición a añadir
    * @param carta    Carta a añadir
    * @exception IllegalArgumentException si la posición no es válida en la lista
    */
   public void insertarCarta(int posicion, Carta carta) {
      List<Carta> aux = new ArrayList<>();

      // Extraemos las cartas desde la posición dada a un array auxiliar
      for (int i = cartas.size() - 1; i >= posicion; i--) {
         aux.add((Carta) cartas.remove(i));
      }

      // Insertamos la carta pasada por parámetro
      cartas.add(carta);

      // Volvemos a insertar las cartas extraídas
      for (int i = aux.size() - 1; i >= 0; i--) {
         cartas.add(aux.get(i));
      }
   }

   /**
    * Extrae la carta de la posición dada, las demás cartas se corren una posición
    *
    * @param posicion Posición de extracción
    * @return Carta que estaba en dicha posición
    * @exception IllegalArgumentException si la posición no es válida en la lista
    */
   public Carta extraerCarta(int posicion) {
      return (Carta) cartas.remove(posicion);
   }

   /**
    * Devuelve la carta de la cima del mazo
    *
    * @return La carta en la cima del mazo
    */
   public Carta extraerCarta() {
      return (Carta) cartas.remove(cartas.size() - 1);
   }

   /**
    * Añade una carta al final del mazo
    *
    * @param carta Carta a añadir
    */
   public void anadirCarta(Carta carta) {
      cartas.add(carta);
   }

   /**
    * Devuelve el número de cartas del mazo
    *
    * @return número de cartas
    */
   public int numCartas() {
      return cartas.size();
   }

   public void barajar() {
      Collections.shuffle(cartas);
   }

   @Override

   public String toString() {
      return "" + cartas;
   }

}



Kabuto

  • Moderador Global
  • Experto
  • *******
  • Mensajes: 988
    • Ver Perfil
Re: Interfaces
« Respuesta #5 en: 14 de Junio 2023, 12:08 »
Lo que se pide es:
  • Por un lado, que la clase Carta implemente Comparable, haciendo que se ordenen de forma natural, primero por "palos" y luego por "número" de carta.
    Es decir, el mismo orden que usamos para la clase OrdPalNumInc
  • Y por otro lado, crear clases que implementen Comparator(ligeramente distinto a Comparable) donde cada una ordene de formas distintas a la "natural"

Esto es porque, aunque a una clase le enseñemos cómo ha de compararse (mediante Comparable), luego de forma externa podemos hacerle llegar otras reglas de comparación distintas(mediante Comparator)

Por tanto, nos proponen que la clase Mazo tenga dos métodos para ordenar.

Uno de esos métodos no recibe ningún parámetro
Para aplicar este orden, basta con pedirle al List de cartas que se ordene invocando su método sort().

Código: [Seleccionar]
public void ordena() {
    cartas.sort(null);
}

Al darle valor nulo como parámetro, aplicará el orden que digan las propias cartas, que es el que ellas "conocen" gracias a su Comparable.


El otro método, sí recibirá un objeto Comparator y se lo haremos llegar al método sort().
En este caso, ahora no son las cartas quienes deciden su orden, si no que se seguirán las reglas que marquen ese Comparator
Código: [Seleccionar]
public void ordena(Comparator comparador) {
    cartas.sort(comparador);
}
    Resumiendo, has de:
    • Implementar la interfaz Comparable a la clase Carta, para que se ordene de forma "natural"
    • Crear distintas clases que implementen Comparator, donde se apliquen reglas de ordenación distintas a la "natural"(ordenar primero por número y luego por palo, ordenar de forma inversa...
    • Modificar la clase Mazo para que "sobrecargar" el método ordenar(), es decir, el mismo método tendrá dos variantes: la que no recibe parámetros y la que recibe un Comparator

    Inténtalo, y si te atascas, te ayudamos.
    Saludos.
NO respondo dudas por mensaje privado
Publicando vuestras dudas en el foro público conseguimos:
- Que más gente aporte respuestas mejores o complementarias.
- Que otras personas puedan aprender de vuestras dudas.

Mejor en PÚBLICO que en privado. Gracias

drate

  • Sin experiencia
  • *
  • APR2.COM
  • Mensajes: 24
    • Ver Perfil
Re: Interfaces
« Respuesta #6 en: 15 de Junio 2023, 17:13 »
Buenas tardes.
He intentado resolver el ejercicio pero no acabo de verlo claro. Si me podéis echar una mano. Muchas gracias, un saludo.

Kabuto

  • Moderador Global
  • Experto
  • *******
  • Mensajes: 988
    • Ver Perfil
Re: Interfaces
« Respuesta #7 en: 16 de Junio 2023, 02:23 »
A ver, primero hacemos que Carta implemente la interfaz Comparable

Si lo hacemos así:
Citar
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 Object
Object es algo así como la superclase suprema de la que TODAS las clases Java son hijas, sí o sí...
Citar
   @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 Carta

Pero 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...
Citar
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.

Citar
   @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:
Código: [Seleccionar]
@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  AlgoritmoOrdenacion
Citar
public class Mazo {
   
       
      List cartas;
       private AlgoritmoOrdenacion algoritmo;
Podemos quitarle ese atributo y también el método que lo seteaba
Citar
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:
Código: [Seleccionar]
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 Cartas

Si lo probamos con un nuevo Main, veremos que el mazo se ordena correctamente de forma "natural":
Código: [Seleccionar]
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 Carta
Citar
public 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 Comparator

Podemos 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:
Código: [Seleccionar]
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 Main

Citar
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());

   }

}

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:

Código: [Seleccionar]
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:
Citar
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.
NO respondo dudas por mensaje privado
Publicando vuestras dudas en el foro público conseguimos:
- Que más gente aporte respuestas mejores o complementarias.
- Que otras personas puedan aprender de vuestras dudas.

Mejor en PÚBLICO que en privado. Gracias

 

Sobre la educación, sólo puedo decir que es el tema más importante en el que nosotros, como pueblo, debemos involucrarnos.

Abraham Lincoln (1808-1865) Presidente estadounidense.

aprenderaprogramar.com: Desde 2006 comprometidos con la didáctica y divulgación de la programación

Preguntas y respuestas

¿Cómo establecer o cambiar la imagen asociada (avatar) de usuario?
  1. Inicia sesión con tu nombre de usuario y contraseña.
  2. Pulsa en perfil --> perfil del foro
  3. Elige la imagen personalizada que quieras usar. Puedes escogerla de una galería de imágenes o subirla desde tu ordenador.
  4. En la parte final de la página pulsa el botón "cambiar perfil".