6. Caso de Estudio Nº 2: Reservas en un Vuelo

Un cliente quiere que construyamos un programa para manejar las reservas de un vuelo. Se sabe que el avión tiene 50 sillas, de las cuales 8 son de clase ejecutiva y las demás de clase económica. Las sillas ejecutivas se acomodan en filas de cuatro, separadas en el medio por el corredor. Las sillas económicas se acomodan en filas de seis, tres a cada lado del corredor.

Cuando un pasajero llega a solicitar una silla, indica sus datos personales y sus preferencias con respecto a la posición de la silla en el avión. Los datos del pasajero que le interesan a la aerolínea son el nombre y la cédula. Para dar la ubicación deseada, el pasajero indica la clase y la ubicación de la silla. Esta puede ser, en el caso de las ejecutivas, ventana y pasillo, y en el de las económicas, ventana, pasillo y centro. La asignación de la silla en el avión se hace en orden de llegada, tomando en cuenta las preferencias anteriores y las disponibilidades.

La interfaz de usuario del programa a la que se llegó después de negociar con el cliente se muestra en la figura 3.6.

Fig. 3.6 Interfaz de usuario para el caso de estudio del avión
  • En la parte superior del avión aparecen las 8 sillas ejecutivas.
  • En la parte inferior, aparecen las 42 sillas económicas, con un corredor en la mitad.
  • Se ofrecen las distintas opciones del programa a través de los botones que se pueden observar en la parte superior de la ventana.
  • Cuando una silla está ocupada, ésta aparecerá indicada en el dibujo del avión con un color especial.
  • Cada silla tiene asignado un número que es único. La silla 7, por ejemplo, está en primera clase, en el corredor de la segunda fila.

6.1. Comprensión de los Requerimientos

Nos vamos a concentrar en el siguiente requerimiento funcional:

Nombre R1 - Asignar una silla a un pasajero.
Resumen Asigna una silla a un pasajero según sus preferencias. Estas son clase (Ejecutiva o Económica) y ubicación (Ventana, Centro o Pasillo).
Entradas (1) nombre del pasajero, (2) cédula del pasajero, (3) clase de la silla, (4) ubicación de la silla.
Resultados Se marca como asignada una de las sillas disponibles en el avión, dependiendo de la clase y ubicación elegida. En caso de que todas las sillas estén asignadas, se muestra un mensaje de error.

6.2. Comprensión del Mundo del Problema

Podemos identificar tres entidades distintas en el mundo: avión, silla y pasajero. Lo cual nos lleva al diagrama de clases que se muestra en la figura 3.7.

Fig. 3.7 Diagrama de clases para el caso de estudio del avión

En este diagrama se puede leer lo siguiente:

  • Una silla puede ser ejecutiva o económica (un enumerador con las dos constantes definidas para la posible clase de la Silla), puede estar localizada en pasillo, corredor o centro (un enumerador con tres constantes definidas para la posible ubicación de la Silla), y tiene un identificador único que es un valor numérico.
  • Entre Silla y Pasajero hay una asociación opcional (0..1). Si la asociación está presente se interpreta como que la silla está ocupada y se conoce el pasajero que allí se encuentra. Si no está presente (vale null) se interpreta como que la silla está disponible.
  • Un pasajero se identifica con la cédula y tiene un nombre.
  • Un avión tiene 8 sillas ejecutivas (constante SILLAS_EJECUTIVAS de la clase Avion) y 42 sillas económicas (constante SILLAS_ECONOMICAS de la clase Avion). Fíjese cómo se expresa la cardinalidad de una asociación en UML.

6.3. Diseño de la Solución

Vamos a dividir el proyecto en 3 paquetes, siguiendo la arquitectura planteada en el primer nivel del libro. Los paquetes son:

uniandes.cupi2.avion.interfaz 
uniandes.cupi2.avion.test 
uniandes.cupi2.avion.mundo

La principal decisión de diseño del programa se refiere a la manera de representar el grupo de sillas del avión. Para esto vamos a manejar dos arreglos de objetos. Uno con 8 posiciones que tendrá los objetos de la clase Silla que representan las sillas de la clase ejecutiva, y otro arreglo de 42 posiciones con los objetos para representar las sillas económicas.

En las secciones que siguen presentaremos las distintas clases del modelo del mundo que constituyen la solución. Comenzamos por la clase más sencilla (la clase Pasajero) y terminamos por la clase que tiene la responsabilidad de manejar los grupos de atributos (la clase Avion), en donde tendremos la oportunidad de utilizar los patrones de algoritmo vistos en las secciones anteriores.

6.4. La Clase Pasajero

Tarea 6

Objetivo: Hacer la declaración en Java de la clase Pasajero.

Complete la declaración de la clase Pasajero, incluyendo sus atributos, el constructor y los métodos que retornan la cédula y el nombre. Puede guiarse por el diagrama de clases que aparece en la figura 3.7.

public class Pasajero
{

    //-----------------------------------
    // Atributos
    //-----------------------------------









    //-----------------------------------
    // Constructor
    //-----------------------------------
    public Pasajero( String pCedula, String pNombre )
    {









    }

    //-----------------------------------
    // Métodos
    //-----------------------------------
    public String darCedula( )
    {









    }
    public String darNombre( )
    {









    }
}

6.5. La Clase Silla

Tarea 7

Objetivo: Completar la declaración de la clase Silla.

Complete las declaraciones de los atributos y las enumeraciones de la clase Silla y desarrolle los métodos que se le piden para esta clase.

public class Silla
{
    //-------------------------------------------
    // Enumeraciones
    //-------------------------------------------

    /**
      * Enumeradores para las clases de silla.
      */
     public enum Clase 
     {
        /**
          * Representa la clase ejecutiva.
          */
          EJECUTIVA,

          /**
           * Representa la clase económica.
           */
          ECONOMICA
    }  

    /**
      * Enumeradores para las ubicaciones de las sillas.
      */
     public enum Ubicacion 
     {
        /**
          * Representa la ubicación ventana.
          */
         VENTANA,

         /**
          * Representa la ubicación centro.
          */


         /**
          * Representa la ubicación pasillo.
          */

    }

    ...
}
  • Se declara un enumerador con dos constantes para el atributo clase de la silla (EJECUTIVA, ECONOMICA).
  • Se declara un enumerador con tres constantes para representar las tres ubicaciones posibles de una silla (VENTANA, CENTRAL, PASILLO).
public class Silla
{
    ...

    //-------------------------------------------
    // Atributos
    //-------------------------------------------
    private int numero;
    private Clase clase;
    private Ubicacion ubicacion;
    private Pasajero pasajero;

    ...
}
  • Se declaran en la clase cuatro atributos: (1) el número de la silla, (2) la clase de la silla, (3) su ubicación y (4) el pasajero que opcionalmente puede ocupar la silla.
  • El atributo "pasajero" debe tener el valor null si no hay ningún pasajero asignado a la silla.
public Silla( int pNumero, Clase pClase, Ubicacion pUbicacion )
{
    numero = pNumero;
    clase = pClase;
    ubicacion = pUbicacion;
    pasajero = null;
}
  • En el constructor se inicializan los atributos a partir de los valores que se reciben como parámetro.
  • Se inicializa el atributo pasajero en null, para indicar que la silla se encuentra vacía.
public class Silla
{
    ...
    public void asignarPasajero( Pasajero pPasajero )
    {









    }
    ...
}
  • Asigna la silla al pasajero "pPasajero".
public class Silla
{
    ...
    public void desasignarSilla ( )
    {









    }
    ...
}
  • Quita al pasajero que se encuentra en la silla, dejándola desocupada.
public class Silla
{
    ...
    public boolean sillaAsignada( )
    {









    }
    ...
}
  • Informa si la silla está ocupada.
public class Silla
{
    ...
    public int darNumero( )
    {









    }
    ...
}
  • Retorna el número de la silla.
public class Silla
{
    ...
    public Clase darClase( )
    {









    }
    ...
}
  • Retorna la clase de la silla.
public class Silla
{
    ...
    public Ubicacion darUbicacion( )
    {

    }
    ...
}
  • Retorna la ubicación de la silla.
public class Silla
{
    ...
    public Pasajero darPasajero( )
    {

    }
    ...
}
  • Retorna el pasajero de la silla.

6.6. La Clase Avion

Ejemplo 9

Objetivo: Mostrar las declaraciones y el constructor de la clase Avion.

En este ejemplo se presentan las declaraciones de los atributos y las constantes de la clase Avion, lo mismo que su método constructor.

public class Avion
{
    //--------------------------------------------
    // Constantes
    //--------------------------------------------
    public final static int SILLAS_EJECUTIVAS = 8;
    public final static int SILLAS_ECONOMICAS = 42;
    ...

}
  • Con dos constantes representamos el número de sillas de cada una de las clases.
public class Avion
{
    ...
    //--------------------------------------------
    // Atributos
    //--------------------------------------------
    private Silla[] sillasEjecutivas;
    private Silla[] sillasEconomicas;

    ...
}
  • La clase Avion tiene dos contenedoras de tamaño fijo de sillas: una, de 42 posiciones, con las sillas de clase económica, y otra, de 8 posiciones, con las sillas de clase ejecutiva.
  • Se declaran los dos arreglos, utilizando la misma sintaxis que utilizamos en el caso de las notas del curso.
  • La única diferencia es que, en lugar de contener valores de tipo simple, van a contener objetos de la clase Silla.

A continuación aparece un fragmento del constructor de la clase. En las primeras dos instrucciones del constructor, creamos los arreglos, informando el número de casillas que deben contener. Para eso usamos las constantes definidas en la clase.

Después de haber reservado el espacio para los dos arreglos, procedemos a crear los objetos que representan cada una de las sillas del avión y los vamos poniendo en la respectiva casilla.

Esta inicialización se podría haber hecho con varios ciclos, pero el código resultaría un poco difícil de explicar.

public Avion( )
{
    sillasEjecutivas = new Silla[ SILLAS_EJECUTIVAS ]; 
    sillasEconomicas = new Silla[ SILLAS_ECONOMICAS ];

    // Creación de las sillas de clase ejecutiva
    sillasEjecutivas[ 0 ] = new Silla( 1, Clase.EJECUTIVA, Ubicacion.VENTANA ); 
    sillasEjecutivas[ 1 ] = new Silla( 2, Clase.EJECUTIVA, Ubicacion.PASILLO ); 
    sillasEjecutivas[ 2 ] = new Silla( 3, Clase.EJECUTIVA, Ubicacion.PASILLO ); 
    sillasEjecutivas[ 3 ] = new Silla( 4, Clase.EJECUTIVA, Ubicacion.VENTANA ); 
    sillasEjecutivas[ 4 ] = new Silla( 5, Clase.EJECUTIVA, Ubicacion.VENTANA ); 
    sillasEjecutivas[ 5 ] = new Silla( 6, Clase.EJECUTIVA, Ubicacion.PASILLO ); 
    sillasEjecutivas[ 6 ] = new Silla( 7, Clase.EJECUTIVA, Ubicacion.PASILLO ); 
    sillasEjecutivas[ 7 ] = new Silla( 8, Clase.EJECUTIVA, Ubicacion.VENTANA );

    // Creación de las sillas de clase económica
    sillasEconomicas[ 0 ] = new Silla( 9, Clase.ECONOMICA, Ubicacion.VENTANA ); 
    sillasEconomicas[ 1 ] = new Silla( 10, Clase.ECONOMICA, Ubicacion.CENTRAL ); 
    sillasEconomicas[ 2 ] = new Silla( 11, Clase.ECONOMICA, Ubicacion.PASILLO );
    ...
}

Ya con las declaraciones hechas y con el constructor implementado, estamos listos para comenzar a desarrollar los distintos métodos de la clase. Pero antes de empezar, queremos hablar un poco de las diferencias que existen entre un arreglo de valores de tipo simple (como el del caso de estudio de las notas) y un arreglo de objetos (como el del caso del avión).

Para empezar, en la figura 3.8a se muestra una instancia de la clase Silla ocupada por un pasajero. En la figura 3.8b se muestra un objeto de la clase Silla que se encuentra vacía. En la figura 3.8c se ilustra un posible contenido del arreglo de sillas ejecutivas (usando un diagrama de objetos).

Fig. 3.8 Ejemplo del contenido del arreglo de sillas ejecutivas
  • Figura 3.8a: en la silla de primera clase número 6, situada en el corredor, está sentado el Sr. José Sánchez con cédula No. 1234.
  • Figura 3.8b: la silla de clase económica número 10, situada en el centro, está desocupada.
  • Figura 3.8c: cada casilla del arreglo tiene un objeto de la clase Silla (incluso si la silla está desocupada).
  • Las sillas ocupadas tienen una asociación con el objeto que representa al pasajero que la ocupa. * En los arreglos de objetos se almacenan referencias a los objetos, en lugar de los objetos mismos.
  • Con la sintaxis sillasEjecutivas[x] podemos hacer referencia al objeto de la clase Silla que se encuentra en la casilla x.
  • Si queremos llegar hasta el pasajero que se encuentra en alguna parte del avión, debemos siempre pasar por la silla que ocupa. No hay otra manera de "navegar" hasta él.

Ya teniendo una visualización del diagrama de objetos del caso de estudio, es más fácil contestar las siguientes preguntas:

¿Cómo se llama un método de un objeto que está en un arreglo? Por ejemplo, dentro de la clase Avion, para preguntar si la silla que está en la posición 0 del arreglo de sillas ejecutivas está ocupada, se utiliza la sintaxis: sillasEjecutivas[0].sillaAsignada( ).Esta sintaxis es sólo una extensión de la sintaxis que ya veníamos utilizando. Lo único que se debe tener en cuenta es que cada vez que hacemos referencia a una casilla, estamos hablando de un objeto, más que de un valor simple.
¿Los objetos que están en un arreglo se pueden guardar en una variable? Tanto las variables como las casillas de los arreglos guardan únicamente referencias a los objetos. Si se hace la siguiente asignación: Silla sillaTemporal = sillasEjecutivas[0]; tanto la variable sillaTemporal como la casilla 0 del arreglo estarán haciendo referencia al mismo objeto. Debe quedar claro que el objeto no se duplica, sino que ambos nombres hacen referencia al mismo objeto.
¿Qué pasa con el objeto que está siendo referenciado desde una casilla si asigno null a esa posición del arreglo? Si guardó una referencia a ese objeto en algún otro lado, puede seguir usando el objeto a través de dicha referencia. Si no guardó una referencia en ningún lado, el recolector de basura de Java detecta que ya no lo está usando y recupera la memoria que el objeto estaba utilizando. ¡Adiós objeto!

Ejemplo 10

Objetivo: Mostrar la sintaxis que se usa para manipular arreglos de objetos.

En este ejemplo se muestra el código de un método de la clase Avion que permite eliminar todas las reservas del avión. No forma parte de los requerimientos funcionales, pero nos va a permitir mostrar una aplicación del patrón de recorrido total.

public void eliminarReservas( )
{
    for( int i = 0; i < SILLAS_EJECUTIVAS; i++ )
    {
        sillasEjecutivas[ i ].desasignarSilla( );
    }

    for( int i = 0; indice < SILLAS_ECONOMICAS; i++ )
    {
        sillasEconomicas[ i ].desasignarSilla( );
    }
}
  • Este método elimina todas las reservas que hay en el avión.
  • Note que podemos utilizar la misma variable como índice en los dos ciclos. La razón es que en la instrucción for, al terminar de ejecutar el ciclo, se destruyen las variables declaradas dentro de él y, por esta razón, podemos volver a utilizar el mismo nombre para la variable del segundo ciclo.
  • El método utiliza el patrón de recorrido total dos veces, una por cada uno de los arreglos del avión.

Ya vimos toda la teoría concerniente al manejo de los arreglos (estructuras contenedoras de tamaño fijo). Lo que sigue es aplicar los patrones de algoritmo que vimos unas secciones atrás, para implementar los métodos de la clase Avion.

Tarea 8

Objetivo: Desarrollar los métodos de la clase Avión que nos permitan implementar los requerimientos funcionales del caso de estudio.

Para cada uno de los problemas que se plantean a continuación, escriba el método que lo resuelve. No olvide identificar primero el patrón de algoritmo que se necesita y usar las guías que se dieron en secciones anteriores.

Calcular el número de sillas ejecutivas ocupadas en el avión:

public int contarSillasEjecutivasOcupadas( )
{









}

Localizar la silla en la que se encuentra el pasajero identificado con la cédula que se entrega como parámetro. Si no hay ningún pasajero en clase ejecutiva con esa cédula, el método retorna null.

public Silla buscarPasajeroEjecutivo( String pCedula )
{









}

Localizar una silla económica disponible, en una localización dada (ventana, centro o pasillo). Si no existe ninguna, el método retorna null:

public Silla buscarSillaEconomicaLibre( Ubicacion pUbicacion )
{









}

Asignar al pasajero que se recibe como parámetro una silla en clase económica que esté libre (en la ubicación pedida). Si el proceso tiene éxito, el método retorna verdadero. En caso contrario, retorna falso:

public boolean asignarSillaEconomica( Ubicacion pUbicacion, Pasajero pPasajero )
{









}

Anular la reserva en clase ejecutiva que tenía el pasajero con la cédula dada. Retorna verdadero
si el proceso tiene éxito:

public boolean anularReservaEjecutivo( String pCedula )
{









}

Contar el número de puestos disponibles en una ventana, en la zona económica del avión:

public int contarVentanasEconomica( )
{









}

Informar si en la zona económica del avión hay dos personas que se llamen igual. Patrón de doble
recorrido:

public boolean hayDosHomonimosEconomica( )
{









}

6.7. La instrucción for-each

El esqueleto del patrón de recorrido total también puede definirse con la instrucción for-each, la cual es una variación de la instrucción for que se puede resumir en el siguiente fragmento de código:

for( NombreClase elemento: arreglo )
{
    <cuerpo>
}

La instrucción for-each permite recorrer todos los elementos de un arreglo. De esta manera, para cada objeto existente en el arreglo, se ejecutan las instrucciones que se encuentran en el cuerpo del ciclo. En cada iteración, la variable elemento va a referenciar al objeto actual, permitiendo que se hagan las operaciones necesarias sobre este. Cabe resaltar que en el for-each no es necesario utilizar un índice, ya que la instrucción se encarga de pasar por cada uno de los elementos de forma automática. Es por esto que la instrucción for-each se utiliza principalmente en problemas que requieran un recorrido sobre todos los elementos del arreglo (recorrido total).

Ejemplo 11

Objetivo: Mostrar la sintaxis que se usa para la instrucción for-each.

En este ejemplo se muestra el código de un método de la clase Avion, el cual permite contar la cantidad de sillas económicas ocupadas, con el fin mostrar una aplicación del patrón de recorrido total utilizando la instrucción for-each. Si no hay ninguna silla económica ocupada, el método retorna cero.

A continuación se muestra el método utilizando la instrucción for:

public int contarSillasEconomicasOcupadas( )
{
    int contador = 0;
    Silla silla = null;
    for( int i = 0; i < SILLAS_ECONOMICAS; i++ )
    {
        silla = sillasEconomicas[ i ];
        if( silla.sillaAsignada( ) )
        {
            contador++;
        }
    }
    return contador;
}

La implementación del método utilizando la instrucción for-each es la siguiente:

public int contarSillasEconomicasOcupadas( )
{
    int contador = 0;
    for( Silla sillaEconomica : sillasEconomicas )
    {
        if( sillaEconomica.sillaAsignada( ) )
        {
            contador++;
        }
    }
    return contador;
}

Tarea 9

Objetivo: Desarrollar los métodos de la clase Avión que nos permitan implementar los requerimientos funcionales del caso de estudio utilizando la instrucción for-each.

Para cada uno de los problemas que se plantean a continuación, escriba el método que lo resuelve. En todos los casos son problemas que requieren un recorrido total y que se deben resolver utilizando la instrucción for-each.

Calcular el número de sillas económicas libres en el avión:

public int contarSillasEconomicasLibres( )
{









}

Contar el número de puestos disponibles en el pasillo, en la zona ejecutiva del avión:

public int contarPasilloEjecutivas( )
{









}

Desocupar avión. Se encarga de desocupar todas las sillas del avíon:

public void desocuparAvion( )
{









}

results matching ""

    No results matching ""