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 4 (laboratorio): Orientación a Objetos y Herencia (II)

Exercise Section1.1. Archivos multimedia

Ejercicio

Pretendemos crear una aplicación con la que gestionar una serie de archivos multimedia presentes en nuestro equipo. Con ella vamos a poder almacenar características de estos archivos. Dado que nos vamos a centrar en archivos de audio y de vídeo, habrá características que sean comunes a ambos conjuntos de archivos (nombre de archivo), pero habrá otras que sean propias de un grupo o del otro (dimensiones de la imagen en un vídeo).

Apartado 1. Excepción base

Para llevar a cabo el control de errores vamos a definir una clase MultimediaObjectException, que es una excepción que, cuando se lanza, da lugar a que salga por pantalla el texto:

Incorrect value
  

Apartado 2. Clase MultimediaObject

Aprovechando que hay una serie de características que están presentes en todos los ficheros multimedia vamos a crear una clase padre, llamada MultimediaObject, que va a contener lo siguiente:

  • Definición de los atributos name, para almacenar el nombre del archivo, y minutes y seconds, para indicar la duración en minutos y segundos, respectivamente.

  • Constructor al que se le puedan pasar valores para inicializar todos estos atributos. En el constructor se comprobará que el valor de inicialización de seconds es mayor o igual que 0 y menor que 60, y que el valor de inicialización de minutes es mayor o igual a 0. En caso de que no sea así se lanzará una MultimediaObjectException.

  • Método printData() que saque por pantalla los datos referentes a los atributos:

    File: name_of_the_file
    Length: minutes:seconds
          

    A modo de ejemplo:

    File: Nothing else matters.mp3
    Length: 6:15
          

Apartado 3. Clases derivadas

Ahora vamos a definir las clases para distinguir entre los ficheros de audio y los de vídeo. Estas clases heredan de la clase MultimediaObject.

La clase que se encarga de gestionar ficheros de audio, llamada AudioObject, debe tener:

  • Definición de atributos bitRate, frequency y quality. Los dos primeros deben almacenar valores enteros mientras que el último será un String que tomará los valores Stereo o Mono.

  • Constructor para inicializar todos los atributos que puede tener un AudioObject (no sólo los definidos ahora) y que compruebe que la tasa binaria y la frecuencia se inicializan a valores mayores o iguales que 0 y que la calidad es uno de los dos valores permitidos. Si esto no ocurre se lanzará la excepción MultimediaObjectException.

  • Método printData() que invoque el método de la clase padre y saque por pantalla también los atributos propios con el formato:

    Bit rate: value in kbps
    Frequency: value in Hz
    Quality:  value
          

Al final del apartado 4 tienes un ejemplo de cómo debe ser la salida por pantalla tras la llamada a este método.

La clase VideoObject, por su parte, incluirá:

  • Definición de atributos width, height y fps (frames por segundo). Los dos primeros han de ser enteros y el último, float.

  • Constructor con las mismas características que el de AudioObject.

  • Método printData() que, tras invocar al método de la clase padre, sacará por pantalla los datos referentes al fichero de vídeo con el formato:

    Screen size: width x height
    Frames per second: value
          

Apartado 4. Clase main

Finalmente vamos a hacer el programa que maneja estos elementos. Este programa estará dentro de una clase llamada MultimediaCollection. El programa deberá crear dos objetos MultimediaObject. Uno será un AudioObject y el otro, un VideoObject. Las características de estos ficheros son:

  • AudioObject:
    • Name: Nothing else matters.mp3
    • Minutes: 6
    • Seconds: 15
    • Bit rate: 192
    • Frequency: 44100
    • Calidad: Estéreo
  • VideoObject:
    • Name: Kill Bill Trailer.mpg
    • Minutes: 3
    • Seconds: 15
    • Width: 176
    • Height: 76
    • Fps: 30.0

Una vez creados, se sacará por pantalla la información relativa a ambos. El resultado deberá ser:

File: Nothing else matters.mp3
Length: 6:15
Bit rate: 192 kbps
Frequency: 44100 Hz
Quality: Estéreo

File: Kill Bill Trailer.mpg
Length: 3:15
Screen size: 176 x 76
Frames per second: 30.0
  

El programa deberá manejar las excepciones que se puedan producir, sacando por pantalla el mensaje de error correspondiente. En el tratamiento de excepciones deberá distinguir entre excepciones MultimediaObjectException y el resto de excepciones.

Solución

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

public class MultimediaObjectException extends Exception {
  public MultimediaObjectException() {
    super("Incorrect value");
  }
}

          
public class MultimediaObject {
  String name;
  int minutes;
  int seconds;

  public MultimediaObject(String name, int minutes, int seconds)
      throws MultimediaObjectException {
    this.name = name;
    if (minutes >= 0) {
      this.minutes = minutes;
    } else {
      throw new MultimediaObjectException();
    }
    if (seconds >= 0 && seconds < 60) {
      this.seconds = seconds;
    } else {
      throw new MultimediaObjectException();
    }
  }

  public void printData() {
    System.out.println("File: " + name);
    System.out.println("Length: " + minutes + ":" + seconds);
  }
}

          
public class AudioObject extends MultimediaObject {
  int bitRate;
  int frequency;
  String quality;

  public AudioObject(String name, int minutes, int seconds, int bitRate,
      int frequency, String quality) throws MultimediaObjectException {
    super(name, minutes, seconds);
    if (bitRate >= 0) {
      this.bitRate = bitRate;
    } else {
      throw new MultimediaObjectException();
    }
    if (frequency >= 0) {
      this.frequency = frequency;
    } else {
      throw new MultimediaObjectException();
    }
    if (quality.equalsIgnoreCase("Stereo") || quality.equalsIgnoreCase("Mono")) {
      this.quality = quality;
    } else {
      throw new MultimediaObjectException();
    }
  }

  public void printData() {
    super.printData();
    System.out.println("Bit rate: " + bitRate + " kbps");
    System.out.println("Frequency: " + frequency + " Hz");
    System.out.println("Quality: " + quality);
  }
}

          
public class VideoObject extends MultimediaObject {
  int width;
  int height;
  float fps;

  public VideoObject(String name, int minutes, int seconds, int width,
      int height, float fps) throws MultimediaObjectException {
    super(name, minutes, seconds);
    if (width >= 0) {
      this.width = width;
    } else {
      throw new MultimediaObjectException();
    }
    if (height >= 0) {
      this.height = height;
    } else {
      throw new MultimediaObjectException();
    }
    if (fps >= 0) {
      this.fps = fps;
    } else {
      throw new MultimediaObjectException();
    }
  }

  public void printData() {
    super.printData();
    System.out.println("Screen size: " + width + " x " + height);
    System.out.println("Frames per second: " + fps);
  }
}

          
public class MultimediaCollection {
  public static void main(String args[]) {
    try {
      MultimediaObject audio = new AudioObject("Nothing else matters.mp3", 6,
          15, 128, 44100, "Stereo");
      MultimediaObject video = new VideoObject("Kill Bill Trailer.mpg", 3, 15,
          176, 76, 30.0f);
      audio.printData();
      video.printData();
    } catch (MultimediaObjectException moe) {
      System.err.println(moe.toString());
    } catch (Exception e) {
      System.err.println(e.toString());
    }
  }
}

          

Homework Section2. Actividades para casa

Exercise Section2.1. Sistemas operativos

Ejercicio

Los sistemas operativos multitarea actuales permiten la ejecución concurrente (al mismo tiempo) de varios programas a la vez. Para realizarlo el núcleo del sistema operativo dispone de una entidad denominada planificador que, de acuerdo a una serie de características, selecciona un programa como el próximo a ser ejecutado.

Todos los programas que pueden ser ejecutados en un sistema operativo disponen de las siguientes características:

  • Un identificador de tipo cadena que permite distinguir de forma unívoca un programa de otro.

  • Una prioridad en la que se basará el planificador para determinar cuál es el próximo programa a ejecutar. Podrá tomar los valores 3, 2, 1. Siendo 3 la prioridad más alta y 1 la más baja.

  • Tienen la capacidad de poder mostrar en la consola la información sobre su identificador y prioridad.

La clase para representar estos objetos se llamará Program y contiene los atributos indicados, métodos de acceso a dichos atributos, un constructor que recibe todos los atributos, y el método void print() referido anteriormente.

Además, existen dos tipos de programas especiales, uno de ellos denominado de tiempo real, que siempre tienen una prioridad muy alta (valor 4) y unos programas que se ejecutan en segundo plano que tienen la prioridad más baja (0). Además, estos programas especializan el comportamiento de mostrar por consola la información de identificador y prioridad, añadiendo el tipo de objeto que son (de tiempo real o de segundo plano).

Apartado 1. Jerarquía de clases

Se pide programar el conjunto de clases (Program, RealTimeProgram, BackgroundProgram) que definen el comportamiento de los programas según las características descritas anteriormente.

Apartado 2. Planificador

Se quiere definir una clase Scheduler (planificador) que sea capaz de gestionar programas con prioridad. Esta clase tendrá un atributo que será un array de Program, donde se almacenarán los programas a gestionar. El constructor de la clase recibe como parámetro el número máximo de programas que el planificador es capaz de gestionar.

Se pide programar un método que sea capaz de almacenar programas ordenados de menor a mayor prioridad: void add(Program program) throws Exception. Este método lanza una excepción si no se pueden añadir más programa (si el array está lleno).

Apartado 3. Método next()

Programar un método en la clase planificador que devuelva el próximo programa que debe ejecutarse (el de mayor prioridad): Program next() throws Exception. El método lanzará una excepción si no hay ningún programa que devolver (si el array está vacío).

Nota: Se deja a elección del alumno decidir ante niveles de prioridad iguales qué programa devolver.

Solución

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

public class Program {
  private String id;
  private int priority;

  public Program(String id, int priority) {
    this.id = id;
    this.priority = priority;
  } // Program

  public int getPriority() {
    return priority;
  } // getPriority

  public void print() {
    System.out.println("Id: " + id);
    System.out.println("Priority: " + priority);
  } // print

} // Program

          
public class RealTimeProgram extends Program {
  final static int MAX_PRIORITY = 4;

  public RealTimeProgram(String id) {
    super(id, MAX_PRIORITY);
  } // RealTimeProgram

  public void print() {
    System.out.println("Real Time Program");
    super.print();
  } // print

} // RealTimeProgram

          
public class BackgroundProgram extends Program {
  final static int MIN_PRIORITY = 0;

  public BackgroundProgram(String id) {
    super(id, MIN_PRIORITY);
  } // BackgroundProgram

  public void print() {
    System.out.println("Background Program");
    super.print();
  } // print

} // BackgroundProgram

          
public class Scheduler {
  private Program programs[];

  public Scheduler(int size) {
    programs = new Program[size];
  } // Scheduler

  /** Adds a program, sorted from low to high priority */
  public void add(Program program) throws Exception {
    boolean found = false;
    int i = 0;
    int size = programs.length;
    int currentPriority = program.getPriority();
    // Find a place to insert into
    while ((!found) && (i < size)) {
      if (programs[i] == null) {
        found = true;
      } else if (currentPriority < programs[i].getPriority()) {
        found = true;
      } else {
        i++;
      }
    } // while
    if (found) {
      // Insert the program into the null position
      if (programs[i] == null) {
        programs[i] = program;
      } else {
        // Move the elements...
        // ...but what if it is full?
        if (programs[size - 1] != null) {
          throw new Exception("List is full (Cond 1)");
        } else {
          // Move from the end
          for (int j = size - 1; j > i; j--) {
            programs[j] = programs[j - 1];
          }
          // Then, asign the value
          programs[i] = program;
        }
      }
    } else {
      throw new Exception("List is full (Cond 2)");
    }
  } // add

  public Program next() throws Exception {
    boolean found = false;
    int size = programs.length;
    int i = size - 1;
    while ((!found) && (i >= 0)) {
      found = (programs[i] != null);
      i--;
    }
    if (!found) {
      throw new Exception("Empty list, no program to execute");
    } else {
      return programs[i + 1];
    }
  } // next

} // Scheduler

          
public class Programs {
  public static void main(String args[]) {
    Scheduler miScheduler = new Scheduler(6);
    try {
      Program program = new Program("1", 1);
      miScheduler.add(program);
      program = new Program("2", 2);
      miScheduler.add(program);
      program = new Program("3", 3);
      miScheduler.add(program);
      program = new Program("4", 2);
      miScheduler.add(program);
      RealTimeProgram realtimeProgram = new RealTimeProgram("5");
      miScheduler.add(realtimeProgram);
      BackgroundProgram backgroundProgram = new BackgroundProgram("6");
      miScheduler.add(backgroundProgram);

      // Test the full list (Cond 2)
      // miScheduler.add(new Program("7", 7));

      Program next = miScheduler.next();
      next.print();
    } catch (Exception ex) {
      System.out.println(ex.getMessage());
    }
    System.out.println("End");
  } // main
} // Programs