Universidad Carlos III de Madrid

Ingeniería de Telecomunicación

Enero-Mayo 2010 / January-May 2010

Orientación a Objetos y Herencia

Lab Section1. Sesión 2 (laboratorio): Orientación a Objetos y Herencia (I)

Exercise Section1.1. Puntos y Figuras Geométricas (I)

La clase Punto.

Un punto en el plano se puede representar mediante un par de coordenadas x e y, ambas tomando valores en el conjunto de los números reales. En Java podemos representar un punto en el plano mediante una instancia de la siguiente clase:

public class Punto {
    private double x;
    private double y;

    /* métodos */
    /* a completar en el resto de apartados */
}
Constructor de la clase.

En Java, el constructor de la clases sirve para inicializar los valores de los atributos a la hora de instanciarse un objeto de la misma en tiempo de ejecución.

  1. Programa un constructor para la clase Punto. Debe recibir como parámetros las dos coordenadas del punto.

Método para representar un objeto en formato de texto.

El método toString() tiene un significado especial en los objetos Java. Es el método que se utiliza para obtener una representación como cadena de texto de dicho objeto.

  1. Programa el método toString() para que devuelva una cadena de texto con la representación del punto con el siguiente formato:

    (x, y)

    donde x e y deben ser reemplazados por sus respectivos valores. El prototipo de dicha función se especifica a continuación:

    public String toString() {
        /* ... */
    }

    Pista

    Recuerda que el operador "+", aplicado a cadenas de texto, permite concatenarlas. Si se concatenan números a cadenas, Java los convierte automáticamente a cadenas de texto para realizar la concatenación.

El método main.

Ahora debes crear clase para probar el código anterior.

  1. Programa una clase llamada Prueba que tenga un método main. Este método debe recibir como argumentos de línea de comandos las coordenadas x e y, crear un nuevo objeto Punto con dichas coordenadas e imprimir en su salida estándar (la pantalla en este caso) la representación textual de dicho objeto.

    El programa debe comprobar que el número de argumentos de línea de comandos recibido sea el correcto.

    Pista

    El método parseDouble de la clase Double (consulta su API pinchando en el enlace) transforma una cadena de texto a un tipo primitivo double.

Los métodos de acceso.

Es habitual que los atributos de un objeto se declaren como privados (private) para evitar accesos incontrolados desde otros puntos del código. Si es necesario que desde el exterior se acceda a estos atributos, se proporcionan métodos cuyo nombre empieza, por convenio, con las cadenas "get" (acceso en lectura) y "set" (acceso en escritura).

  1. Programa en la clase Punto los siguientes métodos, que devuelven el valor de las coordenadas x e y. El prototipo de dichos métodos se muestra a continuación:

    public double getX() {
        /* ... */
    }
    
    public double getY() {
        /* ... */
    }
  2. Modifica el código de tu clase Prueba para comprobar que su comportamiento es correcto.

Cálculo de distancias.

En este apartado vamos a implementar dos métodos auxiliares que nos permitirán calcular distancias entre puntos.

  1. Programa un método de la clase Punto que devuelva la distancia del punto al origen de coordenadas. El prototipo del método se muestra a continuación:

    public double distanciaAlOrigen() {
    /*  completar */
    }

    Modifica el código de tu clase Prueba para comprobar que su comportamiento es correcto.

  2. Programa un método en Punto que devuelva la distancia entre el punto representado por la instancia actual del objeto y otra instancia de Punto que se recibe como parámetro. El prototipo del método se muestra a continuación:

    public double calcularDistancia(Punto otroPunto) {
        /* completar */
    }

    Modifica el código de tu clase Prueba para comprobar que su comportamiento es correcto.

Cálculo de cuadrante.
  1. Programa un método de la clase Punto que devuelva el cuadrante en el que se encuentra el punto.El prototipo del método se muestra a continuación:

    • Devuelve 0 si está en el origen de coordenadas o sobre alguno de los ejes.

    • Devuelve 1 si está en el primer cuadrante (x e y positivos).

    • Devuelve 2 si está en el segundo cuadrante (x negativo e y positivo).

    • Devuelve 3 si está en el tercer cuadrante (x e y negativos).

    • Devuelve 4 si está en el cuarto cuadrante (x positivo e y negativo).

    El prototipo del método se muestra a continuación:

    public int calcularCuadrante() {
      /* completar */
    }

    Modifica el código de tu clase de prueba para comprobar que su comportamiento es correcto.

Cálculo del punto más cercano.

En este apartado tienes que basarte en los métodos de los apartados anteriores.

  1. Programa un método en Punto que reciba como parámetro un array de objetos de la clase Punto y devuelva una referencia al objeto de dicho array que esté más cercano al punto actual.El prototipo del método se muestra a continuación:

    public Punto calcularMasCercano(Punto[] otrosPuntos) {
      /* completar */
    }

    Modifica el código de tu clase Prueba para comprobar que su comportamiento es correcto.

La clase Triangulo.

Un triángulo está plenamente definido por sus tres vértices. Estos vértices se pueden representar como objetos de la clase Punto.

Declaración de la clase.

En este apartado tienes que basarte en los métodos de los apartados anteriores.

  1. Programa la clase Triangulo con sus atributos y un constructor que reciba como parámetro tres puntos del plano.

Longitud de los lados.

Programa una clase para probarlo.

  1. Programa el método calcularLongitudLados() de la clase Triangulo, que debe devolver un array de tres posiciones, cada una de las cuales debe ser la longitud de uno de los lados del triángulo. El prototipo del método se muestra a continuación:

    public double[] calcularLongitudLados() {
        /* completar... */
    }

Soluciones

Las soluciones del ejercicio se pueden ver en el siguiente listado:

// Clase Punto
// (c) 2008 IT

public class Punto {
  private double x;
  private double y;

  // Constructor
  public Punto(double x, double y) {
    this.x = x;
    this.y = y;
  }

  // toString: devuelve una cadena con la representacion del objeto
  public String toString() {
    // el signo + para cadenas no significa "suma matematica" sino concatenacion
    return "(" + x + ", " + y + ")";
  }

  // devuelve la distancia al origen
  public double distanciaAlOrigen() {
    // NOTA: se podria haber hecho con la distancia a (0,0):
    // return calcularDistancia(new Punto(0,0));
    return Math.sqrt(x * x + y * y);
  }

  // metodos de acceso
  public double getX() {
    return x;
  }

  public double getY() {
    return y;
  }

  // devuelve la distancia a otro punto
  public double calcularDistancia(Punto otroPunto) {
    double x1 = x - otroPunto.getX();
    double y1 = y - otroPunto.getY();
    return Math.sqrt(x1 * x1 + y1 * y1);
  }

  // devuelve el cuadrante
  public int calcularCuadrante() {
    if (x > 0.0 && y > 0.0) {
      return 1;
    } else if (x < 0.0 && y > 0.0) {
      return 2;
    } else if (x < 0.0 && y < 0.0) {
      return 3;
    } else if (x > 0.0 && y < 0.0) {
      return 4;
    } else {
      // (x==0.0 || y==0.0)
      return 0;
    }
  }

  // calcula el punto mas cercano del array
  public Punto calcularMasCercano(Punto[] otrosPuntos) {
    Punto puntoMasCercano = null;

    if (otrosPuntos != null && otrosPuntos.length > 0) {
      // me guardo el primero como mas cercano
      double distanciaMinima = calcularDistancia(otrosPuntos[0]);
      puntoMasCercano = otrosPuntos[0];

      for (int i = 1; i < otrosPuntos.length; i++) {
        // si encuentro otro mas cercano, lo sustituyo
        double distancia = calcularDistancia(otrosPuntos[i]);
        if (distancia < distanciaMinima) {
          distancia = distanciaMinima;
          puntoMasCercano = otrosPuntos[i];
        }
      }
    }
    // devuelve el punto encontrado si el array contiene puntos, null en caso
    // contrario
    return puntoMasCercano;
  }
}

	  
// Clase de prueba de Punto
// (c) 2007 IT
public class Prueba {

  public static void main(String args[]) {

    // Comprobar el numero de argumentos (el nombre de programa mas las dos
    // coordenadas)
    if (args.length != 2) {
      System.out.println("Uso:");
      System.out.println("  java Prueba x y");
      System.out
          .println("donde x e y son las cooordenadas de un punto en el espacio.");
      return;
    }

    // Manejador de excepciones
    try {
      double x = Double.parseDouble(args[0]);
      double y = Double.parseDouble(args[1]);

      Punto p = new Punto(x, y);
      System.out.println("El punto es " + p.toString());
      System.out.println("Su distancia al origen es " + p.distanciaAlOrigen());
      System.out.println("Su coordenada x es " + p.getX()
          + " y su coordenada y es " + p.getY());

      System.out.println("Esta ubicado en el cuadrante "
          + p.calcularCuadrante());

      Punto[] arrayPuntos = new Punto[5];
      arrayPuntos[0] = new Punto(1, 1);
      arrayPuntos[1] = new Punto(5, 3);
      arrayPuntos[2] = new Punto(10, 10);
      arrayPuntos[3] = new Punto(-3, 2);
      arrayPuntos[4] = new Punto(-4, -5);

      for (int i = 0; i < arrayPuntos.length; i++) {
        System.out.println("Su distancia al punto " + arrayPuntos[i].toString()
            + " es " + p.calcularDistancia(arrayPuntos[i]));
      }
      System.out.println("El punto mas cercano es "
          + p.calcularMasCercano(arrayPuntos));
    } catch (NumberFormatException e) {
      System.out.println("Error en los argumentos de la linea de comandos.");
    }
  }
}
	  
// Clase de prueba de Triangulo
// (c) 2007 IT
public class PruebaTriangulo {

  public static void main(String args[]) {

    // Comprobar el numero de argumentos (el nombre de programa mas las dos
    // coordenadas)
    if (args.length != 6) {
      System.out.println("Uso:");
      System.out.println("  java PruebaTriangulo x1 y1 x2 y2 x3 y3");
      System.out
          .println("donde (xi,yi) son las cooordenadas de cada vertice del triangulo.");
      return;
    }

    // Manejador de excepciones
    try {
      double x1 = Double.parseDouble(args[0]);
      double y1 = Double.parseDouble(args[1]);
      double x2 = Double.parseDouble(args[2]);
      double y2 = Double.parseDouble(args[3]);
      double x3 = Double.parseDouble(args[4]);
      double y3 = Double.parseDouble(args[5]);

      // Se crean los tres vertices y el triangulo
      Punto v1 = new Punto(x1, y1);
      Punto v2 = new Punto(x2, y2);
      Punto v3 = new Punto(x3, y3);
      Triangulo t = new Triangulo(v1, v2, v3);

      // Presentacion de la informacion
      System.out.println("El triangulo tiene como vertices " + v1.toString()
          + ", " + v2.toString() + ", " + v3.toString());

      double[] longitudLados = t.calcularLongitudLados();
      System.out.println("Sus lados miden " + longitudLados[0] + ", "
          + longitudLados[1] + ", " + longitudLados[2]);
    } catch (Exception e) {
      System.out.println("Error en los argumentos de la linea de comandos.");
      return;
    }

  }
}
	  
// Clase Triangulo
// (c) 2007 IT
public class Triangulo {

  private Punto vertice1;
  private Punto vertice2;
  private Punto vertice3;

  public Triangulo(Punto vertice1, Punto vertice2, Punto vertice3) {
    this.vertice1 = vertice1;
    this.vertice2 = vertice2;
    this.vertice3 = vertice3;
  }

  public double[] calcularLongitudLados() {
    double longitudLados[] = new double[3];

    // longitud 1->2
    longitudLados[0] = vertice1.calcularDistancia(vertice2);
    // longitud 2->3
    longitudLados[1] = vertice2.calcularDistancia(vertice3);
    // longitud 3->1
    longitudLados[2] = vertice3.calcularDistancia(vertice1);

    return longitudLados;
  }
}

	  

Homework Section2. Actividades para casa

Exercise Section2.1. Ejercicio para practicar con Fechas

En este ejercicio, vamos a crear una clase Fecha que nos permita trabajar con fechas. La clase debe almacenar una serie de atributos y debe definir una serie de métodos para realizar distintas operaciones básicas.

Antes de escribir código, piensa cuidadosamente el diseño de la clase Fecha.

  1. ¿Qué información debe almacenar cada objeto? Si un mismo dato puede almacenarse en distintos formatos, ¿usarías varios atributos para representar la misma información? ¿Por qué? ¿Qué formato crees que es más conveniente?

  2. ¿Qué constructores proporcionarías? Observa que los constructores tendrán que inicializar los datos internos del objeto.

  3. Piensa qué métodos crees que sería útil incluir.

  4. ¿Se te ocurre alguna información que sería conveniente incluir en la clase, común para todos los objetos Fecha?

Atributos de la clase

  1. Define los atributos de la clase Fecha.

Constructores de la clase.

La clase Fecha debe proporcionar dos constructores que inicialicen objetos de tipo Fecha:

  • Un constructor con tres enteros que indican el día, mes y año respectivamente.

  • Un constructor con tres cadenas de caracteres, que indican el día, el mes y el año.

  1. Programar dichos constructores, de acuerdo a las siguentes declaraciones:

    public Fecha(int dia, int mes, int año) {
        /* completar */
    }
    
    public Fecha(String dia, String mes, String año) {
        /* completar */
    }
    

Métodos de acceso de los atributos de la clase.

Los atributos del objeto conviene que se declaren de acceso privado para evitar errores en su modificación. Programa los métodos get y set necesarios para leer y modificar la información encapsulada en los objetos Fecha.

Método toString() de representación del objeto.

El método toString() tiene un significado especial en los objetos Java. Es el método que se utiliza para obtener una representación como cadena de texto de dicho objeto mostrando los valores de los atributos en un instante determinado.

  1. Programa el método toString() que tiene la siguiente declaración:

    public String toString() {
        /* completar */
    }
    

    Este método tiene que devolver una cadena de texto con la representación de una fecha, según el siguiente formato:

    día(Numero) de mes(Texto) de año(Numero)

    EJEMPLO : 6 de Agosto de 2007

Método compareTo() para comparar fechas.

El método compareTo() tiene un significado especial en los objetos Java. Es el método que se utiliza para comparar dos objetos.

LECTURA RECOMENDADA: Consulta el API del interfaz Comparable para comprobar qué valor debe devolver en los distintos casos: según si el objeto con el que comparamos el objeto actual es mayor, menor o igual que éste.

  1. Programa el método compareTo() que tiene la siguiente declaración:

    public int compareTo(Fecha fecha) {
        /* ... */
    }
    

    El método compara la fecha almacenada en el objeto con la que se le pasa como parámetro, devolviendo como resultado:

    • -1 si la fecha contenida en el objeto actual es anterior a la que se pasa por parámetro.

    • 0 si son iguales.

    • 1 si la fecha contenida en el objeto actual es posterior a la que se pasa por parámetro.

Método auxiliar sobrecargado.

Recuerda que en una clase pueden aparecer varios métodos con el mismo nombre, siempre que tengan distintos parámetros de entrada. A esto se le denomina sobrecarga de métodos (en inglés, overload).

  1. Programa un método auxiliar que devuelve el número de días que tiene el mes que se le pasa como parámetro. Sobrecarga el método de modo que pueda utilizarse el número o el nombre del mes. Los métodos tienen las siguientes declaraciones:

    ... int getDiasMes(int mes) {
        /* completar */
    }
    
    ... int getDiasMes(String mes) {
        /* completar */
    }
    

Solución

Las soluciones del ejercicio se pueden ver en los siguientes listados:

import java.io.*;

public class Fecha {

  /**
   * Meses del ano, ordenados, para facilitar la conversion de formato cadena a
   * numero y viceversa
   * 
   * El numero de mes coincidira con la posicion de su nombre en el array mas 1
   * (porque las posiciones del array se numeran a partir de 0 pero los meses a
   * partir de 1)
   */
  private static final String[] meses = { "enero", "febrero", "marzo", "abril",
      "mayo", "junio", "julio", "agosto", "septiembre", "octubre", "noviembre",
      "diciembre" };

  // ATRIBUTOS

  private int dia;
  private int mes;
  private int agno;

  // CONSTRUCTORES

  public Fecha(int dia, int mes, int agno) throws FechaException {

    comprobarFecha(dia, mes, agno);

    this.dia = dia;
    this.mes = mes;
    this.agno = agno;

  }

  public Fecha(String sDia, String sNombreMes, String sAgno)
      throws FechaException {

    // Convertir las cadenas del dia y el ano en numeros
    try {
      dia = Integer.parseInt(sDia);
      agno = Integer.parseInt(sAgno);

    } catch (NumberFormatException nfe) {
      // Error al convertir una cadena en numero
      throw new FechaException("Fecha incorrecta");
    }

    mes = getMes(sNombreMes);

    // Comprobar ademas que los valores tienen sentido
    comprobarFecha(dia, mes, agno);

  }

  // ACCESORES

  public int getDia() {
    return dia;
  }

  public int getMes() {
    return mes;
  }

  public int getAgno() {
    return agno;
  }

  public void setDia(int dia) throws FechaException {
    comprobarFecha(dia, this.mes, this.agno);
    this.dia = dia;
  }

  public void setMes(int mes) throws FechaException {
    comprobarFecha(this.dia, mes, this.agno);
    this.mes = mes;
  }

  public void setAgno(int agno) throws FechaException {
    comprobarFecha(dia, mes, agno);
    this.agno = agno;
  }

  // METODOS

  public String toString() {
    return (dia + " de " + meses[mes - 1] + " de " + agno);
  }

  public int compareTo(Fecha fecha) {

    int resultado = 0;

    if (agno < fecha.getAgno()) {
      resultado = -1;
    } else if (agno > fecha.getAgno()) {
      resultado = 1;
    } else { // los anos son iguales => comparar los meses

      if (mes < fecha.getMes()) {
        resultado = -1;
      } else if (mes > fecha.getMes()) {
        resultado = 1;
      } else { // los meses tambien son iguales => comparar los dias

        if (dia < fecha.getDia()) {
          resultado = -1;
        } else if (dia > fecha.getDia()) {
          resultado = 1;
        } else { // los dias tambien son iguales => misma fecha
          resultado = 0;
        }
      }
    }

    return resultado;
  }

  // METODOS AUXILIARES

  /**
   * Devuelve el numero de dias de un mes dado
   */
  private int getDiasMes(int mes) throws FechaException {

    int diasMes = 0;

    switch (mes) {

    case 1:
    case 3:
    case 5:
    case 7:
    case 8:
    case 10:
    case 12: // meses de 31 dias
      diasMes = 31;
      break;

    case 4:
    case 6:
    case 9:
    case 11: // meses de 30 dias
      diasMes = 30;
      break;

    case 2: // febrero
      if (esBisiesto(agno))
        diasMes = 29;
      else
        diasMes = 28;
      break;

    default: // mes incorrecto
      throw new FechaException("Mes incorrecto");
    }

    return diasMes;

  }

  /**
   * Devuelve el numero de dias de un mes dado
   */
  private int getDiasMes(String mes) throws FechaException {
    return getDiasMes(getMes(mes));
  }

  /**
   * Metodo auxiliar para calcular el numero de mes, dado su nombre. Devuelve -1
   * si el texto introducido no se corresponde con un mes.
   */
  private static int getMes(String sNombreMes) throws FechaException {

    // Hallar el numero de mes
    int mes = -1;
    for (int i = 0; i < meses.length && mes == 0; i++) {
      if (meses[i].equalsIgnoreCase(sNombreMes)) {
        // El mes coincide con el elemento actual del array
        mes = i + 1;
      }
    }
    /*
     * if (mes == 0) { // si el mes introducido no coincide con ninguno de los
     * almacenados // en el array es que hay un error throw new FechaException(
     * "Mes incorrecto" ); }
     */

    return mes;

  }

  /**
   * Metodo auxiliar para comprobar que una fecha es correcta
   */
  private void comprobarFecha(int dia, int mes, int agno) throws FechaException {

    // Comprobar que el dia es correcto
    // (El metodo getDiasMes ya comprueba que el mes sea correcto)
    if ((dia <= 0) || (dia > getDiasMes(mes))) {
      throw new FechaException("Dia incorrecto");
    }

  }

  /**
   * Comprueba si un ano es bisiesto Son bisiestos los anos multiplos de 4 que
   * no sean multiplos de 100 y los multiplos de 400
   */
  private boolean esBisiesto(int agno) {
    return ((((agno % 4) == 0) && ((agno % 100) != 0)) || ((agno % 400) == 0));
  }

  public static Fecha leerFecha() {

    BufferedReader entrada = new BufferedReader(
        new InputStreamReader(System.in));
    Fecha fecha = null;
    String sDia, sMes, sAgno; // Variables para almacenar la entrada del usuario
    int iMes;

    boolean correcto = false;

    do {

      try {

        System.out.print("Introduzca dia: ");
        System.out.flush();
        sDia = entrada.readLine();
        System.out.print("Introduzca mes: ");
        System.out.flush();
        sMes = entrada.readLine();
        System.out.print("Introduzca ano: ");
        System.out.flush();
        sAgno = entrada.readLine();

        // Probamos si el usuario ha introducido el nombre del mes
        iMes = getMes(sMes);

        if (iMes == -1) {
          // Probamos si el usuario ha introducido el numero de mes
          iMes = Integer.parseInt(sMes);
        }

        fecha = new Fecha(sDia, meses[iMes], sAgno);
        correcto = true;

      } catch (Exception ex) {
        correcto = false;
      }

    } while (!correcto);

    return fecha;
  }

  public Fecha fechaMasReciente(Fecha[] fechas) {

    Fecha fecha = null;

    if ((fechas != null) && (fechas.length > 0)) {

      int max = 0;
      for (int i = 1; i < fechas.length; i++) {
        if (fechas[max].compareTo(fechas[i]) < 0) {
          max = i;
        }
      }
      fecha = fechas[max];
    }

    return fecha;

  }

}

	  
/**
 * La excepcion FechaException se lanza cuando se intenta generar un objeto
 * Fecha con datos incorrectos
 */
public class FechaException extends Exception {

  /**
   * Constructor sin parametros, genera una excepcion sin mensaje explicativo
   * especifico.
   */
  public FechaException() {
    super(); // se llama al constructor de la clase padre Exception
  }

  /**
   * Constructor con parametros, genera una excepcion con un mensaje explicativo
   * del error.
   * 
   * @param mensaje
   *          explicativo del error que ha generado la excepcion
   */
  public FechaException(String mensaje) {
    super(mensaje); // se llama al constructor de la clase padre Exception
  }
}
	  

Exercise Section2.2. Orientación a objetos, paso a paso

Clases y Creación de Objetos

Objetivo

Practicar la declaración de clases y la creación de objetos.

Ejercicio

La clase Album va a representar la producción musical de un determinado cantante o grupo, que se caracteriza por los siguientes atributos:

  • title: El título del Album

  • author: El nombre del cantante o grupo

  • year: Año de publicación

  • elements: Número de cds o DVDs que incluye el Album

  • price: Precio recomendado de venta al público, sin incluir IVA

  • genre: Un caracter indicando el tipo de música (D: Dance, P: Pop, R: Rock, C: Classical, J: Jazz, O: Other)

  • isSpanish: True si el álbum es de un cantante español

Razona de qué tipo sería cada uno de los atributos y los modificadores de acceso. Luego escribe la clase Album en Java

Ahora programa una clase llamada AlbumTest, que únicamente contenga un método main y sirva para probar cómo funciona la clase Album. La clase de prueba debe realizar lo siguiente:

  • Crear dos objetos de tipo Album llamados album1 y album2

  • Dar valor a los atributos de ambos objetos con los datos de dos álbumes que te gusten

  • Imprimir los datos de cada álbum correctamente tabulados, como se presentan a continuación

               	Album:
    		Titulo:		Crazy Hits
    		Autor:		Crazy Frog
    		Año:		2005
    		Num:		1
    		Precio:		14.99
    		Género:		D
    		Español:	False
             

Solución

La solución se puede ver en los siguientes listados:

Album.java

public class Album { public String title; public String author; public int year; public int elements; public float price; public char genre; public boolean isSpanish; public void printAlbum() { System.out.println("Album:"); System.out.println("Title:\t\t" + title); System.out.println("Author:\t\t" + author); System.out.println("Year:\t\t" + year); System.out.println("Price:\t\t" + price + " euros"); System.out.println("Genre:\t\t" + genre); System.out.println("IsSpanish:\t" + isSpanish); System.out.println(""); // Might also be made by calling the access methods: // System.out.println("Title:\t\t"+getTitle()); // ... } }

AlbumTest.java

public class AlbumTest { public static void main(String[] args) { Album album1; Album album2; // Object creation album1 = new Album(); album2 = new Album(); // assigning value to the attributes album1.title = "Crazy Hits"; album1.author = "Crazy Frog"; album1.year = 2005; album1.elements = 1; album1.price = 14.99f; album1.genre = 'D'; // album1.isSpanish=false; album2.title = "Cien gaviotas donde iran"; album2.author = "Varios"; album2.year = 2005; album2.elements = 1; album2.price = 14.99f; album2.genre = 'O'; album2.isSpanish = true; // printing information about album1 and album2 album1.printAlbum(); album2.printAlbum(); } }

Métodos de acceso

Objetivo

Practicar la encapsulación de objetos y el acceso mediante métodos públicos a atributos privados.

Ejercicio

Añade al programa métodos para rellenar y leer todos los campos de la clase. En el caso del atributo genre antes de asignar valor al atributo, comprueba que el caracter utilizado es un caracter válido.

Modifica el main de la clase AlbumTest para que utilice los metodos de acceso definidos. Comprueba que imprime el resultado correcto.

Solución

La solución se puede ver en el siguiente listado:

Album.java

public class Album { private String title; private String author; private int year; private int elements; private float price; private char genre; private boolean isSpanish; public void setTitle(String title) { this.title = title; } public void setAuthor(String author) { this.author = author; } public void setYear(int year) { this.year = year; } public void setElements(int elements) { this.elements = elements; } public void setPrice(float price) { this.price = price; } public void setGenre(char genre) { switch (genre) { case 'D': case 'P': case 'R': case 'C': case 'J': case 'O': this.genre = genre; break; default: System.out .println("The genre is not valid use one of the following characters: \n DANCE: D \n POP: P \n ROCK: R \n CLASSICAL: C \n JAZZ: J \n OTHER: O"); } } public void setIsSpanish(boolean isSpanish) { this.isSpanish = isSpanish; } public String getTitle() { return title; } public String getAuthor() { return author; } public int getYear() { return year; } public int getElements() { return elements; } public float getPrice() { return price; } public char getGenre() { return genre; } public boolean getIsSpanish() { return isSpanish; } public void printAlbum() { System.out.println("Album:"); System.out.println("Title:\t\t" + title); System.out.println("Author:\t\t" + author); System.out.println("Year:\t\t" + year); System.out.println("Price:\t\t" + price + " euros"); System.out.println("Genre:\t\t" + genre); System.out.println("IsSpanish:\t" + isSpanish); System.out.println(""); // Might also be made by calling the access methods: // System.out.println("Title:\t\t"+getTitle()); // ... } }

AlbumTest.java

public class AlbumTest { public static void main(String[] args) { Album album1; Album album2; // Object creation album1 = new Album(); album2 = new Album(); // assigning value to the attributes album1.setTitle("Crazy Hits"); album1.setAuthor("Crazy Frog"); album1.setYear(2005); album1.setElements(1); album1.setPrice(14.99f); album1.setGenre('D'); album1.setIsSpanish(false); album2.setTitle("Cien gaviotas donde iran"); album2.setAuthor("Varios"); album2.setYear(2005); album2.setElements(1); album2.setPrice(14.99f); album2.setGenre('O'); album2.setIsSpanish(true); // printing information about album1 and album2 album1.printAlbum(); album2.printAlbum(); } }

Operadores

Objetivo

Practicar el uso de operadores aritméticos.

Ejercicio

Modifica AlbumTest.java para que calcule el precio total de los dos álbumes e imprima un mensaje en pantalla como este:

	  Precio total (sin IVA):	29.98 euros
	  Precio total (con 16% IVA):	34.7768 euros
	

Solución

La solución se puede ver en el siguiente listado:


AlbumTest.java

public class AlbumTest { public static void main(String[] args) { Album album1; Album album2; // Object creation album1 = new Album(); album2 = new Album(); // assigning value to the attributes album1.setTitle("Crazy Hits"); album1.setAuthor("Crazy Frog"); album1.setYear(2005); album1.setElements(1); album1.setPrice(14.99f); album1.setGenre('D'); album1.setIsSpanish(false); album2.setTitle("Cien gaviotas donde iran"); album2.setAuthor("Varios"); album2.setYear(2005); album2.setElements(1); album2.setPrice(14.99f); album2.setGenre('O'); album2.setIsSpanish(true); // printing information about album1 and album2 album1.printAlbum(); album2.printAlbum(); System.out.println("Total price (without IVA): " + (album1.getPrice() + album2.getPrice())); System.out.println("Total price (with 16% IVA): " + (1.16 * (album1.getPrice() + album2.getPrice()))); } }

Constructores

Objetivo

Practicar el uso de constructores y su relación con los métodos de acceso.

Ejercicio

Hasta ahora no hemos escrito ningún constructor para la clase Album. Después de crear un objeto usando el constructor por defecto se llama a los métodos de acceso setTitle o setAuthor para dar valor a los atributos del objeto creado. Esto tiene el inconveniente de que si nos olvidamos de rellenar algún atributo pueden quedar objetos Album con valores inconsistentes. Para solucionarlo, escribe un constructor para la clase Album que de valor a todos los atributos del objeto. Para hacerlo debes pasarle al constructor una lista de parámetros para rellenar todos los atributos del objeto. Esto nos permitirá llamar al constructor de la siguiente forma para crear un objeto:

	new Album("Crazy Hits","Crazy Frog",2005,1,14.99,'D',false);
	

Solución

La solución se puede ver en el siguiente listado:

Album.java

public class Album { private String title; private String author; private int year; private int elements; private float price; private char genre; private boolean isSpanish; public Album(String title, String author, int year, int elements, float price, char genre, boolean isSpanish) { setTitle(title); setAuthor(author); setYear(year); setElements(elements); setPrice(price); setGenre(genre); setIsSpanish(isSpanish); // In some cases, when there is no verification of data before making the // assignment // you can asign value directly in the constructor instead of calling the // Set method // this.title = title; // ... } public void setTitle(String title) { this.title = title; } public void setAuthor(String author) { this.author = author; } public void setYear(int year) { this.year = year; } public void setElements(int elements) { this.elements = elements; } public void setPrice(float price) { this.price = price; } public void setGenre(char genre) { switch (genre) { case 'D': case 'P': case 'R': case 'C': case 'J': case 'O': this.genre = genre; break; default: System.out .println("The genre is not valid use one of the following characters: \n DANCE: D \n POP: P \n ROCK: R \n CLASSICAL: C \n JAZZ: J \n OTHER: O"); } } public void setIsSpanish(boolean isSpanish) { this.isSpanish = isSpanish; } public String getTitle() { return title; } public String getAuthor() { return author; } public int getYear() { return year; } public int getElements() { return elements; } public float getPrice() { return price; } public char getGenre() { return genre; } public boolean getIsSpanish() { return isSpanish; } public void printAlbum() { System.out.println("Album:"); System.out.println("Title:\t\t" + title); System.out.println("Author:\t\t" + author); System.out.println("Year:\t\t" + year); System.out.println("Price:\t\t" + price + " euros"); System.out.println("Genre:\t\t" + genre); System.out.println("IsSpanish:\t" + isSpanish); System.out.println(""); // Might also be made by calling the access methods: // System.out.println("Title:\t\t"+getTitle()); // ... } }

AlbumTest.java

public class AlbumTest { public static void main(String[] args) { Album album1; Album album2; // Object creation album1 = new Album("Crazy Hits", "Crazy Frog", 2005, 1, 14.99f, 'D', false); album2 = new Album("Cien gaviotas donde iran", "Varios", 2005, 1, 14.99f, 'O', true); // printing information about album1 and album2 album1.printAlbum(); album2.printAlbum(); System.out.println("Total price (without IVA): " + (album1.getPrice() + album2.getPrice())); System.out.println("Total price (with 16% IVA): " + (1.16 * (album1.getPrice() + album2.getPrice()))); } }

Constantes

Objetivo

Practicar el uso de las constantes y de la sentencia de selección switch.

Ejercicio

Crea una constante para identificar cada uno de los distintos generos musicales y asígnales el valor indicando en el enunciado por ejemplo ROCK='R'. Modifica el método setGenre para que utilice estas constantes para realizar las comprobaciones necesarias y asignar valor al atributo genre

Solución

La solución se puede ver en el siguiente listado:

Album.java

public class Album { public static final char DANCE = 'D'; public static final char POP = 'P'; public static final char ROCK = 'R'; public static final char CLASSICAL = 'C'; public static final char JAZZ = 'J'; public static final char OTHER = 'O'; private String title; private String author; private int year; private int elements; private float price; private char genre; private boolean isSpanish; public Album(String title, String author, int year, int elements, float price, char genre, boolean isSpanish) { setTitle(title); setAuthor(author); setYear(year); setElements(elements); setPrice(price); setGenre(genre); setIsSpanish(isSpanish); // In some cases, when there is no verification of data before making the // assignment // you can asign value directly in the constructor instead of calling the // Set method // this.title = title; // ... } public void setTitle(String title) { this.title = title; } public void setAuthor(String author) { this.author = author; } public void setYear(int year) { this.year = year; } public void setElements(int elements) { this.elements = elements; } public void setPrice(float price) { this.price = price; } public void setGenre(char genre) { switch (genre) { case DANCE: case POP: case ROCK: case CLASSICAL: case JAZZ: case OTHER: this.genre = genre; break; default: System.out .println("The genre is not valid use one of the following characters: \n DANCE: D \n POP: P \n ROCK: R \n CLASSICAL: C \n JAZZ: J \n OTHER: O"); } } public void setIsSpanish(boolean isSpanish) { this.isSpanish = isSpanish; } public String getTitle() { return title; } public String getAuthor() { return author; } public int getYear() { return year; } public int getElements() { return elements; } public float getPrice() { return price; } public char getGenre() { return genre; } public boolean getIsSpanish() { return isSpanish; } public void printAlbum() { System.out.println("Album:"); System.out.println("Title:\t\t" + title); System.out.println("Author:\t\t" + author); System.out.println("Year:\t\t" + year); System.out.println("Price:\t\t" + price + " euros"); System.out.println("Genre:\t\t" + genre); System.out.println("IsSpanish:\t" + isSpanish); System.out.println(""); // Might also be made by calling the access methods: // System.out.println("Title:\t\t"+getTitle()); // ... } }

Tipos de referencia

Objetivo

Practicar el uso de las clases como tipos de referencia en la declaración de atributos

Ejercicio

El precio de un álbum es algo que puede cambiar en el tiempo dependiendo de nuestras políticas de precios, ofertas de temporada, etc. vamos a cambiar el atributo price para gestionar mejor estos cambios. En lugar de utilizar un tipo basico (double) para representarlo vamos a crear un tipo específico de datos que llamaremos Rate (tarifa). De este modo podemos declarar una clase Rate y encapsular en ella un conjunto de datos y comportamientos específicos que nos permitirán calcular dicho precio.

Crea una clase Rate que contenga la siguiente información:

  • 3 constantes numéricas para los diferentes tipos de tarifa (NORMAL=0, REDUCED=1, INCREASED=2)

  • Un atributo llamado base para representar el precio sin ofertas ni recargos

  • Un atributo plus que indica la cantidad que hay que sumar o restar al precio básico dependiendo de que se trate de una tarifa aumentada o reducida

  • Un método getPrice que calcule el precio según la siguiente fórmula y devuelva su val:

    • Precio normal = base*num

    • Precio rebajado (ejemplo oferta de temporada) = base*num*(1-plus)

    • Precio aumentado (ejemplo edición especial) = base*num*(1+plus)

Solución

La solución se puede ver en el siguiente listado:

Album.java

public class Album { public static final char DANCE = 'D'; public static final char POP = 'P'; public static final char ROCK = 'R'; public static final char CLASSICAL = 'C'; public static final char JAZZ = 'J'; public static final char OTHER = 'O'; private String title; private String author; private int year; private int elements; private Rate rate; private char genre; private boolean isSpanish; public Album(String title, String author, int year, int elements, float price, char genre, boolean isSpanish) { setTitle(title); setAuthor(author); setYear(year); setElements(elements); setPrice(price); setGenre(genre); setIsSpanish(isSpanish); // In some cases, when there is no verification of data before making the // assignment // you can asign value directly in the constructor instead of calling the // Set method // this.title = title; // ... } public Album(String title, String author, int year, int elements, float price, float plus, char genre, boolean isSpanish) { setTitle(title); setAuthor(author); setYear(year); setElements(elements); setPrice(price, plus); setGenre(genre); setIsSpanish(isSpanish); // In some cases, when there is no verification of data before making the // assignment // you can asign value directly in the constructor instead of calling the // Set method // this.title = title; // ... } public Album(String title, String author, int year, int elements, float price, float plus, int rateType, char genre, boolean isSpanish) { setTitle(title); setAuthor(author); setYear(year); setElements(elements); setPrice(price, plus, rateType); setGenre(genre); setIsSpanish(isSpanish); // In some cases, when there is no verification of data before making the // assignment // you can asign value directly in the constructor instead of calling the // Set method // this.title = title; // ... } public void setTitle(String title) { this.title = title; } public void setAuthor(String author) { this.author = author; } public void setYear(int year) { this.year = year; } public void setElements(int elements) { this.elements = elements; } public void setPrice(float base) { rate = new Rate(base); } public void setPrice(float base, float plus) { rate = new Rate(base, plus); } public void setPrice(float base, float plus, int rateType) { rate = new Rate(base, plus, rateType); } public void setGenre(char genre) { switch (genre) { case DANCE: case POP: case ROCK: case CLASSICAL: case JAZZ: case OTHER: this.genre = genre; break; default: System.out .println("The genre is not valid use one of the following characters: \n DANCE: D \n POP: P \n ROCK: R \n CLASSICAL: C \n JAZZ: J \n OTHER: O"); } } public void setIsSpanish(boolean isSpanish) { this.isSpanish = isSpanish; } public String getTitle() { return title; } public String getAuthor() { return author; } public int getYear() { return year; } public int getElements() { return elements; } public float getPrice() { float resultado = 0; resultado = (rate.getPrice()) * elements; return resultado; } public char getGenre() { return genre; } public boolean getIsSpanish() { return isSpanish; } public int getRateType() { int resultado = rate.getRateType(); return resultado; } public void printAlbum() { System.out.println("Album:"); System.out.println("Title:\t\t" + title); System.out.println("Author:\t\t" + author); System.out.println("Year:\t\t" + year); System.out.println("Price:\t\t" + getPrice() + " euros"); System.out.println("Genre:\t\t" + genre); System.out.println("IsSpanish:\t" + isSpanish); System.out.println("Rate type:\t" + getRateType()); System.out.println(""); // Might also be made by calling the access methods: // System.out.println("Title:\t\t"+getTitle()); // ... } }

AlbumTest.java

public class AlbumTest { public static void main(String[] args) { Album album1; Album album2; Album album3; // Object creation album1 = new Album("Crazy Hits", "Crazy Frog", 2005, 1, 14.99f, 0.1f, 1, 'D', false); album2 = new Album("Cien gaviotas donde iran", "Varios", 2005, 1, 14.99f, 0.1f, 2, 'O', true); album3 = new Album("Prueba", "Varios", 2005, 1, 14.99f, 0.1f, 0, 'O', true); // printing information about album1 and album2 album1.printAlbum(); album2.printAlbum(); album3.printAlbum(); System.out.println("Total price (without IVA): " + (album1.getPrice() + album2.getPrice() + album3.getPrice())); System.out.println("Total price (with 16% IVA): " + (1.16 * (album1.getPrice() + album2.getPrice() + album3.getPrice()))); } }

Rate.java

public class Rate{ private static final int NORMAL = 0; private static final int REDUCED = 1; private static final int INCREASED = 2; private int rateType; private float base; private float plus; public Rate(float base){ this.base = base; this.plus = 10; setRateType(0); } public Rate(float base, float plus){ this.base = base; this.plus = plus; setRateType(0); } public Rate(float base, float plus, int rateType){ this.base = base; this.plus = plus; setRateType(rateType); } public void setRateType(int rateType){ if (rateType==NORMAL || rateType == REDUCED || rateType == INCREASED){ this.rateType=rateType; }else{ this.rateType=-1; System.out.println("The rate type is not valid use one of the following values: \n NORMAL: 0 \n REDUCED: 1 \n INCREASED: 2 \n "); } } public float getPrice(){ float resultado = 0; switch(rateType){ case NORMAL: resultado = base; break; case REDUCED: resultado = base*(1+plus); break; case INCREASED: resultado = base*(1-plus); break; } return resultado; } public int getRateType(){ return rateType; } }