Programación Orientada a Objetos
Este libro está inspirado en el proyecto CUPI2, realizado por la Universidad de los
Andes, cuyo principal propósito es encontrar mejores formas de enseñar/aprender
a resolver problemas haciendo uso de un lenguaje de programación
Sonia Jaramillo Valbuena Adscrito al
Programa de Ingeniería de Sistemas y Computación Facultad de Ingeniería
Universidad del Quindío
Sergio Augusto Cardona Torres Adscrito al
Programa de Ingeniería de Sistemas y Computación Facultad de Ingeniería
Universidad del Quindío
Leonardo Alonso Hernández Rodríguez Adscrito al
Programa de Ingeniería de Sistemas y Computación Facultad de Ingeniería
Universidad del Quindío
Programación Orientada a Objetos
No está permitida la reproducción total o parcial de esta obra, ni su tratamiento o
transmisión por cualquier método sin autorización escrita deleditor.
Derechos reservados
ISBN: 978-958-44-7914-3 200 ejemplares
©Derechos reservados
Reproducido y editado por Ediciones Elizcom Primera edición, diciembre del 2010
200 ejemplares
www.elizcom.com
ventas@elizcom.com
Fax: 57 +6 +7450655
Móvil: 57 +3113349748
Armenia, Quindío
Colombia
PROGRAMACIÓN ORIENTADA A OBJETOS CONTENIDO
Pág.
ESTRUCTURAS CONTENEDORAS DE TAMAÑO FIJO
..................................................................................... 9
1
Objetivos.......................................................................................................................
9
2
Motivación.....................................................................................................................
9
3 Caso de estudio N.1 La Empresa (Código Fuente: unidadICaso01Empresa)
............................................ 9
3.1 Comprensión de los requisitos
............................................................................................................. 10
3 2 Comprensión del mundo del
problema................................................................................................. 11
3 3
Arreglos..........................................................................................................................
11
3.4 Recorrer los arreglos
........................................................................................................................... 13
3 5 Patrones para instrucciones
repetitivas................................................................................................ 16
3.6 El manejo de la memoria en Java
........................................................................................................ 18
3.7 Excepciones
.......................................................................................................................................
18
3.8 Diseño por contrato
............................................................................................................................. 20
4 Caso de estudio N.2 Cine ElizMark (Código Fuente: unidadICaso02Cine)
.............................................. 27
4.1 Comprensión de los requisitos
............................................................................................................. 28
4 2 Comprensión del mundo del
problema................................................................................................. 28
4 3 Diseño y construcción de la solución del problema
.............................................................................. 30
5 Hoja de trabajo 1 La Biblioteca (Código Fuente:
unidadIHoja01Biblioteca).............................................. 36
5.1 Comprensión de los requisitos
............................................................................................................. 37
5 2 Comprensión del mundo del
problema................................................................................................. 37
5 3 Diseño y construcción de la solución del problema
.............................................................................. 39
6 Hoja de trabajo N.2 Universidad (Código Fuente: unidadIHoja02Universidad)
........................................ 45
6.1 Requisitos funcionales
.................................................................................................................... 45
6 2 Comprensión del mundo del
problema............................................................................................ 46
6 3 Diseño y construcción de la solución del problema
......................................................................... 48
ESTRUCTURAS CONTENEDORAS DE TAMAÑO
VARIABLE.......................................................................... 53
1 Objetivos
.......................................................................................................................................
53
2 Motivación
.......................................................................................................................................
53
3 Caso de estudio N.1 Conjuntos (Código Fuente:
unidadIICaso01Conjuntos)............................................... 53
3.1 Requisitos funcionales
.................................................................................................................... 54
3 2 Comprensión del mundo del
problema............................................................................................ 55
3 3 Diseño y construcción de la solución del problema
......................................................................... 57
4 Caso de estudio N.2 Conjunto Cerrado (Código
Fuente:unidadIICaso02ConjuntoCerrado)..................... 62
4.1 Requisitos funcionales
.................................................................................................................... 63
4 2 Comprensión del mundo del
problema............................................................................................ 64
4 3 Diseño y construcción de la solución del problema
......................................................................... 65
5 Caso de estudio N.1 El Avión (Código Fuente: unidadIIHoja01Avion)
......................................................... 67
5.1 Requisitos funcionales
.................................................................................................................... 68
5 2 Comprensión del mundo del
problema............................................................................................ 68
5 3 Diseño y construcción de la solución del problema
......................................................................... 69
5.4 Enum como nuevo elementos de
modelado.................................................................................... 72
5 5 foreach en Java
.............................................................................................................................. 73
6 Caso de estudio N.1 El Banco (Código Fuente: unidadI Hoja02Banco)
................................................... 74
6.1 Requisitos funcionales
.................................................................................................................... 75
6 2 Comprensión del mundo del
problema............................................................................................ 76
6 3 Diseño y construcción de la solución del problema
......................................................................... 76
ARRAY
B D MENSIONAL...........................................................................................................
81
1 Objetivos
.......................................................................................................................................
81
2 Motivación
.......................................................................................................................................
81
3 Caso de estudio N.1 El cine (Código Fuente: unidadIIICaso01Cine)
........................................................... 81
3.1 Requisitos funcionales
.................................................................................................................... 82
3 2 Comprensión del mundo del
problema............................................................................................ 82
3 3 Diseño y construcción de la solución del problema
......................................................................... 84
3.4 Patrones para recorrido sobre matrices
.......................................................................................... 87
4 Caso de estudio N.2 El Bingo (Código Fuente: unidadIIICaso02Bingo)
....................................................... 88
3 5 Requisitos funcionales
.................................................................................................................... 89
3.6 Comprensión del mundo del
problema............................................................................................ 90
3.7 Diseño y construcción de la solución del problema
......................................................................... 92
4 Hoja de Trabajo N.1 El Triqui (Código Fuente:
unidadIIIHoja01Triqui)..................................................... 96
4.1 Requisitos funcionales
.................................................................................................................... 97
4 2 Comprensión del mundo del
problema............................................................................................ 97
4 3 Diseño y construcción de la solución del problema
......................................................................... 98
5 Hoja de Trabajo N 2 Concéntrese (Código Fuente: unidadII Hoja02JuegoParejas)
............................... 102
5.1 Requisitos funcionales
.................................................................................................................. 103
5 2 Comprensión del mundo del
problema.......................................................................................... 104
5 3 Diseño y construcción de la solución del problema
....................................................................... 104
PERSISTENCIA
.......................................................................................................................................
109
1 Objetivos
.......................................................................................................................................
109
2 Motivación
.......................................................................................................................................
109
3 Caso de estudio N.1 La Empresa (Código Fuente: unidadIVCaso01Empresa)
.......................................... 109
3.1 Requisitos funcionales
.................................................................................................................. 110
3 2 Comprensión del mundo del
problema.......................................................................................... 110
3 3 Diseño y construcción de la solución del problema
....................................................................... 112
3.4 Archivos
.......................................................................................................................................
112
3 5 Métodos de ordenamiento y búsqueda
......................................................................................... 116
3 5 Pruebas de
software.....................................................................................................................
122
4 Caso de estudio N.2 La Libreta Telefónica (Código Fuente:
unidadIVCaso02LibretaTelefonica) ........... 129
4.1 Requisitos funcionales
.................................................................................................................. 130
4 2 Comprensión del mundo del
problema.......................................................................................... 131
4 3 Diseño y construcción de la solución del problema
....................................................................... 131
4.4 Serializacion
.................................................................................................................................
135
5 Hoja de trabajo N.1 El Ahorcado (Código Fuente: unidadIVHoja01Ahorcado)
....................................... 136
5.1 Requisitos funcionales
.................................................................................................................. 137
5 2 Comprensión del mundo del
problema.......................................................................................... 137
5 3 Diseño y construcción de la solución del problema
....................................................................... 138
6 Caso de estudio N.2 La Tienda Paisa (Código Fuente:
unidadIVHoja01TiendaPaisa)........................... 141
6.1 Requisitos funcionales
.................................................................................................................. 142
6 2 Comprensión del mundo del
problema.......................................................................................... 143
6 3 Diseño y construcción de la solución del problema
....................................................................... 143
B BLIOGRAFIA.............................................................................................................
147
PREFACIO
El presente libro está inspirado en el proyecto CUPI2 realizado por la Universidad
de los Andes, cuyo principal propósito es encontrar mejores formas de
enseñar/aprender a resolver problemas haciendo uso de un lenguaje de
programación.
Para el entendimiento de este libro es necesario contar conconocimientos básicos
en:clases y objetos, expresiones, estructuras de decisión y ciclos.
El libro se estructura en 4 capítulos
1) Estructuras contenedoras de tamaño fijo. El lector podrá utilizar estructuras
repetitivas para resolver problemas que involucren el uso de estructuras
contenedoras estáticas y conocerá los diferentes patrones para recorrer este tipo
de estructuras. También se familiarizará con la metodología de Diseño por contrato
y el manejo de excepciones.
2) Estructuras contenedoras de tamaño variable. El lector estará en capacidad de
utilizar estructuras repetitivas para resolver problemas que involucren el uso de
estructuras contenedoras. Además, conocerá el método de ordenamiento Burbuja y
nuevos tipos de estructuras, tales como el foreach y enumeraciones.
3) Arreglos bidimensionales. El lector manejará el concepto de estructuras
contenedoras en dos dimensiones y podrá aplicar los diferentes patrones de
recorrido.
4) Serialización. El lector adquirirá reforzará su conocimiento respecto a
estructuras contenedoras yserá capaz de lograr que la información sea persistente,
para ello se incorporarán los temas de archivosProperties, serialización y
Generics. De igual forma, hará uso de excepciones personalizadas que le
permitirán garantizar que la información digitada es correcta.También, se
introducirá el concepto de pruebas con el JUnit. Finalmente se reforzarán los
conocimientos con respecto a métodos de ordenamiento y se incorporará el
concepto de búsqueda binaria.
El código fuente de cada uno de los ejemplos desarrollados en este libro se
encuentra en el CD anexo. Es de anotar, que todos los proyectos explicados
hacen uso de interfaz gráfica.
Para finalizar este prefacio es importante agradecer a la Universidad de los
Andespor su importante proyecto CUPI2, pues éste es fuente de inspiración para
muchas universidades y un importante avance para la solución del típico problema
de enseñar a programar.
ESTRUCTURAS CONTENEDORAS DE TAMAÑO FIJO
Objetivos
Al finalizar la unidad el estudiante estará en capacidad de:
Utilizar estructuras contenedoras de tamaño fijo para resolver problemas en los
cuales es necesario almacenar una secuencia de elementos del mismo tipo
Utilizar ciclos para poder manipular las estructuras contenedoras fijas
Utilizar la metodología de Diseño por contrato logrando con ello que a medida que
se programe se documente el código y se detecten errores.
Utilizar la clase Exception para capturar y manipular errores que pueden surgir en
tiempo de ejecución.
Motivación
En algunas ocasiones se requiere resolver problemas en los cuales es necesario
almacenar una secuencia de elementos, por ejemplo: un listado de estudiantes, de
productos o de empleados. Esta característica debe verse reflejada al momento de
construir el diagrama de clases. Además, al momento de plantear la soluciónese
grupo de elementos se debe materializar, es aquí en donde el aplica el concepto
de arreglos.
En este capítulo además de los arreglos se estudiarán otras temáticas, tales
como: ciclos, metodología de diseño por contrato y excepciones. Estás últimas
permitirán capturar y tratar los errores inesperados que surgen durante la ejecución
de un programa.
Caso de estudio N.1 La Empresa (Código Fuente: unidadICaso01Empresa)
Se desea crear una aplicación para manejar la información de una empresa, en la
cual hay 6 empleados. Cada empleado tiene un nombre, un código, una edad y un
salario. La aplicación debe permitir cambiar la información de cada empleado,
incrementar en un 10% el salario de todos los empleados, informar la cantidad de
empleados cuyo nombre inicia en la vocal especificada por el usuario, informar la
cantidad de empleados con edad superior a 30 e imprimir el salario promedio.
Descripción
Requisito funcional 4
Requisito funcional 5 Entrada
Salida
Nombre
Descripción Entrada
Salida
Nombre
Descripción Entrada
Salida
Modificar la información del empleado
El usuario podrá modificar cualquiera de los 4 datos del empleado. 1)El número del
empleado al que se le va a modificar la información 2) Los nuevos datos: nombre,
código, edad o salario
La información del empleado ha sido modificada
incrementar en un 10% el salario
Se requiere incrementar en un 10% el salario de todos los empleados
Ninguna
Se ha incrementado el salario a todos los empleados
Informar la cantidad de empleados cuyo nombre inicia en la vocal especificada por
el usuario
El usuario selecciona una de las cinco vocales y la aplicación debe informar
cuantos empleados tienen nombre que inicie en dicha vocal
La vocal
La cantidad de empleados con nombre que inicia en esa vocal Informar la cantidad
de empleados con edad superior a 30 Se deben contar los empleados que tienen
edad superior a 30 Ninguna
La cantidad de empleados con edad superior a 30
Informar el salario promedio
Se requiere calcular el salario promedio de la empresa
Ninguna
El salario promedio
3.2 Comprensión del mundo del problema
El modelo conceptual se puede definir a través de dos clases: Empleado y
Empresa, tal como se muestra a continuación:
elementos que seconocer la cantidad de elementos que se van a almacenar.
En Java todos los arreglos son objetos. Los arreglos pueden ser
unidimensionales, bidimensionales o multidimensionales, pero esta unidad se
concentra en los unidimensionales.
Todo arreglo debe declararse y se le debe reservar memoria para poder ser
utilizado. Un arreglo se declara de la siguiente forma: <tipo>[] <nombre>;
También es válido: <tipo><nombre>[];
Un ejemplo concreto de cómo se declara un arreglo es:
int[] edades;
ó int edades[];
Es importante resaltar, que hasta ahora solo se ha declarado el arreglo, no ha sido
creado. Para crear un arreglo se le debe reservar memoria, a través del
operadornew:
edades = new int[10];
También es posible iniciar un arreglo al momento de su declaración, ejemplo: int
edades[]={4,56,34,13};
Luego de que se reserva memoria Java inicializa los arreglos dependiendo del tipo
de dato, ejemplo si el arreglo es de enteros, se inicializa por defecto con ceros,
pero si es de objetos se inicializa con null.
Cuando se declara un arreglo se debe usar el operador de indexación “ []” . Este
indica que se va a almacenar una lista de elementos del mismo tipo. Gracias a
este operador es posible acceder a cada uno de los elementos almacenados en la
estructura contenedora fija. Ello se logra escribiendo primero el nombre del array,
seguido de los corchetes que tendrán en su interior una variable de tipo entero,
denominada índice, que indicará la posición a la cual se desea acceder. Ejemplo,
si se tiene el siguiente arreglo:
Empleado misEmpleados[];
misEmpleados=new Empleado[MAXIMO_EMPLEADOS];
y se desea tener acceso a la posición 2, una instrucción correcta sería:
if(misEmpleados[2]!=null&&
misEmpleados[2].getCodigo().equals(codigo)) {return
true;}
Lo anterior significa que si hay un empleado en la posición 2 y el código del
empleado corresponde con el buscado se retorna true.
Algunas características importantes de los arreglos son las siguientes:
1. Tienen una variable denominada length que permite conocer el tamaño del
arreglo o array.
2. Para poder acceder a los elementos del arreglo se utilizan corchetes [] y un
índice que varía entre 0 y la longitud del arreglo-1, es decir, arreglo length-1.
3. Se pueden crear arrays de objetos pero hay que tener precaución pues luego de
reservarle memoria al arreglo será necesario crear cada uno de los objetos que van
a almacenar.
Retomando el desarrollo del caso de estudio será necesario entonces declarar un
arreglo de Empleados, tal como se muestra a continuación:
publicclass Empresa {
//----------------------------------------------------
------------// Atributos
//----------------------------------------------------
------------
private Empleado misEmpleados[];
//----------------------------------------------------
------------// Constantes
//----------------------------------------------------
------------privatefinalstaticintMAXIMO_EMPLEADOS=6;
//----------------------------------------------------
------------// Constructor
//----------------------------------------------------
------------
/**
* Método constructor de la clase
* post: Se crea una empresa en la que pueden haber
máximo 6 empleados */
public Empresa()
{
misEmpleados=new Empleado[MAXIMO_EMPLEADOS];}
}
3.4 Recorrer los arreglos
Para poder recorrer un arreglo es necesario hacer uso de una estructura repetitiva.
Java posee tres estructuras repetitivas: el for, el while y el do-while.
Toda estructura repetitiva posee tres partes básicas, a saber:
Expresión condicional o Decisión
Cuerpo del ciclo: en esta parte se ponen las instrucciones que se desea ejecutar
repetitivamente un cierto número de veces.
Salida del ciclo
En general, los ciclos se controlan a través de un contador, una variable que
aumenta o disminuye su valor en una cantidad fija cada vez que se efectúa la
repetición.
También, es común encontrar dentro de los ciclos variables acumuladoras, las
cuales permiten almacenar una cantidad variable cada vez que se efectúa una
repetición. Por ejemplo, cuando se requiere realizar una sumatoria o sacar un
promedio.
La primera estructura que se analizará será el while. Esta estructura tiene la
siguiente forma:
while ( condición ) {
acción 1
........
acción n
}
En este tipo de estructura las acciones se repiten “ mientras” que se cumple una
determinada condición, la cual se especifica al inicio dentro de paréntesis.
Cuando se efectúa la última acción se debe volver a evaluar la condición que del
"while" para verificar si nuevamente se ejecutan las instrucciones o si por el
contrario se finaliza la ejecución del while.
El do-while, es una estructura que permite que las acciones se ejecuten almenos
una vez antes de que se verifique la condición de repetición.
do
{
acción 1
........
acción n
} while( condición );
En el while en principio se ejecutan todas las acciones y luego se evalúa la
condición, si ésta da como resultado true nuevamente se repiten las acciones, de
lo contrario se finaliza el ciclo.
La última estructura repetitiva, y la más usada para trabajar con arreglos, es el
ciclo for,que funciona de la siguiente forma:
for ( inicialización; condicion; iteración) {
acción 1
........
acción n
}
En el for lo primero que se ejecuta es la inicialización, la cual normalmente es una
expresión de asignación. La inicialización solo se efectúa una vez. A
continuación, se evalúa la condición y si da verdadero se ejecuta el cuerpo del
ciclo. En caso de que de false, el ciclo finaliza.
Luego se efectúa la iteración, que consiste en aumentar o disminuir la variable de
control del ciclo.
Ahora bien, luego de esta conceptualización se continuará con el desarrollo de
este caso de estudio Para responder a los requisitos funcionales es necesario
construir varios métodos, algunos de los cuales se explicarán a continuación:
El métodoincrementarEn10() se encarga de aumentar el salario de todos los
empleados en un 10% . Este método no requiere de parámetros. El método
funciona de la siguiente forma: Se crea un ciclo for que inicia en 0 y va hasta la
cantidad de empleados. Es importante preguntar en cada posición si se ha
registrado un empleado, es decir, si no es null. En caso de que sea así, se llama al
método setSalario para ese empleado y se le fija el nuevo salario.
publicvoid incrementarEn10()
{
for(int i=0; i<MAXIMO_EMPLEADOS;i++) {
if(misEmpleados[i]!=null)
{
misEmpleados[i].setSalario(misEmpleados[i].getSalario(
}
}
}
El método contarVocal es el encargado de informar la cantidad de empleados cuyo
nombre inicia en la vocal especificada por el usuario. Este método tiene un
parámetro, la vocal. Para poder conocer la cantidad de empleados cuyo nombre
inicia en dicha vocal se debe plantear una estructura repetitiva que permita recorrer
todo el arreglo y verificar en caso de que exista un empleado si su nombre inicia
en esa vocal.
publicint contarVocal(char vocal) {
int contador=0; String nombre="";
for (int i=0; i<MAXIMO_EMPLEADOS; i++)
{
if(misEmpleados[i]!=null)
{ nombre=misEmpleados[i].getNombre().toUpperCase();
if(nombre.charAt(0)==vocal)
{
contador++;
}
}
}
return contador;
}
Observe que a través de la instrucción:
nombre=misEmpleados[i].getNombre().toUpperCase();
Se captura el nombre del empleado y se pasa a mayúscula. Es importante que
tenga claro, que los códigos de las letras mayúsculas son diferentes a los de las
minúsculas.
En el método anterior se hizo uso del método charAt. Este permite obtener un
caracter de un String indicando la posición deseada, ejemplo si se desea obtener
la posición cero la instrucción válida es nombre.charAt(0), si se requiere la
posición 1 la instrucción es nombre.charAt(1), si se necesita la posición i se
escribe nombre.charAt(i).
El método contarEmpleadosMayores30() permite obtener la cantidad de empleados
con edad superior a 30. En éste se recorre todo el arreglo y a cada empleado
existente se le pregunta la edad. En caso de que la edad sea superior a 30 se
debe contabilizar.
publicint contarEmpleadosMayores30() {
int contador=0;
for (int i=0; i<MAXIMO_EMPLEADOS; i++) {
if(misEmpleados[i]!=null&&misEmpleados[i].getEdad()>30
{
contador++; }
}
return contador;
}
3.5 Patrones para instrucciones repetitivas
Un patrón es una solución genérica para un problema. Son tres los patrones que se
trabajarán referentes a estructuras repetitivas, ellos son1
:
a) Patrón de recorrido Total
Mediante este patrón se tiene acceso a cada una de las posiciones del arreglo, por
ello es necesario que el índice inicie en cero y se incremente de uno en uno hasta
llegar a la cantidad de elementos del arreglo-1. También, el índice podría iniciar en
la cantidad de elementos del arreglo-1 e ir decrementando de uno en uno hasta
llegar a cero.
Un ejemplo de este tipo de patrón es el siguiente:
publicdouble calcularPromedio() {
double acumulador=0;
int contador=0;
for (int i=0; i<MAXIMO_EMPLEADOS;i++) {
if(misEmpleados[i]!=null)
{
acumulador+=misEmpleados[i].getSalario(); contador++;
}
}
b) Patrón de Recorrido Parcial
Se recorre el arreglo y por cada elemento se verifica si ya se cumplió la condición
de finalización del ciclo, es decir, si el problema ya fue resuelto. Por ejemplo, se
necesita obtener el primer empleado con edad superior a 35 años, o buscar el
empleado cuya cédula es 415. Luego de encontrar el dato requerido no tiene
sentido seguirse moviendo en el arreglo.
1Estos patrones están descritos en el libro Fundamentos de
Programación. Aprendizaje activo Basado en Casos de Jorge
Villalobos y Rubby Casallas
publicint buscarEmpleado(String codigo)
{
for(int i=0; i<MAXIMO_EMPLEADOS;i++)
{
if(misEmpleados[i]!=null&&misEmpleados[i].getCodigo().e
{ return i;}
}
return -1;
}
Este mismo método se pudo haber planteadotambién de la siguiente forma:
publicint buscarEmpleado(String codigo) {
boolean centinela=false;
int posicion=-1;
for (int i=0;
i<MAXIMO_EMPLEADOS&&centinela==false;i++)
{
if(misEmpleados[i]!=null&&
misEmpleados[i].getCodigo().equals(codigo)) {
posicion=i; centinela=true;
}
}
return posicion;
}
En esta última forma se declara un booleano que controla la finalización del ciclo.
c) Patrón de doble recorrido
En este tipo de patrón por cada elemento del array se realiza un recorrido
completo.
public Empleado determinarMayorFrecuencia()
{
int edad, contador = 0, mayorFrecuencia = 0,
guardaContador = 0;
for ( int i = 0 ; i < misEmpleados.length ; i++ ) {
//Aquí se obtiene cada uno de los elementos del array
edad = misEmpleados [i].getEdad();
contador = 0;
for ( int j = 0 ; j < misEmpleados.length; j++ ) {
if( i != j )
{
if( edad == misEmpleados[j].getEdad() )
{
contador++; }
}
}
//Aquí se compara el contador de ocurrencias del
elemento actual con el contador //general
if( contador > guardaContador )
{ guardaContador = contador;mayorFrecuencia = i; }
}//Cierra el for
return misEmpleados[mayorFrecuencia];
}
3.6 El manejo de la memoria en Java
La memoria está dividida en tres zonas, a saber: la Zona de Datos, el Stack o
Memoria de pila y el Heap, o Memoria de montículo. En la primera de ellas, se
almacenan las instrucciones del programa, las constantes, los métodosy las
clases. En el Stack se guardan las referencias a objetos (es decir, instancias
creadas con new) y las variables de tipo de dato primitivo, másconcretamente,
parámetros y variables locales. En el Heap, la zona de memoria dinámica, se
almacenan los objetos creados. La forma como el heap y el stack interaccionan
puede verse en el siguiente gráfico:
Empleado misEmpleados[];
finalstaticintMAXIMO_EMPLEADOS=3;
misEmpleados=new Empleado[MAXIMO_EMPLEADOS];
misEmpleados[0]= new Empleado(2,3000);
edad, salario);
}
catch (Exception e1) {
JOptionPane.showMessageDialog(null, e1.getMessage());
}
}
Lo anterior puede interpretarse como:
Si se produce un error al llamarse el método agregarEmpleado se genera una
excepción que es capturada, logrando con ello que la ejecución del programa
salte al catch. Dentro del catch se solicita el mensaje del error que ha ocurrido a
través de la variable e1, el cual se imprime haciendo uso del JOptionPane.
Para forzar a que se ejecute algo después de generada una excepción se escribe
finally. El formato general es:
try
{…
}
catch (Exception e) {…
}
finally
{…
}
Si el objetivo es generar una excepción dentro de un método se utiliza throw.
Dichas excepciones se definen creando una subclase de Exception. Cuando
dentro de un método se lanza una excepción derivada de Exception es necesario
añadir la palabra reservada throws en la cabecera del método seguida de la lista
de excepciones que se pueden producir, ejemplo:
publicboolean agregarEmpleado(int posicion, String
codigo, String nombre, int horasTrabajadas,double
valorHora)throws EmpleadoRepetidoException {
if(buscarEmpleado(codigo)==-1)
{
Empleado miE=new
Empleado(codigo,nombre,horasTrabajadas,valorHora);
misEmpleados[posicion]=miE;
verificarInvariante( );
returntrue;
}
else
thrownew EmpleadoRepetidoException("El empleado ya
existe");
}
En el caso anterior se creó un nuevo tipo de excepción
denominadoEmpleadoRepetidoException. Ello se logró definiendo una subclase
del tipo Exception.
publicclass EmpleadoRepetidoException extends
Exception{ public EmpleadoRepetidoException(String
mensaje) {
super (mensaje); }
}
El proceso que se sigue para crear este tipo de clases consiste en crear una
nueva clase que extienda de Exception. En su interior se pone solamente un
método constructor, que recibe como único parámetro el mensaje de error que se
desea mostrar. En este caso, la instrucción super hace referencia al constructor de
la clase base, es decir, al constructor de Exception.
Es muy común que en los programas se definan excepciones propias que hereden
de la clase Exception, pues gracias a ello es posible representar situaciones
particulares para cada problema.
3.8 Diseño por contrato
El Diseño por contrato es una metodología que se popularizó por el lenguaje de
programación Eiffel y sefundamenta en la idea de que cada elemento de diseño es
un participante dentro de una relación análoga a un contrato de negocios. Es decir,
las relaciones entre las clases y sus clientes pueden interpretarse como un
acuerdo o contrato, en el que se expresan los deberes y derechos de cada uno de
los participantes. Esto permite que si ocurre algún problemacon remitirse al
contrato sea posibledeterminar quién era el responsable de ejecutar la tarea que
falló.
Para complementar lo anterior, es importante recordar que para asignar
responsabilidades es posible apoyarse en la técnica del experto o en la técnica
de descomposición por requerimientos. La primera de ellas se basa en la idea de
que el dueño de la información es el responsable de ella y la segunda, en que para
satisfacer un requisito funcional una forma apropiada es descomponerlo en
subproblemas para poder solucionar al requisito completo.
El Diseño por Contrato hace posible diseñar componentespartiendo del hecho que
se efectuaránunas determinadas condiciones de entrada y que se garantizará el
cumplimiento de ciertas condiciones de salida. De igual forma,considera que debe
haber propiedades que no varíen sin importar el procesamiento que se realice
dentro de un componente.
Partiendo de lo anterior, se puede afirmar que un contrato incluye tres tipos de
restricciones: invariante, precondición y postcondición.
- Una invariante es una condición booleana cuyo resultado siempre debe ser true
para todas las instancias de la clase. La invariante permite verificar la
consistencia de los atributos de la clase.
- Una precondición es un predicado que debe haberse efectuado antes de que se
realice una determinada operación.
- Una postcondición es un predicado que, luego de haber ejecutado una determinar
operación, debe ser verdadero.
El Diseño por Contrato ofrece entre otras ventajas las siguientes:
Un efectivo sistema para detectar y disminuir errores en el código, debido a la
clara definición de las especificaciones.
Una forma sencilla de documentar el codigo fuente a medida que se programa.
a. El contrato de un método
El contrato de un método incluye la especificación de las precondiciones y las
postcondiciones. Por ejemplo, si se considera el siguiente método:
publicboolean agregarEmpleado(int posicion, String
codigo, String nombre, int horasTrabajadas,double
valorHora)
Se puede decir que las condiciones previas, o precondiciones, que deben
cumplirse para que este método se ejecute son:
El array de empleados ya se declaró y se le reservó memoria El código no es
null, ni vacío
El nombre no es null, ni vacío
La cantidad de horas trabajadas es un número positivo El valor de la hora es un
número positivo
No se sabe si hay un empleado con este código
La precondición expresa las restricciones necesarias para que la operación
funcione de forma adecuada.
El resultado de la ejecución del método debe ser: Se agregó el empleado
Se produjo un error y no se pudo agregar
La precondición son las condiciones impuestas para que se dé el desarrollo del
método, mientras que la postcondición son los compromisos aceptados.
b.Documentación de los contratos
Para documentar los contratos es necesario apoyarse en Javadoc. Javadoc es
una herramienta que permite generar un conjunto de páginas web a partir de los
archivos de código que contengan los delimitadores /**… */.Javadoc permiteque la
arquitectura de la solución sea mucho más comprensible.
Para lograr una adecuada documentación del contrato se debenagregar
comentarios a cada uno de los métodos que componen el programa.
Un comentario permite agregar información suficiente para que otras personas
puedan entender lo que se ha hecho y el porqué de lo que se ha hecho.
Documentar no sólo es un acto de buena programación, es además una necesidad
para poder entender el programa a medida que crece y poder identificar posibles
fuentes de error.
Una correcta documentación facilita que un software pueda ser modificado a
futuro, ya sea por su creador o por cualquier otro programador que lo reemplace.
Cuando se documenta se debe explicar lo que no es evidente. Es decir, se debe
explicar por qué se hacen las cosas, en lugar de repetir lo que se hace. Cuando se
empiece la construcción del software es importante explicar:
Función de cada clase o paquete
La labor de cada método y cuál es su uso esperado
Por qué se declaró una variable
Cómo funciona el algoritmo que se está utilizando y que limitaciones tiene
Posibles mejoras que podrían realizarse
Es obligatorio poner documentación javadoc en los siguientes casos:
Al inicio de cada clase Acada atributo
Al inicio de cada método
La escritura de un comentario Javadoc exigen seguir una sintaxis. Deben iniciar
por "/**" y terminar por "*/":
/**
* Descripción clara, breve y contundente de lo que
hace. *
* @etiqueta texto para la etiqueta
*/
Una descripción de las posibles etiquetas a utilizar para documentar una clase se
muestra a continuación:
@author Nombre del autor
@version Información sobre la versión y fecha @see
Referencia con otras clases y métodos
En la documentación de los constructores y métodos se deben utilizar al menos
las etiquetas siguientes:
@param
@return
@exception ó @throws
La siguiente tabla ilustra las posibles etiquetas que pueden utilizarse para
documentar un método:
@param Nombre del parámetro
@return Si el métodono es void
@exception Nombre de la excepción ó
@throws
Descripción, uso y valores válidos
Descripción de lo que se debe devolver
Excepciones que pueden surgir durante la ejecución
Acontinuación se muestra un ejemplo de uso de algunas etiquetas Javadoc para
documentar el código:
- Al inicio de la clase
/**
*
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* $Id$
* Universidad del Quindío(Armenia- Colombia)
* Programa de Ingeniería de Sistemas y Computación
* Licenciado bajo el esquema Academic Free License
* Fundamentos de Algoritmia
* Ejercicio: unidadICaso01Empresa
* @author Sonia Jaramillo Valbuena
* @author Sergio Augusto Cardona
* @author Leonardo Hernández
*
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*/
package
uniquindio.fundamentos.unidadICaso01Empresa.mundo; /**
* Clase que representa una Empresa
*/
publicclass Empresa {
}
- Por cada método
/**
* Permite agregar un empleado.
* @param posicion La posicion del empleado que se
desea agregar. posicion>=0&& *
posicion<MAXIMO_EMPLEADOS
* @param codigo El código del empleado. codigo!=null
&& !codigo.equals(" ") * @param nombre El nombre del
empleado. nombre!=null && !nombre.equals(" ") * @param
horasTrabajadas Es la cantidad de horas que trabaja el
empleado. * horasTrabajadas>0
* @param valorHora Es el valor que se le paga al
empleado por cada hora * trabajada. valorHora>0
* @throws Exception Si existe un empleado con el mismo
codigo se lanza una * excepción indicando que no se
pudo agregar
*/
publicboolean agregarEmpleado(int posicion, String
codigo, String nombre, int horasTrabajadas,double
valorHora)throws EmpleadoRepetidoException {
if(buscarEmpleado(codigo)==-1)
{
Empleado miE=new Empleado(codigo,
nombre,horasTrabajadas,valorHora);
misEmpleados[posicion]=miE;
returntrue;
}
else
thrownew EmpleadoRepetidoException("El empleado ya
existe");
}
Luego de finalizar la documentación se puede generar el archivo html con la
documentación. Los pasos para ello son:
Es de anotar, que los modificadores utilizados y el tipo devuelto no forman parte de
la signatura del método.También, es importante recalcarque no puede haber dos
métodos que con la misma signatura en una misma clase.
Para el diseño de la signatura de un método se debe tener en cuenta las entradas
y salidas del requisito funcional que el método pretende resolver, además, del tipo
de dato de cada uno de los parámetros requeridos. Por ejemplo, si se tiene el
método:
publicboolean agregarEmpleado(int posicion, String
codigo, String nombre, int horasTrabajadas,double
valorHora)throws EmpleadoRepetidoException
Para poder cumplir con la responsabilidad de agregar un empleado el método
agregarEmpleado de la clase Empresa debe recibir la posición donde desea
agregar el empleado y los datos referentes a éste.
d. La invariante de la clase
El Diseño por Contrato requiere también la incorporación del concepto de
invariante. Una invariante es una condición booleana cuyo resultado siempre debe
ser true para todas las instancias de la clase. La invariante permite verificar la
consistencia de los atributos de la clase La invariante debe usarse al final del
constructor y de los métodos que modifican el estado del objeto.
La invariante hace uso de la instrucción assert. Un assert es una condición que se
debe dar en todo momento en un programa para que no se produzcan errores Hay
dos formas de escribir aseveraciones en Java:
assert (Expresión con resultado booleano) :
(Descripción del error) ; ó
assert (Expresión con resultado booleano) ;
Observe que en ambas declaraciones se inicia con la palabra assert.
Por cada clase debe construirse un método para verificar la invariante.
Acontinuación se incluyen los métodos verificarInvariante para la cada una de las
clases del caso de estudio de la Empresa.
verificarInvariante para la clase Empleado
// ---------------------------------------------------
-------------// Invariante
// ---------------------------------------------------
-------------/**
* Verifica que el invariante de la clase se cumpla. Si
algo falla, lanza un error * <br>
* <b>inv: </b><br>
* misEmpleados !=null<br>
* los códigos de los empleados son únicos <br>
*/
publicvoid verificarInvariante( )
{
assert (misEmpleados!=null) : "El arreglo no puede ser
null"; assert (verificarConsistencia()==true):"Hay
códigos repetidos"; }
verificarInvariante para la clase Empresa
// ---------------------------------------------------
-------------// Invariante
// ---------------------------------------------------
-------------
/**
* Verifica que el invariante de la clase se cumpla. Si
algo falla, lanza un * error <br>
* <b>inv: </b><br>
* misEmpleados !=null<br>
* los códigos de los empleados son únicos <br>
*/
publicvoid verificarInvariante( )
{
assert (misEmpleados!=null) : "El arreglo no puede ser
null"; assert (verificarConsistencia()==true):"Hay
c�digos repetidos"; }
publicboolean verificarConsistencia()
{boolean centinela=true;
int contador=0;
for(int i=0; i<MAXIMO_EMPLEADOS; i++)
{ contador=0;
for(int j=0; j<MAXIMO_EMPLEADOS; j++)
{
if(misEmpleados[i]!=null&&
misEmpleados[j]!=null&&misEmpleados[i].getCodigo().equa
go()))
{contador++;}
}
if(contador!=1)
{
returnfalse; }
}
return centinela;
}
Los assert en Eclipse no están habilitados por defecto. Para habilitarlos es
necesario dar clic en: Windows -> Preferences -> Java -> Installed JREs.
Luego hay que seleccionar el JDK y dar click el boton Edit y en el campo "Default
VM Arguments" escribir “ -ea” .
permitir eliminar una reservación indicando la cédula del cliente que la realizó.
1)cedula, 2)edad, 3)tipo, 4) Fecha de la solicitud (día, mes, año), 5)Hora de llegada
(discriminada por hora y minuto)
Se asigna una silla al cliente, siempre y cuando exista disponibilidad de acuerdo
a las preferencias del cliente y se le informa el valor a pagar
Liberar una silla
Se requiere cancelar una reservación ingresando para ello la cédula del cliente
que la realizó
cedula
Si efectivamente el cliente tenía reservada una silla, ésta reservación se cancela.
4.2 Comprensión del mundo del problema
El modelo conceptual se puede definir a través de 6 clases:Cine, Puesto,
Reservación, Fecha y Persona. El diagrama de clases de este caso de estudio se
muestra a continuación:
privateint dia, mes, anio;
privateint hora, minuto, segundo;
}
Adicionalmente, se requiere de los siguientes métodos:
- Un método constructor que permite crear una fecha con los datos del dia de hoy.
public Fecha()
{
// Usamos un calendario Gregoriano inicializado en el
día de hoy
GregorianCalendar gc = new GregorianCalendar( );
// Se obtienen los valores de dia, mes y año del
calendario dia = gc.get( Calendar.DAY_OF_MONTH );
mes = gc.get( Calendar.MONTH ) + 1;
anio = gc.get( Calendar.YEAR );
hora=gc.get( Calendar.HOUR );
minuto=gc.get( Calendar.MINUTE );
}
- Un método constructor par crear una fecha con el día, mes y año que el usuario
ingresa, además de la hora y de los minutos.
public Fecha(int dia, int mes, int anio, int hora, int
minuto) { this.dia = dia;
this.mes = mes;
this.anio = anio;
this.hora = hora;
this.minuto = minuto;
verificarInvariante();
}
El método calcularDiferenciaEnMinutos es el encargado de calcular la diferencia
en minutos entre dos fechas. Recibe como parámetro una fecha.
public Fecha calcularDiferenciaEnMinutos(Fecha
miFechaMayor) {
GregorianCalendar
menor=devolverGregorianCalendar(this);
GregorianCalendar
mayor=devolverGregorianCalendar(miFechaMayor); long
diferencia = mayor.getTime().getTime()-
menor.getTime().getTime(); double minutos = diferencia
/ (1000 * 60);
int horas = (int) (minutos / 60);
int minuto = (int) (minutos%60);
returnnew Fecha(0,0,0,horas,minuto);
}
El método devolverGregorianCalendar recibe un objeto de tipo Fecha y lo
convierte a Calendario Gregoriano
public GregorianCalendar
devolverGregorianCalendar(Fecha miFecha)
{
GregorianCalendar gcMenor = new GregorianCalendar( );
gcMenor.set(miFecha.getAnio(), miFecha.getMes()-1,
miFecha.getDia(), miFecha.getHora(),
miFecha.getMinuto());
return gcMenor;
}
Acontinuación se sobreescribe el método equals. Este método tiene como
objetivo comparar dos objetos de tipo Fecha, si son iguales devuelve true, de lo
contrario false.
publicboolean equals(Object o)
{
Fecha miFecha=(Fecha)(o);
if(dia==miFecha.getDia()&&anio==miFecha.getAnio()&&mes=
{ returntrue;}
else
{returnfalse;} }
Adicionalmente, se requiere construir la clase Persona
ACTIVIDAD
Complete la declaración de la clase Persona. Debe incluir los atributos, el
constructor y los métodos get y set.
publicclass Persona {
//----------------------------------------------------
--------//Atributos
//----------------------------------------------------
--------
//----------------------------------------------------
--------//Constructor
//----------------------------------------------------
--------public Persona(String cedula, int edad) {
}
//----------------------------------------------------
--------//Métodos
//----------------------------------------------------
--------
public String getCedula() { return cedula;
}
publicvoidsetCedula(String cedula) {
}
publicint getEdad() {
} publicvoid setEdad(int edad) {
} }
Por otro lado, en la clase Puestose deben declarar los siguientes atributos:
//----------------------------------------------------
------------// Atributos
//----------------------------------------------------
------------/**
* Es el número del puesto
*/
privateint numero;
/**
* Es el tipo del puesto, puede tomar los valores de
GENERAL O PREFERENCIAL
*/
privateint tipo;
/**
* Es el estado del puesto. El estado del puesto puede
ser ESTADO_LIBRE o
* ESTADO_OCUPADO
*/
privateint estado;
/**
* Es el arreglo de reservaciones */
private Reservacion misReservaciones[]; /**
* Es el contador de reservaciones */
privateint contadorReservaciones=0;
//----------------------------------------------------
------------//Constantes
//----------------------------------------------------
------------/**
* Representa al tipo general
*/
publicstaticfinalintGENERAL=1;
/**
* Representa al tipo preferencial
*/
publicstaticfinalintPREFERENCIAL=0;
/**
* Representa al estado libre
*/
publicstaticfinalintESTADO_LIBRE=0;
/**
* Representa al estado ocupado
*/
publicstaticfinalintESTADO_OCUPADO=1;
Se declara una estructura contenedora de 200 posiciones para poder manejar todo
lo referente a las reservaciones que se hagan sobre un puesto específico.
Se declaran 4 constantes, las dos primeras permiten representar los posibles tipos
de puestos (GENERAL y PREFERENCIAL) y las dos últimas permiten representar
los posibles valores del atributo estado (ESTADO_LIBRE y ESTADO_OCUPADO)
Algunos de los métodos más relevantes de la clase Puesto son:
- El constructor de la clase Puesto permite reservarle memoria al array de
Reservaciones.
public Puesto()
{
misReservaciones=new Reservacion[200]; }
- El método agregarReservacion tiene varios parámetros: String cedula, int
edad,int dia, int mes, int anio, int hora, int minuto yint tipo. Este método es el
encargado de crear una nueva reservación, siempre y cuando no se exceda el
máximo de reservaciones por puesto, es decir, 200. Cada vez que se genera una
reservación el estado del puesto se pone en ocupado.
public boolean agregarReservacion(String cedula,int
edad,int dia, int mes, int anio, int hora, int minuto,
int tipo)
{
Reservacion nueva=new Reservacion(new Persona(cedula,
edad),new Fecha(dia,mes,anio,hora,minuto),tipo);
if(contadorReservaciones<200)
{
misReservaciones[contadorReservaciones]=nueva;
contadorReservaciones++;
estado=ESTADO_OCUPADO;
return true;
}
return false;
}
Por último, se tiene la clase Cine, en la cual es necesario declarar un arreglo de
Puestos. Algunos de los métodos de esta clase son:
- El método constructor de la clase Cine. Aquí se le reserva memoria al arreglo de
puestos y también a cada puesto.
public Cine ()
{
//Se le reserva memoria al arreglo misPuestos=new
Puesto[MAXIMO];
//Se le reserva memoria a cada uno de los puestos que
hay en el arreglo for(int i=0; i<MAXIMO; i++)
{
misPuestos[i]= new Puesto();
misPuestos[i].setNumero(i+i);
misPuestos[i].setEstado(Puesto.ESTADO_LIBRE);
if (i>14)
misPuestos[i].setTipo(Puesto.GENERAL); else
misPuestos[i].setTipo(Puesto. PREFERENCIAL); }
}
- El método ubicarPersona tiene varios parámetros: String cedula, int edad, int tipo,
int dia, int mes, int anio, int hora yint minuto. Este método recorre el arreglo de
puesto, para ello se apoya en la preferencia que el cliente desea. Cuando
encuentra un puesto libre acorde a la preferencia solicitada le agrega una
reservación.
publicint ubicarPersona(String cedula, int edad, int
tipo, int dia, int mes, int anio, int hora, int
minuto)
{
int inicio=0, finaliza=14;
//Se verifica que la persona no esté ya sentada en el
cine if(buscarPersona(cedula, new Fecha(dia, mes,
anio,hora, minuto))==false) {
if(tipo==Puesto.GENERAL)
{
inicio=14; finaliza=56;
}
for(int i=inicio; i< finaliza;i++)
{
if(misPuestos[i].getEstado()==Puesto.ESTADO_LIBRE)
{
misPuestos[i].agregarReservacion(cedula, edad, dia,
mes, anio, hora, minuto,tipo);
return i;
}
}
}
return -1;
}
El método buscarPersona recibe la cédula de la persona y la fecha en la cual se le
realizó la reservación, en caso de que exista la reservación devuelve true.
publicboolean buscarPersona(String cedula, Fecha miF)
{
Fecha actual=new Fecha();
for (int i=0; i<MAXIMO; i++)
{
if(misPuestos[i].getContadorReservaciones()>=1&&
misPuestos[i].getMisReservaciones()
[misPuestos[i].getContadorReservaciones()1].getMiPerson
misPuestos[i].getEstado()==Puesto.ESTADO_OCUPADO&&
misPuestos[i].getMisReservaciones()
[misPuestos[i].getContadorReservaciones()1].getMiFechaE
{
returntrue;
}
}
returnfalse;
}
El método liberarEspacio recorre el arreglo de puestos y por cada uno de ellos
verifica si está ocupado. En tal caso compara la cedula de la persona que está
ocupando el puesto con la del cliente buscado, si son iguales pone el estado de la
silla en libre. Finalmente devuelve la posición donde estaba ubicada la persona y
el valor que debe pagar.
public ResultadoLiberacion liberarEspacio(String
cedula)
{
for(int i=0; i<MAXIMO; i++)
{
if(misPuestos[i].getContadorReservaciones()>=1&&misPue
()[misPuestos[i].getContadorReservaciones()
1].getMiPersona().getCedula().equals(cedula)&&
misPuestos[i].getEstado()==Puesto.ESTADO_OCUPADO)
{
misPuestos[i].setEstado(Puesto.ESTADO_LIBRE);
returnnew
ResultadoLiberacion(misPuestos[i].getMisReservaciones(
[misPuestos[i].getContador
Reservaciones()-1].calcularValorAPagar(), i);
}
}
returnnull;
}
}
Hoja de trabajo 1 La Biblioteca (Código Fuente: unidadIHoja01Biblioteca)
Un cliente requiere una aplicación para manejar la información de una Biblioteca.
La Biblioteca tiene un listado de autores, uno de libros, uno de clientes y otro de
préstamos. Cada una de estas listas tiene una cantidad máxima de 100.
La aplicación debe permitir:
Agregar un nuevo cliente, para lo cual se solicita su nombre y código
Agregar un nuevo autor, para lo cual se ingresa el código y nombre del autor
Agregar un nuevo libro ingresando código, nombre, cantidad de existencias,
género y listado de autores, los cuales deben previamente existir en el sistema.
Realizar un nuevo préstamo.
Informar cuál ha sido el libro más prestado
Informar que libros ha escrito un determinado autor
Listar los libros prestados por un determinado usuario
Listar los autores de un libro
Requisito funcional 4 Salida
Nombre
Descripción
Entrada
Requisito funcional 5
Requisito funcional 6 Salida
Nombre
Descripción Entrada
Salida
Nombre
Descripción
Entrada
Requisito funcional 7 Salida
Nombre
Descripción Entrada
Requisito funcional 8 Salida
Nombre
Descripción Entrada
Salida
Agregar un nuevo cliente
Se debe agregar un nuevo cliente proporcionando para ello su información básica.
No se podrán agregar clientes que existan ya en el sistema.
1)nombre y 2)código
Un nuevo cliente ha sido agregado.
Agregar un nuevo autor
Se debe agregar un nuevo autor proporcionando para ello su información básica.
No se podrán agregar autores que existan ya en el sistema.
1)nombre y 2)código
Un nuevo autor ha sido agregado.
Agregar un nuevo libro
Se debe agregar un nuevo libro. No se podrán agregar libros que existan ya en el
sistema.
1) codigo,2)nombre, 3)cantidad de existencias, 4)género y 5)listado de autores
Un nuevo libro ha sido agregado
Realizar un nuevo préstamo
Se debe permitir agregar un nuevo préstamo. Es importante estar verificando que si
haya libros disponibles para prestar y que ha ese cliente no se le hay prestado ese
libro ya.
1) La posición en la cual está ubicado el libro dentro del arreglo de libros, 2) La
posición donde está ubicado el cliente que desea hacer el préstamo dentro del
arreglo de clientes
Un nuevo préstamo ha sido creado
Informar cuál ha sido el libro más prestado
Se debe devolver el libro que ha sido más prestado
Ninguna
El libro más prestado
Informar que libros ha escrito un determinado autor
Se selecciona el autor de un listado y se envía la posición donde estaba ubicado
para poder buscar los libros que éste ha escrito La posición donde está ubicado el
autor dentro del arreglo de autores.
El listado de libros
Listar los libros prestados por un determinado usuario
Se deben listar los libros prestados por un determinado usuario La posición donde
está ubicado el usuario dentro del arreglo de usuarios
El listado de libros prestados
Listar los autores de un libro
Se debe permitir listar los autores de un libro
1)posición donde está ubicado el libro dentro del arreglo de libros El listado de
autores del libro
5.2 Comprensión del mundo del problema
Se pueden identificar diferentes entidades: Biblioteca, Cliente, Autor, Libro y
Préstamo:
}
public String toString()
{
return "cedula "+cedula+ " nombre "+nombre;
}}
El método toString devuelve la representación en String del objeto, en el caso del
Autor se devuelve la cédula y el nombre.
publicclass Cliente { private String cedula, nombre;
public Cliente (String cedula, String nombre) {
this.cedula = cedula;
this.nombre = nombre;
}
public String toString()
{
return "cedula "+cedula+ " nombre "+nombre;
}}
Por otro lado, en la clase Libro se requiere declarar los siguientes atributos:
publicclass Libro {
//----------------------------------------------------
------------// Atributos
//----------------------------------------------------
------------/**
* Ese el código isbn del libro
*/
private String codigo;
/**
* Es el nombre del libro
*/
private String nombre;
/**
* La cantidadDeExistencias representan la cantidad de
copias que hay por libro. */
privateint cantidadDeExistencias;
/**
* El género es un entero 0--> Programación, 1-->Bases
de datos, * 2-->Compiladores, 3-->Arquitectura
*/
privateint genero;
/*
* El array que contiene el listado de autores */
private Autor misAutores[];
/*
* Lleva la cuenta de los autores agregados */
privateint contadorAutores;
//----------------------------------------------------
------------//Constantes
//----------------------------------------------------
------------
/**
* Es la cantidad máxima de autores
*/
publicstaticfinalintMAXIMO_AUTORES=5;
El constructor de la clase Libro permite inicializar los atributos de la clase, por ello
recibe el código del libro, el nombre, la cantidad de existencias y el género. En
este mismo método se le reserva memoria al arreglo de autores.
public Libro(String codigo, String nombre, int
cantidadDeExistencias, int genero) {
this.codigo=codigo;
this.nombre=nombre;
this.cantidadDeExistencias=cantidadDeExistencias;
this.genero=genero;
misAutores=new Autor[MAXIMO_ACTORES];
}
El método agregarAutor tiene como parámetro un objeto de tipo autor. Antes de
asignar el autor al libro se debe verificar que no se exceda la cantidad de autores
máxima, es decir, 5.
publicvoid agregarAutor(Autor miAutor) {
if(contadorAutores<misAutores.length) {
misAutores[contadorAutores]=miAutor;
contadorAutores++;
}
}
En la clase Préstamo se declaró como atributo el libro y el cliente que va a realizar
la solicitud. En esta clase solo es necesario construir el método constructor, que
lleva dos parámetros, y los respectivos métodos get para cada uno de los atributos
de la clase.
publicclass Prestamo {
//----------------------------------------------------
------------// Atributos
//----------------------------------------------------
------------/**
* Es el libro que se va a prestar
*/
private Libro miLibro;
/**
* Es el cliente al que se le va a prestar el libro */
private Cliente miCliente;
}
Finalmente, se debe construir la clase Biblioteca. En esta clase se han declarado
los siguientes atributos:
publicclass Biblioteca{
//----------------------------------------------------
------------// Atributos
//----------------------------------------------------
------------/**
* Es el arreglo de autores
*/
private Autor[] misAutores;
/**
* Es el arreglo de clientes
*/
private Cliente[] misClientes;
/**
* Es el arreglo de libros
*/
private Libro[] misLibros;
/**
* Es el arreglo de prestamos
*/
private Prestamo[] misPrestamos;
/**
* Es el contador de autores
*/
privateint contadorAutores;
/**
* Es el contador de clientes
*/
privateint contadorClientes;
/**
* Es el contador de libros
*/
privateint contadorLibros; /**
* Es el contador de prestamos
*/
privateint contadorPrestamos;
//----------------------------------------------------
------------//Constantes
//----------------------------------------------------
------------publicstaticfinalintMAXIMO=100;
}
ACTIVIDAD
Acontinuación se muestran algunos de los métodos más relevantes de la clase
Biblioteca. Rellene los métodos que así lo requieran.
El método buscarCliente recibe el código del cliente y recorre el arreglo de clientes
en su búsqueda.
public Cliente buscarCliente(String codigo) {
for(int i=0; i<contadorClientes; i++) {
if(misClientes[i].getCodigo().equals(codigo)) return
misClientes[i];
}
returnnull; }
/**
* Este método permite agregar un cliente, para ello se
recibe un codigo * y un nombre. Es de anotar que antes
de agregar se verifica que el * cliente no exista en
el sistema, porque no pueden haber clientes con * el
mismo codigo, para ello se hace uso del método
buscarCliente. En * caso de que buscarCliente retorne
null es porque el cliente no existe, * de lo contrario
se retorna el cliente encontrado
* @param codigo El código del cliente, codigo!=null
* @param nombre El nombre del cliente, nombre!=null
* @return true en caso de que el cliente se agregue
satisfactoriamente
*/
publicboolean agregarCliente(String codigo, String
nombre)
{
if(buscarCliente(codigo)==null&&
contadorClientes<MAXIMO) {
}
returnfalse;
El método asignarAutorLibro recibe la posición del autor dentro del arreglo de
autores, con dicha posición obtiene el autor y se lo asigna al último libro.
publicvoid asignarAutorLibro(int i) {
Autor miAutor=misAutores[i];
misLibros[contadorLibros-1].agregarAutor(miAutor);
}
/**
* Permite listar todos los autores de un libro
* @param posicion Es la posicion en la cual está
ubicada el libro dentro * del array de Libros
* @return un array de String con el listado de autores
del libro
*/
public String[] listarAutoresLibro(int posicion)
{
String salida[]=new String[5]; Libro
miLibro=misLibros[posicion];
for(int i=0; i< miLibro.getContadorAutores();i++) {
} return salida; }
/**
* Permite listar los libros que un usuario tiene
prestados * @param posicion La posicion del usuario
dentro del array de usuarios * @return un array de
string con el listado de los libros */
public String[] listarLibrosPrestadosPorUsuario(int
posicion) {
Cliente miCliente=misClientes[posicion]; String
prestados[]=new String[100]; int contador=0;
for(int i=0; i<contadorPrestamos; i++) {
}
return prestados; }
devolverCantidadExistenciasPrestadasPorLibro permite devolver la cantidad de
existencias prestadas que hay de un libro. Con un for se recorre el array de
préstamos y se busca el libro si lo encuentra se debe contar. Al final se devuelve
el contador.
publicint
devolverCantidadExistenciasPrestadasPorLibro(String
codigo) {
int contador=0;
for(int i=0; i<contadorPrestamos; i++)
{
if(misPrestamos[i].getMiLibro().getCodigo().equals(cod
{
contador++;
}
}
return contador; }
El método prestarLibro recibe la posición del libro y la posición del cliente para
poder realizar el préstamo.
/**
* Permite prestar una libro
* @param posicionL La posicion del libro dentro del
arreglo de libros * @param posicionCliente La posicion
del cliente dentro del array de * clientes
* @return true si se pudo prestar el libro
*/
publicboolean prestarLibro(int posicionL, int
posicionCliente ) {
/*
* Se debe obtener el libro y el cliente, al igual que
la cantidad de * existenciasprestadas por ese libro.
Es importante tener en cuenta que * si solo hay por
ejemplo 3 existencias de ese libro y ya todos están *
prestados no podrá prestar más.
* De igual forma se verifica que ese prestamo no haya
sido efectuado ya, * eso quieredecir que si el cliente
con codigo 123 prestó el libro 45, * entonces este
cliente no podrá volver a prestar ese libro */
Libro miLibro=misLibros[posicionL];
Cliente miCliente=misClientes[posicionCliente];
int
cantidadPrestamos=devolverCantidadExist
if
(cantidadPrestamos<miLibro.getCantidadDeExistencias()&
o(miLibro, miCliente)==false)
{
Prestamo miP = new Prestamo(miLibro, miCliente);
misPrestamos[contadorPrestamos]=miP;
contadorPrestamos++;
verificarInvariante();
returntrue;
}
returnfalse;
/**
* Devuelve el libro mas prestado * @return El libro
mas prestado */
6.1 Requisitos funcionales
Para resolver este caso de estudio se identificaron los siguientes requisitos
funcionales:
Requisito funcional 1 Nombre
Descripción
Requisito funcional 2 Entrada
Salida
Nombre
Descripción
Entrada
Requisito funcional 3 Salida
Nombre
Descripción Entrada
Requisito funcional 4
Requisito funcional 5
Requisito funcional 6 Salida
Nombre
Descripción Entrada
Salida
Nombre
Descripción Entrada
Salida
Nombre
Descripción Entrada
Salida
Agregar un docente
Se debe permitir agregar un docente al listado general de docentes. Es importante
verificar que el docente no exista en el sistema. 1)código, 2)nombre
Un nuevo docente ha sido agregado
Agregar un grupo
Se debe permitir agregar un grupo al listado general. Es importante verificar que el
grupo no exista ya en el sistema.
1) numero,2) nombre del Grupo,3) código del líder del grupo,4)el listado de
integrantes del grupo
Un nuevo grupo ha sido agregado
Asignar un producto a un grupo
Se debe permitir asignar un producto a un grupo
1)La posición del grupo dentro del arreglo de grupos, 2) el tipo de producto ,3) El
código del grupo, 4) el listado de docentes que crearon el producto
Un nuevo producto se le asigna al grupo
Listar todos los grupos
Se debe generar un listado con la totalidad de grupos
Ninguna
El listado de grupos
Listar productos de un grupo
Se debe permitir el listado de productos de un determinado grupo 1) La posición
del grupo dentro del arreglo de grupos
El listado de productos del grupo indicado
Listar todos los docentes
Se debe permitir listar todos los docentes que hay en la universidad Ninguna
El listado de docentes
6.2 Comprensión del mundo del problema
Se pueden identificar diferentes entidades: Universidad, GrupoDeInvestigacion,
Docente y Producto.
También es necesario un método constructor, los correspondientes métodos get
para cada uno de los atributosy el método toString.
public String toString()
{
return " Código: "+codigo+" Nombre: "+ nombre; }
La clase GrupoDeInvestigacion tiene entre otros los siguientes métodos:
El método agregarProducto tiene 4 parámetros, a saber: el tipo, el codigo y el
listado de docentes que crearon el producto. Antes de agregar el producto se debe
verificar que no se exceda el máximo de productos, es decir, 100.
publicvoid agregarProducto(int tipo, String codigo,
Docente misDocentes[] ) {
if(contadorProductos<MAXIMO)
{
Producto aux=new Producto(tipo,codigo,misDocentes);
misProductos[contadorProductos]=aux;
contadorProductos++;
}
}
El método agregarIntegranteGrupo se encarga de agregar un nuevo integrante al
grupo. Es importante verificar que dicho docente ya no existe en el grupo, con el
objetivo de evitar repeticiones.
publicvoid agregarIntegranteGrupo(Docente
miIntegrante) {
if(buscarDocente(miIntegrante.getCodigo(),misIntegrante
{
for (int i=0; i<misIntegrantes.length;i++) {
if(misIntegrantes[i]==null) {
misIntegrantes[i]=miIntegrante; }
}
} }
El método devolverProductosGrupo() devuelve el listado de productos del grupo.
public String[] devolverProductosGrupo()
{
//Se recorre el arreglo de misProductos y se verifica
si en esa posición //hay producto, en tal caso se
agrega al arreglo productos la //representación en
String de dicho producto
String productos[]=new String[MAXIMO];
return productos; }
Por otro lado, de la clase Producto los atributos son los siguientes:
//----------------------------------------------------
------------// Atributos
//----------------------------------------------------
------------/**
* Es el tipo del producto. Puede ser articulo (1) o
libro (0) */
privateint tipo;
/**
* Es el código del producto
*/
private String codigo;
/**
* Es el listado de docentes que crearon el producto
*/
private Docente misDocentes[];
}
El constructor de la clase Producto permite inicializar los 3 atributos de la clase.
public Producto(int tipo, String codigo,Docente
misDocentes[]) {
this.misDocentes=misDocentes;
this.tipo=tipo;
this.codigo=codigo;
}
El método listarAutores Devuelve un String con el listado de autores.
public String listarAutores() {
String s="";
for(int i=0; i<misDocentes.length;i++)
{
if(misDocentes[i]!=null)
s+=misDocentes[i].getNombre()+" , "; }
return s;
}
Para finalizar la solución de este caso de estudio se debe construir la clase
Universidad. Sus atributos se muestran a continuación:
publicclass Universidad {
//----------------------------------------------------
------------// Atributos
//----------------------------------------------------
------------/**
* Es el listado de grupos de investigacion
*/
private GrupoDeInvestigacion
misGruposDeInvestigacion[]; /**
* Es el listado general de docentes
*/
private Docente misDocentesGeneral[];
//----------------------------------------------------
------------//Constantes
//----------------------------------------------------
------------/**
* Es la constante para manejar el número máximo de
docentes y grupos */
privatestaticfinalintMAXIMO=100;
}
Se destacan los siguientes métodos:
El método agregar docente se encarga de insertar un nuevo docente en el arreglo
de general de docentes. Tiene dos parámetros el código y el nombre.
publicint agregarDocente(String codigo, String nombre)
{
int pos=GrupoDeInvestigacion.buscarDocente(codigo,
misDocentesGeneral); if(pos==-1)
{
for (int i=0; i<misDocentesGeneral.length;i++) {
if(misDocentesGeneral[i]==null) {
misDocentesGeneral[i]=new Docente(codigo, nombre);
return i;
}
}
}
return -1;
}
El método buscarGrupo recibe el código del grupo que se desea hallar. Debe
recorrer el arreglo de grupos en su búsqueda. En caso de encontrarlo devuelve la
posición donde está, de lo contrario retorna -1.
publicint buscarGrupo(int numero) {
}
El método agregarGrupo recibe la información necesaria para crear un nuevo grupo
de investigación, a saber: el número del grupo, el nombre, el código del líder y un
arreglo con las posiciones dentro del array de docentes de las personas que van a
incorporarse.
publicint agregarGrupo(int numero,String
nombreGrupo,String codigoLid,int integrantes[])
{
int posicionEnArregloDelGrupo=0;
int
posicionLiderEnArregloGeneral=GrupoDeInvestigacion.bus
misDocentesGeneral);
Docente misDocentesDelGrupo[]=new
Docente[integrantes.length];
for(int i=0; i<misDocentesDelGrupo.length; i++)
{
misDocentesDelGrupo[i]=misDocentesGeneral[integrantes[
if(misDocentesDelGrupo[i].getCodigo().equals(misDocente
regloGeneral].getCodigo()))
{
posicionEnArregloDelGrupo=i;
}
}
GrupoDeInvestigacion miGrupo= new
GrupoDeInvestigacion();
miGrupo.setMisIntegrantes(misDocentesDelGrupo);
miGrupo.setNombreGrupo(nombreGrupo);
miGrupo.setNumero(numero);
miGrupo.setPosicionLider(posicionEnArregloDelGrupo);
if (buscarGrupo(numero)==-1)
{
for(int i=0; i<misGruposDeInvestigacion.length;i++) {
if(misGruposDeInvestigacion[i]==null) {
misGruposDeInvestigacion[i]=miGrupo; return i;
}
}
}
return -1;
}
Finalmente, el método agregarProductoAGrupo recibe la posicion del grupo al cual
se le asignará, ya sea el libro o el artículo, además del listado de integrantes que
elaboró el producto.
publicvoid agregarProductoAGrupo(int posGrupo, int
tipo, String codigo, int integrantes[])
{
Docente misDocentesDelGrupo[]=new
Docente[integrantes.length]; for(int i=0;
i<misDocentesDelGrupo.length; i++)
{
misDocentesDelGrupo[i]=misDocentesGeneral[integrantes[
}
Producto miProducto=new Producto(tipo, codigo,
misDocentesDelGrupo);
misGruposDeInvestigacion[posGrupo].agregarProducto(tipo
codigo, misDocentesDelGrupo);
}
ESTRUCTURAS CONTENEDORAS DE TAMAÑO VARIABLE
1 Objetivos
Al finalizar la unidad el estudiante estará en capacidad de:
Utilizar estructuras contenedoras de tamaño variable para resolver problemas en
los cuales es necesario almacenar una secuencia de elementos cuya cantidad no
se conoce con anterioridad.
Utilizar ciclos para poder manipular las estructuras contenedoras variables
2 Motivación
Algunas veces se requiere resolver problemas en los cuales es necesario
almacenar una secuencia de elementos, pero no se sabe cuántos. Esta
característica obviamente debe verse reflejada en el diagrama de clases. Además,
al momento de plantear la solución, ese grupo de elementos se debe materializar,
es aquí en donde el aplica el concepto de ArrayList.
3 Caso de estudio N.1 Conjuntos (Código Fuente:
unidadIICaso01Conjuntos)
Se requiere de una aplicación que permita realizar las operaciones de intersección
y unión entre varios conjuntos. Se debe permitir también que se eliminen todos los
conjuntos que se han agregado hasta el momento. El resultado de las operaciones
de unión e intersección se deben mostrar ordenados alfabéticamente.
Requisito funcional 4 Entrada
Salida
Nombre
Descripción
Entrada
Salida
Nombre
Descripción
Entrada Salida
Hallar la intersección entre varios conjuntos
Se debe hallar la intersección entre todos los conjuntos que el usuario haya
ingresado hasta el momento. La intersección consiste en encontrar los elementos
que son comunes en todos los conjuntos.
Ninguna
Un nuevo conjunto con el resultado de la intersección
Hallar la unión entre varios conjuntos
Se debe hallar la unión entre todos los conjuntos que el usuario haya ingresado
hasta el momento.
Ninguna
Un nuevo conjunto con el resultado de la unión
Ordenar alfabéticamente los elementos de un conjunto
Se recibe un conjunto y se aplica un método de ordenamiento para lograr que los
elementos queden ubicados de menor a mayor Un conjunto
El conjunto ordenado
Eliminar los conjuntos
Se debe permitir borrar todos los conjuntos que se han ingresado hasta el
momento
Ninguna
Los conjuntos han sido eliminados
3.2 Comprensión del mundo del problema
Se pueden identificar diferentes entidades: GrupoConjunto y Conjunto.
3.3 Diseño y construcción de la solución del problema
Este caso de estudio requiere de la utilización de estructuras contenedoras de
tamaño variable, en la cuales no se requiere que se conozca su tamaño máximo
tal como ocurre en los arreglos, pues crece o disminuye dinámicamente.
En Java existen varias clases que permiten crear este tipo de estructuras, entre
ellas la clase Vector o la clase ArrayList. En este documento se hará uso de la
segunda.
Cuando se debe representar en el diagrama de clases este tipo de asociaciones
se coloca como cardinalidad los símbolos 0…* para aclarar que su tamaño puede
variar.
Todo ArrayList debe declararse y se le debe reservar memoria. Tal como se
muestra a continuación:
private ArrayList <Conjunto> misConjuntos ;
public GrupoConjunto()
{
misConjuntos=new ArrayList<Conjunto>();
}
En la clase GrupoConjunto se declara un Vector donde cada elemento corresponde
a un conjunto. Para que esto sea posible es necesario importar el paquete
java.util.*;
Observe que al momento de reservarle memoria no fue necesario indicar la
cantidad de elementos que iba a contener. Esto quiere decir, que automáticamente
se arranca con 0 elementos dentro de él. No obstante, ArrayList también brinda la
posibilidad de definir un tamaño inicial:
misConjuntos=new ArrayList<Conjunto>(9);
En este caso se ha creado un ArrayList con un tamaño inicial de 9. Algunos de los
métodos más importantes de los ArrayList son:
size(): Devuelve la cantidad de elementos que hay en la estructura
isEmpty(): Devuelve true si no hay elementos en el ArrayList, de lo contrario
devuelve false.
add(elemento): permite agregar al final de la estructura contenedora un nuevo
elemento.
add(posición, elemento): permite agregar un elemento en la posición indicada. Si
ya había un elemento en esa posición, el elemento que ya existe y todos los que
se encuentran a su derecha se correrán una posición hacia la derecha.
set(posición, elemento): Permite reemplazar el elemento que se encuentra en la
posición por un nuevo elemento.
remove (posición): borra el elemento que está en la posición indicada, esto implica
que los elementos que estaban a la derecha del elemento eliminado se correrán
hacia la izquierda para ocupar el lugar eliminado. Esta operación hace que el
tamaño de la estructura se reduzca en 1. remove(elemento): en este caso se envía
el objeto que se desea eliminar. Es importante aclarar, que si se crea un nuevo
elemento con los datos del objeto que se desea eliminar no indica que sea el
mismo elemento. Para que sean iguales deben ocupar la misma posición de
memoria, es decir, deben ser la mismas instancia.
contains(elemento): Devuelve true si el elemento exist, de lo contrario devuelve
false.
toArray().Copia los elementos que tiene el ArrayList a un arreglo de objetos.
Partiendo del diagrama de clases anterior se iniciará con la construcción de las
clases del paquete mundo.
Primero se mostrarán los atributos de la clase conjunto.
publicclass Conjunto
{
//----------------------------------------------------
------------// Atributos
//----------------------------------------------------
------------/**
* Son los elementos que forman parte del conjunto
*/
private ArrayList <String> misElementos;
}
La clase Conjunto tiene dos métodos constructores. El primero de ellos no tiene
parámetros. Su objetivo es reservarle memoria al ArrayList de elementos del
conjunto.
public Conjunto()
{
misElementos=new ArrayList<String>();
}
El segundo, recibe un ArrayList con los elementos del conjunto.
public Conjunto(ArrayList<String> misElementos) {
this.misElementos = misElementos;
}
Observe que hay dos constructores, el primero de ellos permite reservarle memoria
al Arraylist, surgiendo entonces un conjunto con cero elementos. En el segundo
constructorse reciben los elementos del conjunto por parámetro.
public Conjunto(ArrayList<String> misElementos)
Finalmente el método toString() devuelve un String con la representación del
conjunto.
public String toString()
{
return misElementos.toString(); }
Por otra parte, en la clase GrupoConjuntos se encuentran, entre otros, los
siguientes atributos.
publicclass GrupoConjunto
{
//----------------------------------------------------
------------//Atributos
//----------------------------------------------------
------------/**
* Es el arreglo de conjuntos
*/
private ArrayList <Conjunto> misConjuntos ;
}
El método inicializar(ArrayList <ArrayList<String>> arreglo ) recibe por parámetro un
ArrayList de un ArrayList de String, esto quiere decir, que se tendrá un ArrayList
general llamado arreglo, que en la posición cero almacenará otro ArrayList de
String (correspondiente al primer conjunto que ingresó el usuario). En la posiión 1,
tendrá otro ArrayList con todos los elementos del segundo conjunto y así
sucesivamente.
El método publicvoid inicializar(ArrayList <ArrayList<String>> arreglo) se encarga
de convertir los elementos que hay en la posición cero del arrayList que recibe en
un nuevo conjunto, los elementos que hay en la posición 1 en un nuevo conjunto y
así continúa hasta que recorra todo el ArrayList. Este objetivo se logra a través de
las siguientes instrucciones:
for(int i=0; i<arreglo.size(); i++)
{
misConjuntos add(new Conjunto(arreglo.get(i)));
}
publicvoid inicializar(ArrayList <ArrayList<String>>
arreglo ) {
misConjuntos=new ArrayList<Conjunto>(); for(int i=0;
i<arreglo.size(); i++)
{
misConjuntos.add(new Conjunto(arreglo.get(i)));
} }
El método public Conjunto ordenarAlfabeticamente(Conjunto miConjunto)aplica el
técnica de ordenamiento de Burbuja para ordenar ascendentemente los elementos
del conjunto.
public Conjunto ordenarAlfabeticamente(Conjunto
miConjunto) {//Se aplica burbuja para ordenar
ArrayList<String>
auxiliar=miConjunto.getMisElementos(); for(int i=0;
i<auxiliar.size();i++)
{
for(int j=0; j<auxiliar.size()-1;j++)
{ if(auxiliar.get(j).compareTo(auxiliar.get(j+1))>0) {
String aux=auxiliar.get(j);
auxiliar.set(j,auxiliar.get(j+1)); auxiliar.set(j+1,
aux);
}
}
}
returnnew Conjunto(auxiliar); }
Para entender como funciona este algoritmo imagine que se tiene un arreglo cuyos
elementos son: 66 39 4 35 y 2 y que se ordenará siguiendo la estrategia mostrada
en la siguiente tabla.
66 39 4 35 2
39 66 4 35 2
39 4 66 35 2
39 4 35 66 2
39 4 35 2 66
4 39 35 2 66
4 35 39 2 66
4 35 2 39 66
4 35 2 39 66
4 2 35 39 66
4 2 35 39 66
4 2 35 39 66
2 4 35 39 66
2 4 35 39 66
2 4 35 39 66
2 4 35 39 66 Se puede observar que lo que se ha hecho es desplazar los
elementos más pequeños hacia el inicio del arreglo (hacia el primer elemento) y
los elementos mayores se movieron hacia el fondo del arreglo. Generalizando, lo
que se hizo es tomar el elemento mayor, el cual se fue recorriendo de posición en
posición hasta ponerlo en su lugar. Aeste método de ordenamiento se le conoce
como Burbuja.
Es importante anotar, que existen otros métodos de ordenamiento, entre ellos se
destacan el método de inserción directa y el método de selección.
El método de Inserción directa se basa en tomar uno por uno los elementos de un
arreglo y recorrerlo hacia su posición con respecto a los anteriormente ordenados.
Así empieza con el segundo elemento y lo ordena con respecto al primero. Luego
sigue con el tercero y lo coloca en su posición ordenada con respecto a los dos
anteriores, así sucesivamente hasta recorrer todas las posiciones del arreglo.
Otro método muy conocido es el de Selección, el cual consiste en encontrar el
menor de todos los elementos del arreglo e intercambiarlo con el que está en la
primera posición. Luego el segundo más pequeño, y así sucesivamente hasta
ordenar todo el arreglo.
Por otra parte, el método public ConjuntohallarUnion(), crea un ArrayList de String
en el cual se incluyen todos los elementos de todos los conjuntos verificando que
no se presenten repeticiones.
public Conjunto hallarUnion()
{
ArrayList<String> resultado=new ArrayList<String>();
for (int i=0; i<misConjuntos.size(); i++)
{
for(int
j=0;j<misConjuntos.get(i).getMisElementos().size();j++
{
String
dato=misConjuntos.get(i).getMisElementos().get(j);
if(!resultado.contains(dato))
resultado.add(dato);
}
}
returnnew Conjunto(resultado);
}
Para el método hallarInterseccion() se require de 3 for. El primero de ellos recorre
cada uno de los elementos del conjunto cero. Através del segundo for se obtienen
todos los conjuntos (diferentes al conjunto cero) y con el tercer for, se recorren los
elementos de cada uno de esos conjuntos. La idea general consiste en que cada
elemento obtenido del conjunto cero debe compararse con cada uno de los
elementos que hay en cada conjunto. Si al final se determina que un elemento del
conjunto cero, está presente en todos los demás conjuntos, ese elemento se
selecciona y se agrega al resultado.
public Conjunto hallarInterseccion()
{
int k, j,l;
ArrayList <String> misElementos=new ArrayList<String>
();
String elemento="", elemento1="";
/*Se obtiene el conjunto 0 del conjunto 0 se obtiene
cada uno de sus elementos es decir, se obtiene el
elemento j*/
for(j=0;j<misConjuntos.get(0).getMisElementos().size()
{
elemento=misConjuntos.get(0).getMisElementos().get(j);
/*El elemento obtenido debe compararse con cada uno de
los elementos que hay en
cada conjunto. Por lo tanto se toma cada uno de los
conjuntos que son diferentes
al conjunto 0 y se saca cada uno de los elementos para
luego comparse con el
elemento del conjunto 0*/
int contador=0;
for(k=1; k<misConjuntos.size(); k++)
{
for(l=0;
l<misConjuntos.get(k).getMisElementos().size(); l++)
{
elemento1=misConjuntos.get(k).getMisElementos().get(l)
if(elemento.equals (elemento1))
{ contador++; }
}
}
//si hay 4 conjuntos entonces el elemento comparado
debe estar repetido 3 //veces
if(contador==misConjuntos.size()-1)
{ String
elem=misConjuntos.get(0).getMisElementos().get(j);
if(!misElementos.contains(elem))
misElementos.add(elem);
}
}
returnnew Conjunto(misElementos);
}
}
4 Caso de estudio N.2 Conjunto Cerrado (Código
Fuente:unidadIICaso02ConjuntoCerrado)
Se desea crear una aplicación para manejar la información de un conjunto cerrado.
El conjunto cerrado tiene 55 casas, de las cuales las primeras 35 deben pagar
142000 por concepto de administración (pues son casas de dos plantas), las
restantes deben pagar este mismo valor incrementado en un 10% ( son casas de
tres plantas). Cada casa tiene un listado de habitantes, un número y una cantidad
de pisos. Cuando una persona compra una casa, por cada habitante se registra el
nombre, la identificación, la edad y un tipo. En el caso de los niños menores de 13
años la administración solicita al propietario de la vivienda que informe si el menor
puede salir o no del conjunto.
La aplicación debe permitir adicionalmente mostrar el listado de propietarios de
viviendas y la cantidad de niños autorizados a salir del conjunto, también el total
recaudado en administración.
Nombre
Descripción
Entrada Salida
Registrar una persona en una determinada casa
Se debe registrar una persona, para ello se ingresan sus datos personales y se
indica si es o no el propietario. Si la persona es menor de 13 años el propietario
debe informar si el niño puede salir del conjunto sin la compañía de un adulto.
1)el número de la casa en la que habitará la persona
2)nombre3)identificacion,4)autorización a salir 5) indicar si es propietario5)edad
La persona ha sido registrada
Listar todos los propietarios del conjunto
Se debe recorrer el listado de casas y por cada una de ellas sacar el propietario.
Ninguna
La lista de propietarios
Calcular el total recaudado en administración
Para calcular el total recaudado en administración se debe tener en cuenta que las
primeras 35 deben pagar 142000 por concepto de administración, las restantes
deben pagar este mismo valor incrementado en un 10% . Si la casa no tiene
propietario, es decir, aún pertenece a la constructora no debe pagar administración.
Ninguna
El total recaudado por concepto de administración
4.2 Comprensión del mundo del problema
Las clases identificadas son: ConjuntoCerrado, Casa, Habitante
//----------------------------------------------------
------------//Constantes
//----------------------------------------------------
------------/**
* Es el valor de la cuota de administración
*/
privatefinalstaticdoubleVALOR=142000;
}
En el método constructor se le reserva memoria al ArrayList de Habitantes y se
indica la cantidad de pisos que tiene la propiedad.
public Casa(int numero) {
this.numero = numero;
misHabitantes=new ArrayList<Habitante>();
cantidadPisos=2;
if(numero<ConjuntoCerrado.TIPO1) {
cantidadPisos=3; }
}
El método agregar tiene varios parámetros String nombre, String identificacion,
boolean autorizacionSalir, boolean propietario,int edad. Através de ellos es posible
crear el nuevo habitante que luego será agregado al ArrayList de habitantes.
publicvoid agregarHabitante(String nombre, String
identificacion, boolean autorizacionSalir, boolean
propietario,int edad)
{
misHabitantes.add( new Habitante(nombre,
identificacion, autorizacionSalir, propietario,
edad));
}
El método calcularValorAPagarAdministracion verifica el número de la casa, si es
menor de 35, entonces informa que debe pagar 142000, de lo contrario le aumenta
un 10% a este valor. No se le cobra administración a viviendas que no tienen
propietario, pues siguen siendo propiedad de la constructora.
publicdouble calcularValorAPagarAdministracion() {
if(misHabitantes.size()>0)
{if(numero<ConjuntoCerrado.TIPO1)
{returnVALOR;}
else
{returnVALOR*0.1;}
}
else
return 0; }
Por otro lado, en la clase ConjuntoCerrado se desarrollan métodos como los
siguientes:
Método constructor, en el que se crean la totalidad de casas.
public ConjuntoCerrado()
{
misCasas=new ArrayList<Casa>(); for(int i=0; i<MAXIMO;
i++) {
misCasas.add( new Casa(i+1)); }
}
El método informarCantidadNinosAutorizados recorre el ArrayList de casas y por
cada casa el ArrayList de habitantes y verifica si el habitante es menor de 13 años
y si está autorizado a salir. Si esto es verdadero incrementa el contador.
publicint informarCantidadNinosAutorizados()
{
int contador=0;
for(int i=0; i<misCasas.size();i++)
{
for(int j=0;
j<misCasas.get(i).getMisHabitantes().size(); j++)
{
if(misCasas.get(i).getMisHabitantes().get(j).getEdad()
<13&&
misCasas.get(i).getMisHabitantes().get(j).isAutorizacio
contador++;
}
}
return contador;
}
El método calcularTotalAdministracion recorre el ArrayList de casas y acumula el
valor que se debe pagar por cada casa en la variable acum.
publicdouble calcularTotalAdministracion()
{double acum=0;
for(int i=0; i<misCasas.size();i++)
{
acum+=misCasas.get(i).calcularValorAPagarAdministracion
}
return acum;
}
5 Caso de estudio N.1 El Avión (Código Fuente: unidadIIHoja01Avion)
Se desea crear una aplicación para manejar la información de un avión. El usuario
de la aplicación deberá informar inicialmente cuantas filas y columnas están
presentes en el avión. Se aceptarán valores entre 6 y 11 para las columnas y entre
4 y 14 para las filas.
La aplicación debe permitir sentar a un pasajero indicando su información básica,
su ubicación y clase de preferencia. Las posibles ubicaciones son Centro y
Ventana y las posibles clases son Económica y Ejecutiva. La clase ejecutiva
corresponde a los puestos ubicados en la diagonal principal y secundaria en las
primeras 4 filas. En el avión siempre habrá una zona inactiva que corresponde a
los elementos que se encuentran entre la diagonal principal y secundaria en las
cuatro primeras filas.Todos los demás puestos corresponden a ubicación
económica.
Es muy importante que se conserve el registro de todos los pasajeros que se han
sentado en cada una de las sillas.
También se debe permitir eliminar un pasajero indicando su cédula y consultar la
información de un pasajero indicando su posición.
Salida
Nombre
Descripción
Entrada Salida
Ubicar un pasajero
El pasajero llega a la aeropuerto y da sus datos personales y preferencias en torno
a clase y ubicación
1)cedula, 2)nombre, 3)clase, 4)ubicación
El pasajero ha sido ubicado
Cancelar la reservación de un pasajero
Para cancelar la reservación de un pasajero se debe solicitar la cédula
La cédula
La reservación ha sido cancelada
Consultar la información de un pasajero
Para consultar la información de un pasajero se debe informar la posición en la
cual está ubicado
La posición
El pasajero que está ubicada en dicha posición
5.2 Comprensión del mundo del problema
Se pueden identificar diferentes entidades: Avión, Puesto y Persona
/**
* Es la cedula de la persona
*/
private String cedula;
}
En esta clase se requiere de un constructor y los correspondientes
métodos get y set.
En la clase Puesto, además de los métodos get y set para número, clase,
ubicación y estado se cuenta con los siguientes:
- El método Constructor permite inicializar los atributos número y estado y
reservarle memoria al ArrayList de personas.
public Puesto(int numero, int estado) { this.numero =
numero;
this.estado=estado;
misPersonas=new ArrayList<Persona>();
}
- El método agregarPersona tiene como parámetros el nombre y la cédula. Con
estos datos se crea la persona que se va a agregar al ArrayList. Luego de agregar
una persona la variable estado se pone en 1.
publicvoid agregarPersona(String nombre, String
cedula) { Persona miPersona = new
Persona(nombre,cedula); misPersonas.add(miPersona);
estado=1;
}
- Para eliminar una persona sólo se pone el estado en cero. No se elimina
físicamente puesto que se solicitó conservar el resgistro de todos los clientes que
se han ubicado en los puestos.
publicvoid eliminarUltimaPersona()
{
estado=0;
}
Finalmente, algunos de los métodos de la clase Avion son:
El método constructor del Avión. En éste se le reserva memoria al ArrayList y a
cada uno de los Puestos. Es importante ir colocando la clase y la ubicación a
cada puesto a mediad que se van creando.
Observe que la clase se le asignó a cada puesto a través de una enumeración. Tal
como se muestra a continuación:
/*Aqui se crean todas las sillas que están en
mantenimiento*/ for(int i=0; i<inicio.size(); i++)
{
for(int j=inicio.get(i)+1; j< finaliza.get(i); j++) {
misPuestos.get(j).setClase(Clase.MANTENIMIENTO.getNumC
}
}
public Avion(int filas,int columnas) {
misPuestos=new ArrayList<Puesto>(); for(int i=0; i<
columnas*filas; i++) {
Puesto miPuesto=new Puesto(i,0);
misPuestos.add(miPuesto);
}
ArrayList<Integer> inicio= new ArrayList<Integer>();
ArrayList<Integer> finaliza=new ArrayList<Integer>();
int izq=columnas+1;
int derecha=columnas-1;
/*Aqui se crean todos los puestos de clase ejecutiva y
se capturan todas las posiciones para poder crear las
sillas inactivas*/
for(int i=0; i<4;i++)
{
inicio.add(i*izq);
finaliza.add(derecha*(i+1));
misPuestos.get(i*izq).setClase(Clase.EJECUTIVA.getNumC
misPuestos.get(derecha*
(i+1)).setClase(Clase.EJECUTIVA.getNumClase()); }
/*Aqui se crean todas las sillas que están en
mantenimiento*/
for(int i=0; i<inicio.size(); i++)
{
for(int j=inicio.get(i)+1; j< finaliza.get(i); j++)
{
misPuestos.get(j).setClase(Clase.MANTENIMIENTO.getNumC
}
}
/*No es necesario ponerle clase a las que falta, pues
por defecto se inicializaron con tipo 0 que es
económica. Ahora se fijan las ventanas. No es
necesario fijar el centro pues por defecto se
inicializó con cero. */
for(int i=0; i<=filas*columnas-columnas; i+=columnas )
{
misPuestos.get(i).setUbicacion(Ubicacion.VENTANA.getNum
misPuestos.get(i+columnas-
1).setUbicacion(Ubicacion.VENTANA.getNumUbicacion());
}
}
El método ubicarPasajero se encarga de ubicar un pasajero en un puesto acorde a
las preferencias expresadas con respecto a la clase y la ubicación. Si el pasajero
ya existe, no puede ubicarse nuevamente en el avión.
publicint ubicarPasajero(String nombre, String cedula,
int numUbicacion, int numClase)
{
if(buscarPasajero(cedula)==-1)
{
for(int i=0; i< misPuestos.size(); i++)
{
if(misPuestos.get(i).getEstado()==0&&misPuestos.get(i)
on&&misPuestos.get(i).getClase()==numClase)
{
misPuestos.get(i).agregarPersona(nombre, cedula);
return i;
}
}
}
return -1;}
5.4 Enum como nuevo elementos de modelado
Un nuevo elemento de modelado que se incorpora en este caso de estudio es el
enum. Un enum se utiliza para limitar el contenido de una variable a una lista de
valores definidos con anterioridad. Un tipo enumerado es una instancia del tipo
enumerado del cual se declaró. No se puede considerar como un String o un
entero.
publicenum Clase {
//Clases de puestos
EJECUTIVA (1), ECONOMICA(0), MANTENIMIENTO(2);
privateint numClase;
private Clase(int numClase) { this.numClase =
numClase;
}
publicint getNumClase() { return numClase;
}
publicvoid setNumClase(int numClase) { this.numClase =
numClase;
}
}
Si en un momento dado se requiere imprimir la clase de cada uno de los puestos
que hay en el avión sería posible apoyarnos en esta misma enumeración,
mediante la instrucciónClase.values()[tipo],lo cual se puede interpretar como:
Si tipo toma el valor de cero, entonces Clase. values()[0] devolverá EJECUTIVA, si
toma el valor de 1, Tipo.values()[1] devolverá ECONOMICA, si toma el valor de 2,
Tipo.values()[2] devolverá MANTENIMIENTO.
ACTIVIDAD
Construya un método que genere un listado con la información de todos los
puestos que hay en el Cine. Es importante mostrar como mínimo el número de
puesto, el estado del puesto y la clase del puesto.
Para este caso de estudio también se creó una enumeración para trabajar la
Ubicación del puesto.
publicenum Ubicacion {
//Clases de puestos VENTANA (1), CENTRO(0);
privateint numUbicacion;
private Ubicacion(int numUbicacion) {
this.numUbicacion = numUbicacion;
}
publicint getNumUbicacion() { return numUbicacion;
}
publicvoid setNumUbicacion(int numUbicacion) {
this.numUbicacion = numUbicacion;
}
}
5.5 foreach en Java
En el método buscar pasajero se utilizó la estructura repetitiva for-each, la cual
permite iterar sobre colecciones de objetos.Toda Collection tiene un tamaño y
puede recorrerse para conocer cada uno de los elementos que almacena. En Java
hay clases que manejan colecciones y permiten realizar sus operaciones básicas,
a saber:
add(element): Agrega un elemento.
iterator(): Obtiene un iterador. Un iterador es un objeto a través del cual es posible
ir obteniendo uno a uno los objetos al ir llamando repetitivamente método next().
size(): Devuelve el tamaño de la colección
contains(element): Pregunta si el elemento se encuentra dentro de la colección.
Un ejemplo del uso de Iterator es el siguiente:
void recorrer(Collection<Puesto> misP) {
Iterator<Puesto> it = misP.iterator();
while(it.hasNext())
{
Puesto miP = it.next(); }
}
Luego de la versión 6 de Java se ofrece una manera muy sencilla de recorrer una
collección, que es sumamente útil en el caso de que no se requiera eliminar
elementos. Esta estructura es el foreach. Tiene la siguiente sintáxis:
for (TipoBase variable: ArrayDeTiposBase) {..}
La utilización de esta estructura se muestra a continuación:
publicint buscarPasajero(String cedula)
{
//Se recorren todos los puestos que hay en el
ArrayList
for(Puesto miPuesto: misPuestos)
{
//Por cada puesto se verifica que haya persona y que
la cedula de dicha persona //coincida con la cédula de
la persona buscada
if(miPuesto.getMisPersonas().size()>0&&miPuesto.getMis
MisPersonas().size()-1).getCedula().equals(cedula)&&mi
{
return miPuesto.getNumero();
}
}
return -1;
}
6.1 Requisitos funcionales
Para resolver este caso de estudio se identificaron los siguientes requisitos
funcionales:
Requisito funcional 1 Nombre
Descripción
Requisito funcional 2 Entrada
Salida
Nombre
Descripción Entrada
Requisito funcional 3
Requisito funcional 4 Salida
Nombre
Descripción Entrada
Salida
Nombre
Descripción
Entrada
Salida Registrar un nuevo cliente
Se debe registrar un nuevo cliente, para ellos se debe solicitar el código y el
nombre. No se podrán registrar clientes que ya existan en el sistema.
1)código, 2)nombre
Un nuevo cliente ha sido registrado
Agregar una nueva cuenta
Se debe permitir registrar una nueva cuenta
1)número de la cuenta, 2)el monto, 3)el tipo de cuenta (ahorro o corriente), 4)La
posición donde se encuentra ubicado el cliente al cual se le va a crear la cuenta
Se ha creado una nueva cuenta
Generar el listado de las cuentas ordenado por monto
Se debe generar el listado de cuentas ordenadas por mont Ninguna
El listado de las cuentas ordenadas por monto
Generar listado de cuentas por cliente
Se debe generar listado de cuentas por cliente. Se podrá discriminar también por el
tipo de cuenta 0 ó 1 o todas. 1) Posición del cliente dentro del ArrayList de
clientes, 2) El tipo de consulta deseada ( Ahorro, corriente, todas)
El listado de cuentas que tiene el cliente, de acuerdo al tipo seleccionado
6.2 Comprensión del mundo del problema
Se pueden identificar diferentes entidades, a saber: Banco, Cliente y Cuenta.
/**
* Es el nombre del cliente
*/
private String nombre;
}
En esta clase se construyó un método constructor con dos parámetros y los
métodos get para cada uno de los atributos.
En la clase Cuenta se encuentran los siguientes atributos:
publicclass Cuenta {
//----------------------------------------------------
------------// Atributos
//----------------------------------------------------
------------/**
* Es el numero de la cuenta
*/
private String numero;
/**
* Es el cliente dueño de la cuenta
*/
private Cliente miCliente;
/**
* Es el tipo de la cuenta( 0-> ahorro, 1->corriente)
*/
privateint tipo;
/**
* Es la cantidad de dinero que hay en la cuenta
*/
privatedouble cantidadDinero;
//----------------------------------------------------
------------//Constantes
//----------------------------------------------------
------------/**
* Es la constante para manejar la cuenta de tipo
ahorro */
publicstaticfinalintTIPO_AHORRO=0;
/**
* Es la constante para manejar la cuenta de tipo
corriente
*/
publicstaticfinalintTIPO_CORRIENTE=0;
}
Algunos de los métodos más importantes de esta clase son los mostrados a
continuación:
El método constructor que permite inicializar los atributos numero, tipo y
cantidadDinero.
public Cuenta(String numero, int tipo, double
cantidadDinero) { this.numero = numero;
this.tipo = tipo;
this.cantidadDinero = cantidadDinero;
}
El método agregarCliente permite inicializar el atributo miCliente.
publicvoid agregarCliente(Cliente miCliente)
{
this.miCliente=miCliente;
}
El método toString() devuelve un String con la representación en String de la
cuenta. public String toString()
{String cuenta="Corriente ";
if(tipo==0)
cuenta="Ahorro ";
return "Número "+numero+ " Tipo: "+cuenta+" Dinero
"+cantidadDinero; }
Finalmente, en la clase Banco se tienen entre otros los siguientes métodos.
El método agregarCuenta lo primero que hace es verificar que la cuenta que se va
a crear no exista. Si es así, entonces se crear una nueva cuenta y se le agrega el
cliente que le usuario indicó. Antes de poder agregar esta cuenta, se debe
comprobar a través de buscarCantidadCuentasTipo que el usuario no exceda el
tope de cuentas por tipo, que es de 3.
publicboolean agregarCuenta(String numero, int tipo,
double cantidadDinero, ArrayList <Integer>
posClientes)
{
if(buscarCuenta(numero)==-1)
{
Cuenta miC= new Cuenta(numero, tipo, cantidadDinero);
for(int i=0; i<posClientes.size(); i++)
{
Cliente cliente=misClientes.get(posClientes.get(i));
if(buscarCantidadCuentasTipo(tipo,
cliente.getIdentificacion())<3)
{miC.agregarCliente(cliente);
}
}
misCuentas.add(miC);
returntrue;
}
returnfalse;
}
El método buscarCantidadCuentasTipo recibe el codigo de la persona y el tipo de
cuenta que se pretende crear. La idea es recorrer el ArrayList de cuentas e ir
preguntado por cada cuenta si el propietario es el mismo cliente y si el tipo de la
cuenta coincide con el tipo de la cuenta que se desea crear, si es así se
contabiliza.
publicint buscarCantidadCuentasTipo(int tipoCuenta
,String codPersona) {
int contador=0;
for(int i=0; i<misCuentas.size(); i++)
{
if(misCuentas.get(i).getMiCliente().getNombre().equals
misCuentas.get(i).getTipo()==tipoCuenta)
{
contador++; }
}
return contador; }
El método buscarCuentasClienteTipo recorre el ArrayList comparando el tipo de la
cuenta con el tipo buscado y el codigo del propietario de la cuenta con el código
buscado, si coinciden se agrega a uno de los ArrayList creados. Hay dos
ArrayList: en cuentasClienteTipo se agregan las cuentas si la solicitud
corresponde a corriente o ahorro, en todasCuentasCliente se agregan todas las
cuentas, pues el usuario ha solicitado ver todas las cuentas, sin discriminar entre
corriente y ahorro.
public String[] buscarCuentasClienteTipo(int
tipoCuenta, int posPersona) {
String
codPersona=misClientes.get(posPersona).getIdentificacio
ArrayList <Cuenta> cuentasClienteTipo=new
ArrayList<Cuenta>(); ArrayList <Cuenta>
todasCuentasCliente=new ArrayList<Cuenta>();
for (int i=0; i<misCuentas.size(); i++)
{
if(misCuentas.get(i).getMiCliente().getIdentificacion(
{
todasCuentasCliente.add(misCuentas.get(i));
if(misCuentas.get(i).getTipo()==tipoCuenta)
{
cuentasClienteTipo.add(misCuentas.get(i)); }
}
}
if (tipoCuenta==2)
return pasarArrayListAArreglo(todasCuentasCliente);
else
return pasarArrayListAArreglo(cuentasClienteTipo); }
Finalmente el método ordenarCuentas genera el listado de cuentas ordenado por
monto, utilizando el método burbuja.
public String[] ordenarCuentas()
{
for(int i=0; i< misCuentas.size(); i++)
{
for(int j=0; j< misCuentas.size()-1; j++)
{
if(misCuentas.get(j).getCantidadDinero()
<misCuentas.get(j+1).getCantidadDinero())
{
Cuenta temp=misCuentas.get(j); misCuentas.set(j,
misCuentas.get(j+1)); misCuentas.set(j+1, temp);
}
}
}
return pasarArrayListAArreglo(misCuentas);
}}
ARRAY BIDIMENSIONAL
1 Objetivos
Al finalizar la unidad el estudiante estará en capacidad de:
Utilizar estructuras contenedoras de tamaño fijo en dos dimensiones para resolver
problemas en los cuales es necesario almacenar una secuencia de elementos
Utilizar ciclos para poder manipular las estructuras contenedoras fijas de dos
dimensiones
Conocer y aplicar los patrones de algoritmo para recorrido de matrices.
2 Motivación
Frecuentemente se presentan muchos casos en los cuales se requiere trabajar
con estructuras contenedoras de dos dimensiones. Por ejemplo, un cine en el cual
hay una serie de puestos distribuidos en filas y columnas. En este nivel se
explicará cómo se declaran y crean este tipo de estructuras contenedoras, a las
cuales se les conoce como matrices.
3 Caso de estudio N.1 El cine (Código Fuente: unidadIIICaso01Cine)
Se desea crear una Aplicación para un Cine en cual hay 180 puestos distribuidos
en 12 filas y 15 columnas. Cada puesto tiene un número (formado por una letra y
un número entre 0 y 14) y un estado. El puesto o no estar ocupado por una
persona. Una persona tiene una cédula. La numeración de los puestos inicia en
A0… A14, continúa en B0… B14…. y así sucesivamente hasta llegar a L0…. L14.
Se requiere que se pueda ubicar una persona en el cine informando para ello su
cédula, tipo de preferencia, cantidad de sillas que desea y si requiere o no que
éstas sean consecutivas. El usuario podrá indicar la fila de su preferencia para
realizar su reservación.
También se necesita eliminar una reservación indicando la posición del puesto,
calcular el total recaudado en categoría general y calcular el total recaudado en
categoría preferencial.
columna
La reservación ha sido eliminada
Calcular el total recaudado por tipo de preferencia
Se debe calcular el total recaudado por tipo de preferencia El tipo de preferencia
El total recaudado
3.2 Comprensión del mundo del problema
Se pueden identificar diferentes entidades, a saber:
3.3 Diseño y construcción de la solución del problema
Para resolver este caso de estudio se requiere la incorporación del concepto de
arreglos dimensionales o matrices. Los Array Bidimensionales también se
conocen como tablas o matrices.
Es de anotar, que Java no soporta los arreglos multidimensionales de forma
directa. No obstante, permite trabajar con un arreglo de arreglos.
La propiedad length permite obtener el tamaño del arreglo. Para obtener el número
de filas se utiliza matriz.length y para obtener el número de columnas se utiliza
matriz[0] length.
Toda matriz debe ser declarada y se le debe reservar memoria. La sintaxis
utilizada para la declaración es la siguiente:
<TipoDato> nombreMatriz[][];
ó
<TipoDato> [][] nombreMatriz;
Para reservarle memoria se usa el operador new. Ejemplo:
nombreMatriz=new <TipoDato>[cantidadDeFilas]
[cantidadDeColumnas];
La declaración y reservada de memoria también se puede hacer en una sola línea.
int matriz[][]=new int[4][5];
Puesto misPuestos[][]= new Puesto[12][15];
Como puede verse es posible crear arraysen dos dimensiones de objetos, pero
hay que tener precaución pues luego de reservarle memoria al arreglo será
necesario crear cada uno de los objetos que va a almacenar.
Luego de que se reserva memoria, Java inicializa los arreglos dependiendo del
tipo de dato, ejemplo si el arreglo es de enteros, se inicializa por defecto con
ceros, pero si es de objetos se inicializa con null.
También es posible inicializar los arreglos al momento de la declaración:
int edad[][]={{3,4,5},{5,6,7}};
Cada elemento dentro del array bidimensional tiene una posición dada, la cual
está formada por una fila y una columna. Esto quiere decir que para moverse
dentro de este tipo de estructuras se requiere de dos índices, normalmente i y j. El
primero de ellos se desplaza en las filas, y toma valores entre 0 y matriz length y
el segundo, se mueve en las columnas y toma valores entre 0 y matriz[0].length.
La siguiente tabla está formada por 4 filas y 4 columnas. Dentro de cada celda se
han colocado, en la parte superior los respectivos índices. El primero de ellos
corresponde a la fila (i) y el segundo a la columna(j). Ejemplo si se tiene la
posicion 0,3 quiere decir que se está ubicado en lafila 0 y en la columna 3.
Es importante tener claro que una cosa es la posición y otra lo que se encuentra
almacenado en dicha posición. Por ejemplo, en la posicion 0,3 se encuentra
almacenado un 1 En la posicion 1,3 se encuentra almacenado un 70, en la
posicion 32 se encuentra almacenado un 4.
Columna
Fila 00 01 02 03
0 5 6 1
10 11 12 13
8 1 7 70
20 21 22 23
10 30 0 80
30 31 32 33
2 7 4 8
Observe que:
la i toma valores entre 0 y matriz.length-1 la j toma valores entre 0 y
matriz[0] length-1
Una importante estrategia que permite el desarrollo de la lógica sobre las matrices
consiste en poner los índices sobre cada uno de los elementos que la matriz
puede contener, pues gracias a ello es posible identificar aspectos importantes
que permitan realizargeneralizaciones . Por ejemplo:
Se desea sumar todos los elementos de la diagonal: En la diagonal, la i y la j son
iguales: 00, 11, 22, 33…
Se desea sumar los los elementos de la primera y última columna: En este caso,
j==0 || j== matriz[0].length-1
Se desea obtener los elementos de la diagonal secundaria: Observe que las
posiciones correspondientes a esta diagonal son 03, 12, 21 y 30. En este caso la
sumatoria del valor en i con el valor de j siempre da 3. Es decir, (i+j)==
matriz[0] length-1
El caso de estudio del Cine requiere la creación de la clase Persona, que cuenta
con un solo atributo, además del correspondiente método constructor y get.
publicclass Persona {
//----------------------------------------------------
------------// Atributos
//----------------------------------------------------
------------/**
* Es la cedula de la persona
*/
private String cedula;
}
En la clase Puesto se tienen, además de los métodos set y get de los atributos
numero, tipo, estado, los siguientes métodos:
- El método constructor que permite inicializar los atributos de la clase.
public Puesto(String numero, int tipo, int estado) {
super();
this.numero = numero;
this.tipo = tipo;
this.estado = estado;
}
- En la clase Puesto se crearon dos métodos setMiPersona, apoyándose en la
sobrecarga de métodos. El primero de ellos, permite fijar la persona en null y el
estado en cero, es decir cumple la función de eliminar la persona. El segundo
permite inicializar la persona con la información que el usuario ingresa.
publicvoid setMiPersona() { this.miPersona = null;
estado=0;
}
publicvoid setMiPersona(String cedula) {
this.miPersona = new Persona(cedula); estado=1;
}
Por último, se presentan algunos de los métodos de la clase Cine.
En el constructor de Cine se le reserva memoria a la matriz y luego a cada uno de
los puestos. Amedida que se crea un puesto se le asigna el número, la categoría y
el estado. El número se calcula apoyado en la variable char letra.
public Cine()
{
misPuestos=new Puesto[12][15];
char letra='A';
for(int i=0; i<misPuestos.length; i++) {
for(int j=0; j<misPuestos[0].length; j++)
{
if(i<9)
misPuestos[i][j]=new
Puesto(letra+""+j,Puesto.GENERAL,0); else
misPuestos[i][j]=new
Puesto(letra+""+j,Puesto.PREFERENCIAL,0);
}
letra++;
}
}
El método liberar recibe la fila y la columna donde está ubicado el puesto que se
desea liberar. Si el puesto no está ocupado se genera una excepción.
publicboolean liberar(int i, int j) throws Exception {
if(misPuestos[i][j].getEstado()==1)
{
misPuestos[i][j].setMiPersona();
returntrue;
}
else
thrownew Exception("El puesto no tiene personas y por
ello no se puede liberar"); }
El método obtenerDineroPorTipo, tiene como parámetro el tipo deseado y se
encarga de calcular el total recaudado, para ello se apoya en el método
contarPorTipo.
publicdouble obtenerDineroPorTipo(int tipo) {
double res=0;
if(tipo==0)
res=contarPorTipo(tipo)*Puesto.PRECIO_GENERAL; else
res= contarPorTipo(tipo)*Puesto. PRECIO_PREFERENCIA;
return res;
}
publicint contarPorTipo(int tipo) {
int contador=0;
for(int i=0; i<misPuestos.length; i++) {
for(int j=0; j<misPuestos[0].length; j++) {
if(misPuestos[i]
[j].getMiPersona()!=null&&misPuestos[i][j].getTipo(
)==tipo)
{contador++;}
}}
return contador; }
3.4 Patrones para recorrido sobre matrices
Los patrones para recorrer estructuras contenedoras de dos dimensiones son los
siguientes:
a) Patrón de recorrido Total
Mediante este patrón se tiene acceso a cada una de las posiciones del arreglo
bidimensional. Se requieren dos for, el primero de ellos maneja la fila y el segundo
de ellos la columna.
Un ejemplo de este tipo de patrón es el siguiente:
publicint contarPorTipo(int tipo) {
int contador=0;
for(int i=0; i<misPuestos.length; i++) {
for(int j=0; j<misPuestos[0].length; j++) {
if(misPuestos[i]
[j].getMiPersona()!=null&&misPuestos[i]
[j].getTipo()==tipo) {contador++;}
}}
return contador; }
b) Patrón de Recorrido Parcial
Se recorre el arreglo bidimensional y por cada elemento se verifica si ya se
cumplió la condición de finalización del ciclo, es decir, si el problema ya fue
resulto. Por ejemplo;
public int buscarPersona(String codigo)
{
for(int i=0; i<misPuestos.length; i++)
{
for(int j=0; j<misPuestos[0].length; j++)
{
if(misPuestos[i]
[j].getMiPersona()!=null&&misPuestos[i]
[j].getMiPersona().getCedu la().equals(codigo))
{return i;}
}}
return -1; }
4 Caso de estudio N.2 El Bingo (Código Fuente: unidadIIICaso02Bingo)
Se requiere de una aplicación para jugar Bingo. La aplicación debe generar tantos
tableros aleatorios como clientes deseen jugar. Cada tablero está formado por 5
filas y 5 columnas. Los números correspondientes a la columna B pueden tomar
valores entre 0 y 9, los valores válidos para la columna I son entre 10 y 19, para la
N entre 20 y 29, para la G entre 30 y 39 y para la última columna entre 40 y 49.
Cada tablero debe ser único.
Descripción
Entrada Generar un tablero
Cada vez que llega un cliente a comprar un tablero debe informar sus datos
personales para que el sistema lo genere.
Se debe verificar que el tablero sea válido, es decir, que ese tablero no exista ya.
1) teléfono, 2)nombre, 3) cedula
Un nuevo tablero ha sido generado
Sacar una balota.
El sistema aleatoriamente deberá seleccionar un número entre 0 y 49.
Ninguna
Un número entre 0 y 49
Actualizar todos los tableros luego de que se selecciona una balota Para cada
tablero se debe verificar si la balota seleccionada por el sistema está incluida
dentro de dicho tablero. En tal caso, esto se debe registrar.
1)El número de la balota seleccionada
Requisito funcional 4
Requisito funcional 5 Salida
Nombre
Descripción Entrada
Salida
Nombre
Descripción
Entrada Salida
Los tableros han sido actualizados
Listar todos los tableros vendidos
Se debe permitir mostrar los listados vendidos
Ninguna
El listado de tableros vendidos
Verificar si hay ganador
Luego de que se seleccione una balota el sistema debe verificar si algún tablero
se ha llenado completamente. Puede ocurrir que se completen varios tableros
Ninguna
El listado de tableros ganadores
3.6 Comprensión del mundo del problema
Se pueden identificar diferentes entidades, a saber Bingo, Tablero, Posición y
Propietario.
3.7 Diseño y construcción de la solución del problema
Para resolver este caso de estudio se iniciará con la clase Posición. Una posición
está formada por un número, una letra y un estado (seleccionado o no
seleccionado).
publicclass Posicion {
//----------------------------------------------------
------------// Atributos
//----------------------------------------------------
------------/**
* Es el número de la posicion
*/
privateint numero;
/**
* Seleccionado es cero si el sistema no ha sacado este
número sino es 1. */
privateint seleccionado;
/**
* Es una letra de la palabra Bingo
*/
privatechar letra;
}
Adicionalmente a los métodos get y set para cada uno de los atributos se tienen el
siguiente método:
public Posicion(int numero, int seleccionado) {
this.numero = numero;
this.seleccionado = seleccionado;
}
En la clase Tablero, se tiene entre otros métodos los siguientes:
En el constructor de Tablero se le reserva memoria a cada una de las posiciones
del tablero, pero no se les asigna número.
public Tablero(int numero)
{
matriz=new Posicion[Bingo.CANTIDAD_FILAS]
[Bingo.CANTIDAD_FILAS]; for(int i=0;
i<Bingo.CANTIDAD_FILAS;i++)
{
for(int j=0; j<Bingo.CANTIDAD_FILAS;j++)
{
matriz[i][j]=new Posicion(0,0);
}
}
this.numero=numero; }
El número luego se modifica con base en el número seleccionado aleatoriamente
por el sistema para crear el tablero, para ello se utiliza el método modificarNumero.
Cuando se piensa modificar un número se debe verificar que en esa columna ya
no exista.
publicboolean modificarNumero(int colu, int fil, int
numero) {
for(int i=0; i<Bingo.CANTIDAD_FILAS; i++) {
if(matriz[i][colu].getNumero()==numero) {
returnfalse; }
} matriz[fil][colu].setNumero(numero); returntrue;
}
Luego de que el juego ha iniciado y el sistema selecciona la balota, se debe
verificar si el número de la balota está presente en el tablero. Si es así, se debe
actualizar el tablero, poniendo a la variable seleccionado de la posición donde se
encuentra en uno.
publicvoid actualizarTablero(int aleatorio) {
for(int i=0; i<matriz.length; i++)
{
for (int j=0; j<matriz.length; j++) {
if(matriz[i][j].getNumero()==aleatorio) {
matriz[i][j].setSeleccionado(1); }
}
}
}
Finalmente, algunos de los métodos de la clase Bingo se presentan a
continuación:
El métodocrearTablero generaun nuevo tablero con números aleatorios y por último
verifica que el creado no haya sido generado con anterioridad.
public Tablero crearTablero(String telefono, String
nombre, String cedula) {
boolean centinela=true;
while(centinela)
{
int inicio=0, finaliza=9, aleatorio;
boolean res=false;
Tablero miTablero=new Tablero(misTableros.size()+1);
for (int j=0; j<CANTIDAD_FILAS;j++)
{
inicio=j*10;
finaliza=inicio+9;
for (int i=0; i<CANTIDAD_FILAS; i++) { res=false;
while(res==false)
{
do
{
aleatorio= (int)(Math.random()*finaliza); }while(!
(aleatorio>=inicio&&aleatorio<=finaliza));
res=miTablero.modificarNumero(j,i, aleatorio); }
}
}
if(verificarTableroValido(miTablero)==true) {
miTablero.setMiPropietario(telefono, nombre, cedula);
misTableros.add(miTablero);
centinela=false;
return miTablero;
}
}
returnnull;
}
El método generarPosicion, es el encargado de seleccionar una nueva balota con
número entre 0 y 49. Las balotas que ya se han seleccionado se van almacenando
para evitar repeticiones.
public Posicion generarPosicion() {
if(hayGanador()==null)
{
char letra[]={'B','I','N','G','O'}; int rango=0,
aleatorio=0;
boolean centinela=false;
while(centinela==false)
{
aleatorio= (int)(Math.random()*49);
rango=0;
if (aleatorio>=10&&rango<=19)
rango=1;
if(aleatorio>=20&&rango<=29)
rango=2;
if(aleatorio>=30&&rango<=39)
rango=3;
if(aleatorio>=40&&rango<=49)
rango=4;
if(aleatorio!=0&&!posicionesGanadoras.contains(aleator
{
posicionesGanadoras.add(aleatorio);
actualizarTodosLosTableros(aleatorio);
centinela=true;
}
}
Posicion p=new Posicion(aleatorio,0);
p.setLetra(letra[rango]);
return p;
}
returnnull;
}
El método hayGanador() se encarga de verificar si alguien ya hizo bingo, es decir
ha cubierto completamente los 25 números de su tablero.
public ArrayList<Integer> hayGanador() {
ArrayList<Integer> ganadores=new ArrayList<Integer>();
for(int i=0; i<misTableros.size(); i++) {
if(misTableros.get(i).contarAciertos()==25)
{
ganadores.add(i+1);
}
}
if(ganadores.size()>0)
return ganadores;
else
returnnull;
}
El método actualizarTodosLosTableros se encarga de actualizar los tableros con
base en la balota seleccionada aleatoriamente por el sistema. La actualización
consiste en registrar, en el caso de tableros que tienen el número de la balota un
acierto.
publicint actualizarTodosLosTableros(int aleatorio) {
for(int i=0; i<misTableros.size(); i++) {
ACTIVIDAD
Complete la tabla siguiente con los requisitos funcionales que hacen falta
Requisito funcional 1 Nombre
Descripción Entrada
Requisito funcional 2
Requisito funcional 3
Requisito funcional 4
Requisito funcional 5 Salida
Nombre
Descripción
Entrada
Salida
Nombre
Descripción Entrada
Salida
Nombre
Descripción Entrada
Salida
Nombre
Descripción Entrada
Salida
Realizar una jugada
Uno de los jugadores selecciona una posición del tablero 1) valor en la fila,2) valor
en la columna, 3) nickName de quien realiza la jugada
Ninguna
Verificar si hay ganador del triqui
Luego de que se ha realizado una jugada se deberá verificar si se hizo triqui.
Ninguna
El nombre del jugador que hizo triqui, si lo hay.
4.2 Comprensión del mundo del problema
Se pueden identificar diferentes entidades, a saber: Triqui, Posicion y Jugador
* Es el valor en la fila
*/
privateint i;
/**
* Es el valor en la columna
*/
privateint j;
/**
* Es el jugador que dio clic en esa posicion
*/
private Jugador miJugador;
}
El constructor de la clase recibe respectivamente la columna y la fila que
conforman la posición.
public Posicion(int i, int j) { super();
this.i = i;
this.j = j;
verificarInvariante();
}
El método setMiJugador permite fijar el jugador en la posicion
publicvoid setMiJugador(Jugador miJugador) {
this.miJugador = miJugador;
}
Por otra parte, la clase Jugador tiene entre otros métodos los siguientes:
El constructor que permite inicializar el nombre y Nick del jugador
public Jugador(String nombre, String nick) { super();
this.nombre = nombre;
this.nick = nick;
}
El método equals, que verifica si dos objetos son iguales.
publicboolean equals(Object objeto) {
if ( this == objeto ) returntrue;
if ( objeto == null ) returnfalse;
if ( this.getClass() != objeto.getClass() )
returnfalse;
if ( this.nombre== this.getClass().cast(objeto).nombre
&&this.nick== this.getClass().cast(objeto).nick )
returntrue;
if ( this.nombre != null&&this.nick!=null)
if( this.nombre.equals(
this.getClass().cast(objeto).nombre
)&&this.nick.equals( this.getClass().cast(objeto).nick
))
returntrue;
if ( this.nombre != null&&this.nick==null)
if( this.nombre.equals(
this.getClass().cast(objeto).nombre )) returntrue;
if (this.nick==null)
if( this.nick.equals(
this.getClass().cast(objeto).nick)) returntrue;
returnfalse ; }
}
Finalmente, se tiene la clase Triqui. Algunos de sus métodos son:
El método constructor, en el que se le reserva memoria a la matriz y también a
cada uno de las posiciones dentro de la matriz.
public Triqui()
{
misPosiciones=new Posicion[3][3];
for (int i=0; i<misPosiciones.length; i++) {
for(int j=0; j<misPosiciones[0].length; j++) {
misPosiciones[i][j]=new Posicion();
misPosiciones[i][j].setI(i);
misPosiciones[i][j].setJ(j);
}
}
}
El método jugar recibe la fila y la columna de la celda que el usuario seleccionó y
también su nickName. El método lo que hace es marcar la posición como
seleccionada. Por último, identifica cual es el jugador que debe realizar la próxima
jugada.
public Jugador jugar(int i, int j, String nickName) {
centinela=false;
if(misPosiciones[i][j].getMiJugador()==null&&
turnoJugador.getNick().equals(nickName))
{
misPosiciones[i]
[j].setMiJugador(buscarJugador(nickName));
turnoJugador=buscarJugadorContrario(nickName);
centinela=true;
return verificarTriqui();
}
returnnull;
}
Finalmente, el método verificarTriqui() verifica si se realizó triqui en la diagonal
principal, en la diagonal secundaria, en la columnas o en las filas.
public Jugador verificarTriqui()
{
int i;
//Triqui en la diagonal principal
if( misPosiciones[0][ 0
].getMiJugador()!=null&&misPosiciones[2]
[2].getMiJugador()!=null&&misPosiciones[1 ]
[1].getMiJugador()!=null&&
misPosiciones[ 0 ][
0].getMiJugador().getNick().equals(
misPosiciones[2][2].getMiJugador().getNick()) &&
misPosiciones[0]
[0].getMiJugador().getNick().equals(misPosiciones[1]
[1].getMiJuga dor().getNick()))
{
return misPosiciones[ 0 ][ 0 ].getMiJugador();
}
//Triqui en la otra diagonal
if( misPosiciones[0][ 2
].getMiJugador()!=null&&misPosiciones[1]
[1].getMiJugador()!=null &&misPosiciones[ 2 ][ 0
].getMiJugador()!=null&&
misPosiciones[ 0 ][ 2
].getMiJugador().getNick().equals( misPosiciones[ 1 ][
1 ].getMiJugador().getNick()) && misPosiciones[ 0 ][ 2
].getMiJugador().getNick().equals( misPosiciones[ 2 ]
[0 ].getMiJugador().getNick()))
{
return misPosiciones[ 0 ][ 0 ].getMiJugador();
}
for( i = 0 ; i < 3 ; i++ ) {
if ( misPosiciones[i][ 0
].getMiJugador()!=null&&misPosiciones[i]
[1].getMiJugador()!=null
&&misPosiciones[ i ][ 2 ].getMiJugador()!=null&&
misPosiciones[ i ][ 0
].getMiJugador().getNick().equals(
misPosiciones[ i ][ 2 ].getMiJugador().getNick()) &&
misPosiciones[ i ][ 0
].getMiJugador().getNick().equals(
misPosiciones[ i ][ 1 ].getMiJugador().getNick()))
{
return misPosiciones[ i ][ 0 ].getMiJugador();
}
}
for( i = 0 ; i < 3 ; i++ )
{
if( misPosiciones[0][i
].getMiJugador()!=null&&misPosiciones[1]
[i].getMiJugador()!=null
&&misPosiciones[ 2 ][
i].getMiJugador()!=null&&misPosiciones[0]
[i].getMiJugador().getNick().equals(misP osiciones[ 1
][ i ].getMiJugador().getNick()) &&
misPosiciones[ 1 ][ i ].getMiJugador().getNick().
equals(misPosiciones[2][i].getMiJugador().getNick()))
{
return misPosiciones[ 0 ][ i ].getMiJugador();
}
}
returnnull;
}
5 Hoja de Trabajo N.2 Concéntrese (Código Fuente:
unidadIIIHoja02JuegoParejas)
Se desea crear una aplicación para el juego de parejas. El juego consiste en
seleccionar consecutivamenente dos casillas sobre un tablero, buscando parejas
de fotos.
en el tablero con su respectiva pareja de forma aleatoria.
Ninguna
Un nuevo tablero ha sido creado
Realizar jugada
Se debe seleccionar una casilla en el tablero. Cada vez que se hayan
seleccionado números pares de casillas se deberá verificar si el jugador encontró
una pareja o no.
1) fila 2)columna
Si se halló una pareja se devuelven las dos últimas jugadas realizadas, sino no
se devuelve null
Calcular el puntaje total
Luego de que el usuario encuentra una pareja, dependiendo de los iconos hallados
se acumula el puntaje obtenido
Ninguna
El puntaje obtenido
5.2 Comprensión del mundo del problema
Se pueden identificar diferentes entidades, a saber: Juego, Posicion e Icono.
mismo icono.
publicclass Icono {
//----------------------------------------------------
------------//Atributos
//----------------------------------------------------
------------/**
* Es el nombre del icono
*/
private String nombre;
/**
* Es el estado del icono
*/
privateboolean estado;
/**
* Es el puntaje que da este icono
*/
privateint puntaje;
}
En esta clase además del método constructor, que inicializa los atributos de la
clase se cuenta con los métodos get y set para los atributos.
public Icono(String nombre, boolean estado, int
puntaje) { this.nombre = nombre;
this.estado = estado;
this.puntaje=puntaje;
verificarInvariante();
}
La siguiente clase es la clase Posicion, cuyos atributos se muestran a
continuación.
publicclass Posicion {
//----------------------------------------------------
------------// Atributos
//----------------------------------------------------
------------/**
* Es el valor en la fila
*/
privateint i;
/**
* Es el valor en la columna
*/
privateint j;
/**
* Es el estado del icono
*/
privateint estado;
/**
* Es la ruta de la foto del icono */
private Icono foto;
}
Esta clase tiene,entre otros métodos, un constructor que permite inicializar los
atributos i, j y estado. Además tiene el método setFoto, el cual permite iniciar el
atributo foto.
public Posicion(int i, int j, int estado) { this.i =
i;
this.j = j;
this.estado = estado;
verificarInvariante();
}
publicvoid setFoto(Icono miIcono) { this.foto =
miIcono;
}
Finalmente, la clase Juego tiene un método constructor en el cual se le reserva
memoria al tablero apoyándonse en el método inicializarFotos y crearMatriz.
public Juego() {
misFotos=new ArrayList<Icono>();
misPosiciones=new Posicion[TAMANIO][TAMANIO];
dosUltimasJugadas=new ArrayList<Posicion>();
inicializarFotos();
crearMatriz();
verificarInvariante();
}
publicvoid inicializarFotos()
{
//Se agregan al ArrayList las diferentes fotos
misFotos.add(new Icono("fotos/baby1.jpg",false,2));
misFotos.add(new
Icono("fotos/cupeiro1.jpg",false,-5));
misFotos.add(new Icono("fotos/flor1.jpg",false,3));
misFotos.add(new Icono("fotos/hongo1.jpg",false,3));
misFotos.add(new
Icono("fotos/honguito1.jpg",false,4));
misFotos.add(new Icono("fotos/images1.jpg",false,-8));
misFotos.add(new Icono("fotos/mario1.jpg",false,5));
misFotos.add(new
Icono("fotos/orejitas1.jpg",false,3));
misFotos.add(new Icono("fotos/pez1.jpg",false,2));
misFotos.add(new
Icono("fotos/princess1.jpg",false,4));
misFotos.add(new
Icono("fotos/rosalina1.jpg",false,2));
misFotos.add(new Icono("fotos/luigi1.jpg",false,4)); }
En el método crearMatriz se crean cada una de las posiciones del tablero y a cada
celda se le asigna un icono. Siempre que se ponga un icono en una posicion se
debe poner en otra celda ese mismo icono, pues se requiere formar parejas. La
selección de los iconos debe ser aleatoria.La única posición a la que no se le
pone ícono es la posición [2][2].
publicvoid crearMatriz()
{
do{
int x=0, y=0, icono=0;
boolean centinela=false;
ArrayList<Integer> posicionesIconos=new
ArrayList<Integer>(); int contador=0;
//Se crean todas las posiciones
for(int i=0; i<misPosiciones.length; i++)
{
for(int j=0; j<misPosiciones[0].length; j++)
{
misPosiciones[i][j]=new Posicion(i,j,0) ;
}
}
//Aqui se asignan los iconos
}
permanente.
Construir un programa completo, siguiendo todas las etapas requeridas para
resolver un problema.
Construir pruebas unitarias que permitan probar el correcto funcionamiento del
software
2 Motivación
En la vida real se presentan muchos casos en los cuales se requiere manejar el
estado inicial de un problema y que esta información sea leida a través de un
archivo Para poder dar respuesta a esta necesidad en este nivel se tratará el tema
de archivos Properties y serialización.
3 Caso de estudio N.1La Empresa (Código Fuente:
unidadIVCaso01Empresa)
Se desea crear una aplicación para manejar la información de una empresa. En la
empresa hay empleados. Cada uno tiene un codigo, un nombre, una fecha de
nacimiento y un salario. La aplicación debe permitir:
- Agregar un nuevo empleado
- Leer la información de la empresa de un archivo de entrada.
- Generar un archivo con la información de la empresa
- Obtener la edad promedio de los empleados
- Mostrar la información de los empleados ordenada por salario utilizando el
método de inserción
- Mostrar la información de los empleados ordenada por edad utilizando el método
de selección.
- Buscar empleado que tenga el salario especificado por el usuario
Descripción Entrada
Salida
Requisito funcional 4
Requisito funcional 5 Nombre
Descripción Entrada
Salida
Nombre
Descripción
Requisito funcional 6 Entrada
Salida
Nombre
Descripción
Requisito funcional 7 Entrada
Salida
Nombre
Descripción
Entrada Salida
Agregar un nuevo empleado
Se requiere añadir un nuevo empleado
1)id, 2)nombre, 3)dia, 4) mes, 5)anio,
6)salario
Un nuevo empleado ha sido agregado a la empresa
Leer la información de la empresa de un archivo de entrada. La información de la
empresa se lee desde el archivo y constituye el estado inicial de la empresa
Nombre del archivo con la información de la empresa
Se inicializó el estado de la empresa, a partir de lo que se encontraba almacenado
en el archivo.
Generar un archivo con la información de la empresa
Se requiere generar un archivo con la información de la empresa Nombre del
archivo de la salida
Un nuevo archivo ha sido generado con la información de la empresa
Obtener la edad promedio de los empleados
Se requiere obtener la edad promedio de los empleados Ninguna
La edad promedio
Mostrar la información de los empleados ordenada por salario Se requiere generar
un listado con la información de los empleados ordenada por salario. Para resolver
este requisito se hará uso del método de inserción.
Ninguna
El listado ordenado por salario
Mostrar la información de los empleados ordenada por edad Se requiere generar un
listado con la información de los empleados ordenada por edad. Para resolver este
requisito se hará uso del método de selección.
Ninguna
El listado ordenado por edad
Buscar empleado que tenga el salario especificado por el usuario Se requiere
buscar el primer empleado que tenga el salario especificado por el usuario,
utilizando el método de búsqueda binaria.
El salario buscado
Un empleado que tenga el salario buscado
3.2 Comprensión del mundo del problema
Se pueden identificar diferentes entidades, a saber: Empresa, Empleado y Fecha.
3.3 Diseño y construcción de la solución del problema
Dado que la clase Empresa contiene la información de los empleados, esta clase
es la responsable de:
- Dar la información de los empleados
- Dar la edad promedio de los empleados
- Dar el listado de los empleados ordenada por salario y por edad
- Dar el empleado que tenga el salario especificado por el usuario
- Generar un archivo con la información de la empresa.
Esta clase también tiene las siguientes responsabilidades referentes a la
modificación de su estado:
- Registrar un nuevo empleado
- Leer desde un archivo la información de la empresa y guardarla en el ArrayList de
empleados.
Con base en las anteriores responsabilidades identificadas se definirán los
métodos de la clase Empresa.
3.4 Archivos
Un archivo es una colección de información almacenada como una unidad en
algún dispositivo de almacenamiento secundario. Entre las características más
generales de los archivos se tienen las siguientes:
* Nombre y extensión: Todo archivo debe tener nombre y una extensión. La
extensión indica su formato.
* Datos sobre el archivo: por cada archivo se almacena datos relacionados,tales
como: tamaño, fecha de creación, modificación y de último acceso,
* Ubicación, ruta o path: Todo archivo está ubicado dentro de una carpeta o
subcarpeta. El path de un archivo suele iniciar con la unidad lógica que lo
contiene, seguida de las sucesivascarpetas hasta llegar al directorio que lo
almacena, por ejemplo:
"C:eclipsepluginsedu buffalo.cse.green.relationship.association.source_3.5.0".
Desde java es posible cargar la información de los archivos almacenados en
disco. Los archivos que se manejarán en los siguientes casos de estudio tienen
un formato especial, que recibe el nombre de properties.
Un archivo con extensión properties es utilizado principalmente para almacenar
parámetros de configuración de una aplicación. Tambiénse puede utilizar para
almacenarcadenasparala internacionalizaciónylocalización.
Cadaparámetrosealmacenacomo unpareja de Strings, el primero almacenar
elnombredelparámetro(llamado clave), yel segundo, el valor.
Acontinuación se muestra el formato del archivo que se utilizará:
Nombre Valor de la propiedad
empleados properties
empresa.empleados=5
empresa.empleado0=1234,Juan Perez,23-02-1987,324345
empresa.empleado1=65643,Maria Perez,23-02-1987,4545
empresa.empleado2=443,Rocio Rosero,23-02-1987,3332
empresa.empleado3=12439,Liliana Rodriguez,23-02-
1987,435 empresa.empleado4=5643,Diana Lopez, 23-02-
1987,3232
Cada línea dentro del archivo corresponde a una propiedad.
Para poder aplicar el concepto de properties al caso de estudio de la empresa en
la ventanaPrinicipal se requiere agregar el siguiente método:
publicvoid cargarEmpleados( ) throws Exception {
JFileChooser fc = new JFileChooser( "./data" );
fc.setDialogTitle( "Abrir archivo de empleados" ); int
resultado = fc.showOpenDialog( this );
if( resultado == JFileChooser.APPROVE_OPTION ) {
inicializarEmpleados(datos);
}
El método cargarInfoEmpresa se encarga de cargar la información de los
empleados de la empresa en un objeto de tipo Properties, recibe como parámetro
el archivo que contiene la descripción de los empleados de la empresa y devuelve
un objeto de la clase Properties con la información del archivo.
private Properties cargarInfoEmpresa( File arch )
throws Exception {
Properties datos = new Properties( );
FileInputStream in = new FileInputStream( arch );
try
{ datos.load( in );
in.close( );
}
catch( Exception e )
{
thrownew Exception( "Formato inválido" );
}
return datos;
}
El método inicializarEmpleados tiene como función inicializar el arreglo de
empleados con la información que recibe en el parámetro de entrada. Tiene como
parámetro una un objeto de tipo Properties, al cual se le llamó datos. En datos está
la información cargada del archivo para inicializar la empresa.
privatevoid inicializarEmpleados( Properties datos )
throws Exception {
//A medida que se cargan los empleados se llenará un
archivo log //con el reporte de los problemas
ocurridos.
FileWriter salida=null;
BufferedWriter salida1=null;
salida=new FileWriter("./data/logCarga.txt");
salida1=new BufferedWriter(salida);
copiarLineaEnArchivoLog("En el proceso se generaron
los siguientes errores: ", salida1);
copiarLineaEnArchivoLog("n", salida1);
//Se inicia el proceso de carga del archivo
String strNumeroEmpleados = datos.getProperty(
"empresa.empleados" ); int maxEmpleados =
Integer.parseInt( strNumeroEmpleados );
int idConfirmacion=0;
// Lee el nombre de cada empleados de la respectiva
propiedad y crea el objeto que lo representa
for( int i = 0; i < maxEmpleados; i++ )
{
String id="",nombre="";
int dia=0, mes=0, anio=0;
double salario=0;
String infoEmpleado = datos.getProperty(
"empresa.empleado" + i ); StringTokenizer st2=new
StringTokenizer(infoEmpleado,"-,");
for (int j=0; st2.hasMoreTokens(); j++) {
String elemento=st2.nextToken().trim(); if(j==0)
id=(elemento);
else
if(j==1)
nombre=(elemento);
else
if(j==2)
dia=Integer. parseInt(elemento); else
if(j==3) mes=Integer.parseInt(elemento);
else
if(j==4)
anio=Integer.parseInt(elemento); else
salario=Double.parseDouble(elemento);
}
idConfirmacion=Integer.parseInt(id);
try
{
agregarEmpleado(id, nombre, dia, mes, anio, salario) ;
}
catch(Exception e)
{
copiarLineaEnArchivoLog("Id "+id+" Nombre "+nombre+"
Fecha "+dia+"/"+mes+"/"+anio+" Salario: "+salario,
salida1); }
}
salida1.close(); }
copiarLineaEnArchivoLog se encarga de registrar los errors ocurridos durante el
proceso de carga.
publicvoid copiarLineaEnArchivoLog(String linea,
BufferedWriter salida1)throws Exception
{
salida1.write("n"); salida1.write(linea);
salida1.write("n");
}
El método generarProperties recorre el ArrayList de empleados y va tomando cada
empleado para poder agregar una nueva línea al archivo.
publicvoid generarProperties(String nombreArch) throws
Exception {
FileWriter salida=null;
BufferedWriter salida2=null;
salida=new FileWriter(nombreArch);
salida2=new BufferedWriter(salida);
copiarLineaEnArchivoLog("empresa.empleados="+misEmplead
salida2); for(int i=0; i<misEmpleados.size(); i++)
{
String id=misEmpleados.get(i).getId();
String nombre=misEmpleados.get(i).getNombre();
String
fecha=misEmpleados.get(i).getMiFechaNacimiento().getDia
"+misEmpleados.get(i).getMiFechaNacimiento().getAnio()
double salario=misEmpleados.get(i).getSalario();
String total=id+","+nombre+","+fecha+","+salario;
System.out.println(total);
salida2.write("n");
salida2.write("empresa.empleado"+i+"="+total);
salida2.write("n");
}
salida2.close();
}
3.5 Métodos de ordenamiento y búsqueda
El método de Inserción directa se basa en tomar uno por uno los elementos de un
arreglo y recorrerlo hacia su posición con respecto a los anteriormente ordenados.
Así empieza con el segundo elemento y lo ordena con respecto al primero. Luego
sigue con el tercero y lo coloca en su posición ordenada con respecto a los dos
anteriores, así sucesivamente hasta recorrer todas las posiciones del arreglo.
public String[] ordenarPorInsercionSalario() {
String array[]= new String[misEmpleados.size()];
Empleado temp;
int i,j;
for (i=0; i<misEmpleados.size(); i++)
{
temp = misEmpleados.get(i); for (j=i; j>0;j--)
{
if ( misEmpleados.get(j-1).getSalario()<=
temp.getSalario()) break;
misEmpleados.set(j,misEmpleados.get(j-1)); }
misEmpleados.set(j,temp);
}
for(i=0; i<misEmpleados.size(); i++) {
array[i]=misEmpleados.get(i).getId()+"
"+misEmpleados.get(i).getNombre()+
" Edad: "+misEmpleados.get(i).calcularEdad()+ "
Salario:
"+misEmpleados.get(i).getSalario();
}
return array; }
ACTIVIDAD
Básese en este código para llenar la siguiente tabla y al final escriba un
comentario en torno a cómo funciona el algoritmo.
Otro método muy conocido es el de Selección, el cual consiste en encontrar el
menor de todos los elementos del arreglo e intercambiarlo con el que está en la
primera posición. Luego el segundo más pequeño, y así sucesivamente hasta
ordenar todo el arreglo
public String [] ordenarEdadPorSeleccion() {
String array[]= new String[misEmpleados.size()];
Empleado temp;
int i,j;
for (i=0; i<misEmpleados.size()-1; i++) {
for (j=i+1; j<misEmpleados.size();j++) {
if ( misEmpleados.get(i).calcularEdad()>
misEmpleados.get(j).calcularEdad()) {temp =
misEmpleados.get(i);
misEmpleados.set(i,misEmpleados.get(j));
misEmpleados.set(j,temp);
}
}
}
for(i=0; i<misEmpleados.size(); i++) {
array[i]=misEmpleados.get(i).getId()+"
"+misEmpleados.get(i).getNombre()+
" Edad: "+misEmpleados.get(i).calcularEdad()+ "
Salario:
"+misEmpleados.get(i).getSalario();
}
return array; }
ACTIVIDAD
Básese en ordenarEdadPorSeleccion() para llenar la siguiente tabla y al final
escriba un comentario en torno a cómo funciona el algoritmo.
Para buscar un elemento dentro de un arreglo se puede utilizar la técnica de
búsqueda binaria. Esta técnica requiere que los elementos del arreglo ya se
encuentran ordenados. Su funcionamiento es el siguiente:
Para iniciar lo que se hace es tomar un elemento central (el encuentra a la mitad
del arreglo), y se compara con el elemento buscado. En caso de que el elemento
buscado sea menor, se selecciona el intervalo que va desde el elemento central al
principio, de lo contrario, se elegirá el intervalo que va desde el elemento central
hasta el final del intervalo.
Este proceso se repetirá sucesivamente hasta que se llegué a un intervalo
indivisible, que indique si el elemento buscado está o no en el vector. El código es
el siguiente:
public Empleado busquedaBinaria(double salario) {
DecimalFormat formatoDecimal;
int inicio, fin, medio;
inicio=0;
fin=misEmpleados.size()-1;
ordenarPorInsercionSalario();
formatoDecimal = new DecimalFormat ( "0.0" ); String
dato= formatoDecimal.format ( salario);
dato=dato.replace(',','.');
salario=Double.parseDouble(dato);
while(inicio<=fin)
{
medio=(inicio+fin)/2;
if(salario==misEmpleados.get(medio).getSalario())
return (misEmpleados.get(medio));
else
if(salario>misEmpleados.get(medio).getSalario())
inicio=medio+1;
else
fin=medio-1;
}
returnnull; }
ACTIVIDAD
Aplique el método de busquedaBinaria para hallar a 5
.
3.5 Pruebas de software
Las pruebas o test son utilizadas durante el desarrollo de software para identificar
posibles errores y revelar el grado de cumplimiento en relación a las
especificaciones que inicialmente se plantearon para el sistema. Las pruebas
contribuyen a garantizar la calidad del software construido.
En Java se dispone del Framework JUnit para la realización y automatización de
pruebas. Para crear una clase de prueba ubíquese en el paquete test, de clic sobre
él y seleccione JUnit Test Case.
tearDownAfterClass: Únicamente puede haber un método con esta marca. Se
ejecuta una sóla vez cuando ha finalizado la ejecución de todas las pruebas.
tearDown:Seejecutadespuésde ejecutarse cada prueba. Este método se sustituye
por la anotación @After.
setUp: Se invoca antes de ejecutarcada prueba. Este método se sustituyó por la
anotación @Before
También puede usarse otras etiquetas:
Test: Se le coloca @Test a la prueba que se va a ejecutar
Ignore: El método que tenga esta marca no será ejecutado.
Retomando la creación de la clase de prueba para Empleado de clic en Next.
Luego seleccione los métodos donde se modifica el estado del objeto:
constructores, set o donde se realicen cálculos.
Para este caso se seleccionarán los siguientes métodos:
Empleado(String, String, int, int, int, double)
calcularEdad()
publicclass EmpleadoTest {
//----------------------------------------------------
------------// Atributos
//----------------------------------------------------
------------
/**
* Es la clase donde se realizarán las pruebas */
private Empleado miEmpleado;
//----------------------------------------------------
------------// Métodos
//----------------------------------------------------
------------
/**
* Construye un nuevo empleado */
@Before
publicvoid setupEscenario1( ) {
miEmpleado= new Empleado("123", "luis", 23, 02, 1980,
5000000); }
/**
* Prueba del constructor */
@Test
publicvoid testEmpleado() {
assertEquals( "El codigo es inválido.",
"123",miEmpleado.getId() ); assertEquals( "El nombre
es inválido.", "luis",miEmpleado.getNombre() );
assertEquals( "El dia es
inválido.",23,miEmpleado.getMiFechaNacimiento().getDia
);
assertEquals( "El mes es inválido.",
02,miEmpleado.getMiFechaNacimiento().getMes() );
assertEquals( "El anio es inválido.", 1980
,miEmpleado.getMiFechaNacimiento().getAnio() );
assertEquals( "El salario es inválido.",
5000000,miEmpleado.getSalario(),0 ); }
@Test
publicvoid testCalcularEdad() {
assertEquals( "El salario es inválido.",
31,miEmpleado.calcularEdad() ); }}
Para ejecutar las pruebas de clic en Run As JUnit Test
implementados
*/
publicclass FechaTest {
//----------------------------------------------------
------------// Atributos
//----------------------------------------------------
------------
/**
* Es la clase donde se realizarán las pruebas */
private Fecha miFecha;
//----------------------------------------------------
------------// Métodos
//----------------------------------------------------
------------
/**
* Construye una nueva fecha */
@Before
publicvoid setupEscenario1( ) {
miFecha= new Fecha(23,02,1980); }
/**
* Prueba del constructor
*/
@Test
publicvoid testFechaIntIntInt() {
assertEquals( "El dia es inválido.",
23,miFecha.getDia() );
assertEquals( "El mes es inválido.",
02,miFecha.getMes() ); assertEquals( "El anio es
inválido.", 1980 ,miFecha.getAnio() );
}
@Test
publicvoid testSetDia() {
miFecha.setDia(24);
assertEquals( "El dia es inválido.",
24,miFecha.getDia() ); }
@Test
publicvoid testSetMes() {
miFecha.setMes(03);
assertEquals( "El mes es inválido.",
03,miFecha.getMes() ); }
@Test
publicvoid testSetAnio() {
miFecha.setAnio(1981);
assertEquals( "El anio es inválido.", 1981
,miFecha.getAnio() ); }
@Test
publicvoid testCalcularDiferenciaConFechaActual() {
assertEquals( "La diferencia es incorrecta.", 373
,miFecha.calcularDiferenciaConFechaActual(new
Fecha(24,03,2010))); }}
4 Caso de estudio N.2 La Libreta Telefónica (Código
Fuente:unidadIVCaso02LibretaTelefonica)
Se requiere una aplicación para manejar una libreta telefónica en la cual sea
posible registrar la información de varios contactos. La aplicación debe permitir:
- Agregar un nuevo contacto
- Leer la información de la libreta de un archivo de entrada.
- Almacenar la información de forma persistente haciendo uso del concepto de
serialización.
- Eliminar un contacto indicando su posición
- Modificar un contacto
4.1 Requisitos funcionales
Para resolver este caso de estudio nos centraremos en los siguientes requisitos:
Requisito funcional 1
Requisito funcional 2 Nombre
Descripción
Entrada
Salida
Nombre
Descripción
Entrada Salida
Requisito no funcional
Tipo:
Persistencia Agregar un nuevo contacto
Se debe agregar un nuevo contacto, para ello se debe ingresar el nombre, la
dirección y el listado de teléfonos
1) nombre, 2) dirección 3) el listado de teléfonos
Se ha agregado un nuevo contacto
Leer la información de la libreta de un archivo de entrada. La información de la
libreta se lee desde el archivo y constituye el estado inicial de la libreta
Nombre del archivo con la información de la libreta
Se inicializó el estado de la libreta, a partir de lo que se encontraba almacenado
en el archivo.
La información del modelo del mundo debe persistente. Ello se logra haciendo uso
de archivos de .dat
4.2 Comprensión del mundo del problema
Se pueden identificar diferentes entidades, a saber: Libreta, Contacto,
ContactoRepetidoException y Entidad. Esta última será la encargada de
manejar todo lo referente a serialización.
publicvoid agregarContacto(String nombre, String
direccion,ArrayList<String> misTelefonos) throws
ContactoRepetidoException
{
nombre=nombre.toUpperCase();
if(buscarContacto(nombre)==-1)
misContactos.add(new Contacto(nombre,direccion,
misTelefonos)); else
thrownew ContactoRepetidoException("El contacto ya
existe"); }
La clase ContactoRepetidoException hereda de la clase Exception. Dentro de ella
se llama al constructor de la superclase para poder inicializar la variable message
con el mensaje que se le mostrará al usuario.
Exception es la clase base de la que derivan todas las excepciones. Se podría
concluir entonces que a través de ContactoRepetidoException es posible crear
instancias de objetos de Exception.
publicclass ContactoRepetidoException extends
Exception {
public ContactoRepetidoException (String message) {
super(message);
}
}
Para resolver el requerimiento de cargar la información de la libreta desde un
archivo será necesario apoyarse en los Properties. En la clase Libreta deben ir los
3 siguientes métodos:
publicvoid cargar( File arch ) throws Exception {
Properties datos = cargarInfoLibreta( arch );
inicializarContactos(datos);
}
El método cargarInfoLibreta se encarga de cargar la información de los empleados
de la empresa en un objeto de tipo Properties.
private Properties cargarInfoLibreta( File arch )
throws Exception {
Properties datos = new Properties( );
FileInputStream in = new FileInputStream( arch );
try
{ datos.load( in );
in.close( );
}
catch( Exception e )
{
thrownew Exception( "Formato inválido" );
}
return datos;
}
El método inicializarContactos es el encargado de inicializar el arreglo de
contactos con la información que recibe en el parámetro de entrada. Este método
tiene como parámetro a datos. datos contiene la información cargada del archivo
para inicializar la libreta.
privatevoid inicializarContactos( Properties datos )
throws Exception {
ArrayList <String> misTelefonos=new ArrayList<String>
();
//Se inicia el proceso de carga del archivo
String strNumeroContactos = datos.getProperty(
"libreta.contactos" ); int maxEmpleados =
Integer.parseInt( strNumeroContactos );
// Lee el nombre de cada persona de la respectiva
propiedad y crea el objeto que //lo representa
for ( int i = 0; i < maxEmpleados; i++ ) {
String direccion="",nombre="";
String infoEmpleado = datos.getProperty(
"libreta.contacto" + i ); StringTokenizer st2=new
StringTokenizer(infoEmpleado,"[,]");
for (int j=0; st2.hasMoreTokens(); j++) {
String elemento=st2.nextToken().trim(); if(j==0)
nombre=(elemento);
else
if(j==1)
direccion=(elemento);
else
{ int telefono=Integer.parseInt(elemento);
misTelefonos.add(elemento);
}
}
try {
agregarContacto(nombre, direccion, misTelefonos);
} catch(Exception e)
{
}
misTelefonos=new ArrayList<String>();
} }
Por otro lado, en la VentanaPrincipal debe ir el método cargarContactos. Este
método es el que carga los empleados a partir de un archivo seleccionado por el
usuario
/** Carga los empleados a partir de un archivo
seleccionado por el usuario * @throws Exception
*/
publicvoid cargarContactos( ) throws Exception
{
JFileChooser fc = new JFileChooser( "./data" );
fc.setDialogTitle( "Abrir archivo de contactos" );
int resultado = fc.showOpenDialog( this );
if( resultado == JFileChooser.APPROVE_OPTION )
{
File archivo = fc.getSelectedFile( );
miLibreta.cargar(archivo);
}
}
Para resolver el requisito de ordenar por nombre en la clase se utilizará el método
burbuja y la clase Collator, que ofrece más ventajas que el método compareTo.
public String[] listarContactosPorNombre()
{
String arreglo[]=new String[misContactos.size()];
/*Collator posee unas constantes para trabajar
diversos criterios relacionados con la comparación
Collator.PRIMARY considera distintas dos letras si la
letra base es distinta, por ejemplo si se tiene A, a y
á, son iguales puesto que tiene la misma base
Collator.SECUNDARY sólo considera iguales las
mayúsculas y las minúsculas. No son iguales si tienen
tilde.
Collator.TERCIARY Son completamente diferentes las
tres letras.
Collator.IDENTICALLY sólo son iguales si su codigo
interno es el mismo. Por ejemplo, existen
varias formas de codificar internamente una á con
tilde. No obstante cada codificación sería diferente
aunque se vea igual.
*/
Collator comparador = Collator.getInstance(new
Locale("es", "ES", "EURO")); // EURO es para estar al
dia
//Se configura para que ‘A’, ‘a’ y ‘á’ sean iguales
comparador.setStrength(Collator.PRIMARY);
for (int i = 0; i < misContactos.size(); i++) {
for (int j = 0; j < misContactos.size()-1; j++) {
// Compare elements of the array two at a time.
if
(comparador.compare(misContactos.get(j).getNombre(),
misContactos.get(j+1).getNombre() ) > 0 ) {
// Intercambia las palabras
Contacto tmp = misContactos.get(j);
misContactos.set(j,misContactos.get(j+1));
misContactos.set(j+1,tmp);;
}
}
}
for (int i = 0; i < misContactos.size(); i++) {
arreglo[i]=misContactos.get(i).toString(); }
return arreglo;
}
4.4 Serializacion
La serialización de objetos es una propiedad de Java a través de la cual es
posible leer y escribir objetos en un archivo. Para serializar es necesario que cada
una de las clases del paquete mundo implemente la interfaz serializable, la cual
obliga a que todos los campos de datos del objeto sean serializables. La interfaz
Serializable no tiene métodos, por ello su implementación es muy sencilla, basta
con colocar implements Serializable en cada clase. Ejemplo:
publicclass Contacto implements Serializable {
}
Para serializar es necesario utilizar las clases ObjectInputStream y
ObjectOutputStream para leer y escribir los objetos.
Si se desea especificarle a la máquina virtual de Java que un atributo no será
parte persistente de un objeto debe utilizarse el modificador transient.
Para automatizar el proceso de serialización se creó una clase “ genérica”
llamada Entidad, la cual puede ser utilizada en cualquier aplicación que usted
construya para que le agregue esta funcionalidad.
La genericidad o parametrización surge a partir de Java 5 y su objetivo es permitir
la creación de estructuras que almacenan elementos de un único tipo, siendo el
compilador quien se encarga de comprobar que no se presenten inconsistencias.
Java también permite la creación de clases
genéricas. Siguiendo la sintaxis: NombreClase<T1,…,Tn>. Ejemplo: Entidad
que almacena objetos de tipo T
publicclass Entidad <T> {
private T miObjeto; private String ruta;
public Entidad ( String ruta, T miObjeto) {
this.ruta=ruta;
this.miObjeto =miObjeto; // capacidad 0, contenido
nada, incremento 0 }
Recibe un objeto de tipo T, para inicializar el atributo de la clase
public T load ( String nameFile ) throws Exception
{
FileInputStream fileIn; Devuelve un objeto de tipo T con la
ObjectInputStream in; información que se cargó del
archivoT readFile;
try
{
fileIn = new FileInputStream ( nameFile );
in = new ObjectInputStream ( fileIn );
readFile = ( T ) (in.readObject());
}
catch( Exception e )
{ thrownew Exception("ERROR, no se pudo leer del
archivo");} return readFile;}
publicvoid leerDatosArchivo ( ) throws Exception {
miObjeto = (T) load (ruta);}
}
La expresión de instanciación para este tipo de clases debe llevar el identificador
completo del tipo que será creado, al igual que el argumento para los constructores
de dicho tipo. Aesta clase se le reservará memoria en la VentanaPrincipal. A
continuación se describen los pasos realizados.
En la VentanaPrincipal debe agregar un atributo de tipo Entidad:
privatestatic Entidad <Libreta>miEntidad;
Esta línea quiere decir que se va a almacenar una libreta teléfonica, es decir, se
debe aclarar que es lo que se va a almacenar. Si la clase principal del mundo fue
por ejemplo Empresa, entonces la línea sería privatestatic Entidad
<Empresa>miEntidad;
En la VentanaPrincipal se requiere también agregar los siguientes métodos:
El método serializar tiene como parámetro la ruta donde está almacenado el
archivo. En caso de que el archivo no exista se crea uno nuevo, sino se carga la
información del archivo y se le asigna a la libreta.
publicstaticvoid serializar(String ruta) throws
Exception {
miEntidad = new Entidad <Libreta> (ruta,miLibreta );
File fOrig = new File(ruta );
if(!fOrig.exists ( ))
{
miEntidad.save(ruta);
}
else
{ miEntidad.leerDatosArchivo();
miLibreta=miEntidad.getMiObjeto(); }
jList1.setListData(miLibreta.listarContactosPorNombre(
}
El método guardar archivo almacena la información que hay en el mundo.
publicvoid guardarArchivo() throws Exception {
miEntidad.save(miEntidad.getRuta());}
5 Hoja de trabajo N.1 El Ahorcado (Código Fuente:
unidadIVHoja01Ahorcado)
Se requiere una aplicación para el juego del Ahorcado. El usuario podrá agregar
palabras al conjunto de palabras existentes. También deberá proporcionarse la
funcionalidad de cargar palabras de un archivo. De igual forma, la aplicación
deberá ofrecer persistencia mediante serialización.
Cuando el juego inicie el sistema seleccionará aleatoriamente una palabra del
banco de palabras existentes. El usuario ingresará una letra y el sistema verificará
si está contenida dentro de la palabra seleccionada. Si el usuario se equivoca 4
veces el juego se dará por perdido.
5.1 Requisitos funcionales
Para resolver este caso de estudio nos centraremos en los siguientes requisitos:
Requisito funcional 1
Requisito funcional 1
Requisito funcional 2 Nombre
Descripción Entrada
Salida
Nombre
Descripción Entrada
Salida
Nombre
Descripción
Entrada Salida
Requisito no funcional
Tipo:
Persistencia Agregar una palabra
Cargar palabras desde un archivo
jugar
El usuario ingresa una letra y se debe verificar si está o no contenida en la palabra
que el sistema seleccionó aleatoriamente Una letra
Si la letra está en la palabra se le informa al usuario las posiciones donde está
ubicada la letra dentro de la palabra y se verifica si ya se completó la palabra,
pues en este caso el juego terminaría. Si la letra no está entonces se contabiliza
un nuevo errores y se verifica si ya completó los 4 errores.
La información del modelo del mundo debe persistente. Ello se logra haciendo uso
de archivos de .dat
5.2 Comprensión del mundo del problema
Se pueden identificar diferentes entidades, a saber:
5.3 Diseño y construcción de la solución del problema
En la clase Ahorcado se debe crear un método que permita seleccionar
aleatoriamente una palabra.
publicvoid iniciarJuego()throws SinPalabrasException
{
if(misPalabras.size()!=0)
{palabraSeleccionada=misPalabras.get((int)
(Math.random()*(misPalabras.size()1)));
palabra=newchar[palabraSeleccionada.length()];
}
else
thrownew SinPalabrasException("No hay palabras
almacenadas"); }
El método agregarPalabra tiene como parámetro la palabra que el usuario desea
agregar al banco de palabras.
publicvoid agregarPalabra(String palabra) throws
PalabraRepetidaException {
if(!misPalabras.contains(palabra))
{
misPalabras.add(palabra);
}
else
thrownew PalabraRepetidaException("La palabra ya
existe"); }
El método jugar recibe una letra y mediante un for verifica si ésta se encuentra
contenida en la palabra seleccionada aleatoriamente por el sistema.
publicboolean jugar(char letra)
{
boolean centinela=false;
System.out.println("letra "+letra+ " Seleccionada
"+palabraSeleccionada); for(int i=0;
i<palabraSeleccionada.length(); i++)
{
if(letra==palabraSeleccionada.charAt(i))
{
palabra[i]=palabraSeleccionada.charAt(i);
centinela=true;
}
}
if(centinela==false)
{contadorErrores++;}
return centinela;
}
El método verificarGano recorre la palabra seleccionada y compara con cada uno
de los caracteres que hay en el arreglo de char llamado palabra.
publicboolean verificarGano() {
}
El método verificarGano compara el contador de errores con 4. Si son iguales el
usuario ha perdido.
publicboolean verificarPerdio()
{
}
Para cargar las palabras desde el archivo Properties se deben incluir en la clase
Ahorcado los siguientes métodos:
publicvoid cargar( File arch ) throws Exception {
Properties datos = cargarPalabras( arch );
inicializarPalabras(datos);
}
El método cargarPalabras se encarga de cargar cada una de las palabras del
ahorcado en un objeto de tipo Properties.
private Properties cargarPalabras( File arch ) throws
Exception {
Properties datos = new Properties( );
FileInputStream in = new FileInputStream( arch );
try
{ datos.load( in );
in.close( );
}
catch( Exception e )
{
thrownew Exception( "Formato inválido" );
}
return datos;
}
El método inicializarPalabras inicializa el ahorcado con la información que recibe
en el parámetro de entrada.
privatevoid inicializarPalabras( Properties datos )
throws Exception {
//Se inicia el proceso de carga del archivo
String strNumeroPalabras = datos.getProperty(
"ahorcado.palabras" ); int maxPalabras =
Integer.parseInt( strNumeroPalabras );
// Lee cada palabra de la respectiva propiedad y crea
el objeto que lo representa for( int i = 0; i <
maxPalabras; i++ )
{
//Complete
} }
Por otro lado, se cuenta con un archivo Properties en donde se encuentra la ruta
del archivo en donde se va a serializar. Esta ruta se cargará a través de los
siguientes dos métodos, incluidos también en la clase Ahorcado.
public String cargarRutaSerializacion( File arch )
throws Exception {
Properties datos = cargarPalabras( arch ); return
inicializarRutaSerializacion(datos); }
private String inicializarRutaSerializacion(
Properties datos ) throws Exception {
//Se inicia el proceso de carga del archivo
String ruta= datos.getProperty( "ahorcado.ruta" );
return ruta;
}
El archivo ahorcado properties tiene la siguiente forma:
ahorcado.ruta=./data/archivo.dat
En la VentanaPrincipal se debe declarar el siguiente atributo: privatestatic
Entidad <Ahorcado>miEntidad;
Y también hay que agregar el siguiente método
publicstaticvoid serializar(String ruta) throws
Exception {
miEntidad = new Entidad <Ahorcado> (ruta,miAhorcado );
File fOrig = new File(ruta );
if(!fOrig.exists ( ))
{
miEntidad.save(ruta);
}
else
{ miEntidad.leerDatosArchivo();
miAhorcado=miEntidad.getMiObjeto(); }
}
6 Caso de estudio N.2 La Tienda Paisa (Código Fuente:
unidadIVHoja01TiendaPaisa)
Se desea crear una aplicación para manejar la información de un minimercado. En
el minimercado hay artículos, cada uno de los cuales tiene codigo, nombre,
2)nombre, 3)cantidad de Existencias y 4)precio Un nuevo artículo ha sido
agregado
Generar venta o factura
Se debe permitir generar una nueva factura, para ello el cliente debe informar
cuales son los artículos que desea adquirir y la cantidad correspondiente por cada
uno de ellos. Se debe verificar que si exista la cantidad solicitada por el usuario.
1)listado de articulo con la cantidad solicitada por cada uno de ellos Una nueva
factura se ha generado
La información del modelo del mundo debe persistente. Ello se logra haciendo uso
de archivos de .dat
6.2 Comprensión del mundo del problema
Se pueden identificar diferentes entidades, a saber:
El método actualizarUltimoPedido permite actualizar la cantidad de existencias en
el ArrayList general de pedidos, es decir, cuando se adquiere un artículo en el
minimercado la cantidad de existencias de ese artículo debe disminuir.
public Pedido actualizarUltimoPedido(int cantidad)
throws
NoHayExistenciasDisponiblesException
{
misPedidosCompraActual.get(misPedidosCompraActual.size
1).setCantidadExistencias(cantidad);
int
pos=identificarYaExistePedido(misPedidosDisponibles,
misPedidosCompraActual.get(misPedidosCompraActual.size
if(pos!=-1)
{
if
(misPedidosDisponibles.get(pos).getCantidadExistencias
cantidad>=0&&misPedidosDisponibles.get(pos).getCantidad
{
misPedidosDisponibles.get(pos).setCantidadExistencias(m
os).getCantidadExistencias()-cantidad);
}
else
{
misPedidosCompraActual.remove(misPedidosCompraActual.s
thrownew NoHayExistenciasDisponiblesException("No hay
existencias disponibles de ese articulo");
}
}
return
misPedidosCompraActual.get(misPedidosCompraActual.size
}
El método calcularPrecioTotalVenta recorre el ArrayList de la venta y calcula el
total a pagar.
publicdouble calcularPrecioTotalVenta() {
double acum=0;
for (int i=0; i<misPedidosCompraActual.size(); i++)
{
acum+=
(misPedidosCompraActual.get(i).getCantidadExistencias(
ual.get(i).getPrecio());
}
return acum; }
Finalmente, de la clase Tienda se tienen entre otros los siguientes métodos:
El método agregarPedido agrega un nuevo pedido al ArrayList general de pedidos.
Si el pedido ya existe se genera una excepción.
publicvoid agregarPedido(String codigo, String nombre,
int cantidadExistencias, double precio)throws
YaEstaElPedidoException
{
if(buscarPedido(codigo)==-1)
{
Pedido miP=new
Pedido(codigo,nombre,cantidadExistencias,precio);
misPedidos.add(miP);
}
else
thrownew YaEstaElPedidoException("Este pedido ya
existe en el sistema"); }
El método crear Factura le reserva memoria a una nueva factura y la agrega al
ArrayList general de ventas.
publicvoid crearFactura() {
Venta miVenta=new Venta(misPedidos);
misVentas.add(miVenta);
}
El método agregarPedidoALaFactura agrega un nuevo pedido a la factura que se
encuentra ubicada en la última posición del ArrayList de ventas.
publicvoid agregarPedidoALaFactura(String codigo,
String nombre, int cantidad,double precio)throws
NoHayExistenciasDisponiblesException {
misVentas.get(misVentas.size()-1).agregarPedido(codigo
nombre, cantidad, precio);
}
BIBLIOGRAFIA
ARBOLEDACOBO, Liliana María.Programación en red con java. Cali, Universidad
ICESI, 2004
BISHOP, Judy. Java Fundamentos de programación. Addison-Wesley. Segunda
Edición. Madrid. 1999. ISBN: 84-7829-022-2.
BOOCH. Object Oriented Analysis & Design With Applications. Prentice Hall,
1998
BOOCH. UML El Lenguaje Unificado de Modelado. Addison Wesley
CEBALLOS S ERRA, Francisco Javier. Java 2: curso de programación.
Alfaomega, 2006. México
DEJALÓN G. Javier y RODRÍGUEZ J. Ignacio, Aitor, Imaz. Aprenda Java como si
estuviera en primero. Escuela Superior de Ingenieros Industriales. San Sebastian.
Enero 2000.
DEITEL, H y DEITEl, P. Como programar en Java, Prentice Hall. Primera edición.
México, 1994 ISBN: 970-17-0044-9.
ECKEL, Bruce. Piensa en Java. Prentice-Hall, Pearson Educación. Segunda
edicion. Madrid, 2003. ISBN: 84-205-3192-8.
ER KSSON, H. UML 2 Toolkit. Indianapolis: Wiley 2004
FOWLER, Martín. UML, gota a gota. Addison Wesley Longman de México,SAde
CV
México 1.999. ISBN: 968-44-364-1
Goodrich, Michael y Tamassia, Roberto. Estructuras de datos y algoritmos en
Java.
CECSA. Segunda edición. 2002
HURTADO G L, Sandra Victoria. Conceptos Avanzados de Programación con
JAVA. Universidad ICESI, 2002
LEE, Richard. Practical Object Oriented Development with UML and Java.
Prentice-hall, 2002.
LEMAY, Laura. Cadenhead Rogers. Aprendiendo java en 21 días. Prentice Hall.
ISBN: 970-17-0229-8. Mexico.1999.
882570-9.
RICHARDSON. Professional Java JDK 6. Wrox, 2007
0228-1.
VILLALOBOS, Jorge. Introduccion a las Estructuras de Datos. Prentice Hall, 2008
VILLALOBOS S., Jorge Ay CASALLAS, Rubby. Fundamentos de programación
Aprendizaje Activo Basado en casos. Prentice Hall. ISBN: 970-26-0846-5. 2006
ZHANG, Computer Graphics Using Java 2d & 3d,-Pearson, Enero de 2007.

Programación orientada a objetos sergio augusto cardona torres

  • 7.
    Programación Orientada aObjetos Este libro está inspirado en el proyecto CUPI2, realizado por la Universidad de los Andes, cuyo principal propósito es encontrar mejores formas de enseñar/aprender a resolver problemas haciendo uso de un lenguaje de programación Sonia Jaramillo Valbuena Adscrito al Programa de Ingeniería de Sistemas y Computación Facultad de Ingeniería Universidad del Quindío Sergio Augusto Cardona Torres Adscrito al Programa de Ingeniería de Sistemas y Computación Facultad de Ingeniería Universidad del Quindío Leonardo Alonso Hernández Rodríguez Adscrito al Programa de Ingeniería de Sistemas y Computación Facultad de Ingeniería Universidad del Quindío
  • 8.
    Programación Orientada aObjetos No está permitida la reproducción total o parcial de esta obra, ni su tratamiento o transmisión por cualquier método sin autorización escrita deleditor. Derechos reservados ISBN: 978-958-44-7914-3 200 ejemplares ©Derechos reservados Reproducido y editado por Ediciones Elizcom Primera edición, diciembre del 2010 200 ejemplares www.elizcom.com ventas@elizcom.com Fax: 57 +6 +7450655 Móvil: 57 +3113349748 Armenia, Quindío Colombia PROGRAMACIÓN ORIENTADA A OBJETOS CONTENIDO Pág. ESTRUCTURAS CONTENEDORAS DE TAMAÑO FIJO ..................................................................................... 9 1 Objetivos....................................................................................................................... 9 2 Motivación..................................................................................................................... 9 3 Caso de estudio N.1 La Empresa (Código Fuente: unidadICaso01Empresa) ............................................ 9
  • 9.
    3.1 Comprensión delos requisitos ............................................................................................................. 10 3 2 Comprensión del mundo del problema................................................................................................. 11 3 3 Arreglos.......................................................................................................................... 11 3.4 Recorrer los arreglos ........................................................................................................................... 13 3 5 Patrones para instrucciones repetitivas................................................................................................ 16 3.6 El manejo de la memoria en Java ........................................................................................................ 18 3.7 Excepciones ....................................................................................................................................... 18 3.8 Diseño por contrato ............................................................................................................................. 20 4 Caso de estudio N.2 Cine ElizMark (Código Fuente: unidadICaso02Cine) .............................................. 27 4.1 Comprensión de los requisitos ............................................................................................................. 28 4 2 Comprensión del mundo del problema................................................................................................. 28 4 3 Diseño y construcción de la solución del problema .............................................................................. 30 5 Hoja de trabajo 1 La Biblioteca (Código Fuente: unidadIHoja01Biblioteca).............................................. 36 5.1 Comprensión de los requisitos ............................................................................................................. 37
  • 10.
    5 2 Comprensióndel mundo del problema................................................................................................. 37 5 3 Diseño y construcción de la solución del problema .............................................................................. 39 6 Hoja de trabajo N.2 Universidad (Código Fuente: unidadIHoja02Universidad) ........................................ 45 6.1 Requisitos funcionales .................................................................................................................... 45 6 2 Comprensión del mundo del problema............................................................................................ 46 6 3 Diseño y construcción de la solución del problema ......................................................................... 48 ESTRUCTURAS CONTENEDORAS DE TAMAÑO VARIABLE.......................................................................... 53 1 Objetivos ....................................................................................................................................... 53 2 Motivación ....................................................................................................................................... 53 3 Caso de estudio N.1 Conjuntos (Código Fuente: unidadIICaso01Conjuntos)............................................... 53 3.1 Requisitos funcionales .................................................................................................................... 54 3 2 Comprensión del mundo del problema............................................................................................ 55 3 3 Diseño y construcción de la solución del problema ......................................................................... 57 4 Caso de estudio N.2 Conjunto Cerrado (Código Fuente:unidadIICaso02ConjuntoCerrado)..................... 62
  • 11.
    4.1 Requisitos funcionales ....................................................................................................................63 4 2 Comprensión del mundo del problema............................................................................................ 64 4 3 Diseño y construcción de la solución del problema ......................................................................... 65 5 Caso de estudio N.1 El Avión (Código Fuente: unidadIIHoja01Avion) ......................................................... 67 5.1 Requisitos funcionales .................................................................................................................... 68 5 2 Comprensión del mundo del problema............................................................................................ 68 5 3 Diseño y construcción de la solución del problema ......................................................................... 69 5.4 Enum como nuevo elementos de modelado.................................................................................... 72 5 5 foreach en Java .............................................................................................................................. 73 6 Caso de estudio N.1 El Banco (Código Fuente: unidadI Hoja02Banco) ................................................... 74 6.1 Requisitos funcionales .................................................................................................................... 75 6 2 Comprensión del mundo del problema............................................................................................ 76 6 3 Diseño y construcción de la solución del problema ......................................................................... 76 ARRAY B D MENSIONAL........................................................................................................... 81 1 Objetivos
  • 12.
    ....................................................................................................................................... 81 2 Motivación ....................................................................................................................................... 81 3 Casode estudio N.1 El cine (Código Fuente: unidadIIICaso01Cine) ........................................................... 81 3.1 Requisitos funcionales .................................................................................................................... 82 3 2 Comprensión del mundo del problema............................................................................................ 82 3 3 Diseño y construcción de la solución del problema ......................................................................... 84 3.4 Patrones para recorrido sobre matrices .......................................................................................... 87 4 Caso de estudio N.2 El Bingo (Código Fuente: unidadIIICaso02Bingo) ....................................................... 88 3 5 Requisitos funcionales .................................................................................................................... 89 3.6 Comprensión del mundo del problema............................................................................................ 90 3.7 Diseño y construcción de la solución del problema ......................................................................... 92 4 Hoja de Trabajo N.1 El Triqui (Código Fuente: unidadIIIHoja01Triqui)..................................................... 96 4.1 Requisitos funcionales .................................................................................................................... 97 4 2 Comprensión del mundo del problema............................................................................................ 97 4 3 Diseño y construcción de la solución del problema
  • 13.
    ......................................................................... 98 5 Hojade Trabajo N 2 Concéntrese (Código Fuente: unidadII Hoja02JuegoParejas) ............................... 102 5.1 Requisitos funcionales .................................................................................................................. 103 5 2 Comprensión del mundo del problema.......................................................................................... 104 5 3 Diseño y construcción de la solución del problema ....................................................................... 104 PERSISTENCIA ....................................................................................................................................... 109 1 Objetivos ....................................................................................................................................... 109 2 Motivación ....................................................................................................................................... 109 3 Caso de estudio N.1 La Empresa (Código Fuente: unidadIVCaso01Empresa) .......................................... 109 3.1 Requisitos funcionales .................................................................................................................. 110 3 2 Comprensión del mundo del problema.......................................................................................... 110 3 3 Diseño y construcción de la solución del problema ....................................................................... 112 3.4 Archivos ....................................................................................................................................... 112 3 5 Métodos de ordenamiento y búsqueda
  • 14.
    ......................................................................................... 116 3 5Pruebas de software..................................................................................................................... 122 4 Caso de estudio N.2 La Libreta Telefónica (Código Fuente: unidadIVCaso02LibretaTelefonica) ........... 129 4.1 Requisitos funcionales .................................................................................................................. 130 4 2 Comprensión del mundo del problema.......................................................................................... 131 4 3 Diseño y construcción de la solución del problema ....................................................................... 131 4.4 Serializacion ................................................................................................................................. 135 5 Hoja de trabajo N.1 El Ahorcado (Código Fuente: unidadIVHoja01Ahorcado) ....................................... 136 5.1 Requisitos funcionales .................................................................................................................. 137 5 2 Comprensión del mundo del problema.......................................................................................... 137 5 3 Diseño y construcción de la solución del problema ....................................................................... 138 6 Caso de estudio N.2 La Tienda Paisa (Código Fuente: unidadIVHoja01TiendaPaisa)........................... 141 6.1 Requisitos funcionales .................................................................................................................. 142 6 2 Comprensión del mundo del problema.......................................................................................... 143 6 3 Diseño y construcción de la solución del problema
  • 15.
    ....................................................................... 143 B BLIOGRAFIA............................................................................................................. 147 PREFACIO Elpresente libro está inspirado en el proyecto CUPI2 realizado por la Universidad de los Andes, cuyo principal propósito es encontrar mejores formas de enseñar/aprender a resolver problemas haciendo uso de un lenguaje de programación. Para el entendimiento de este libro es necesario contar conconocimientos básicos en:clases y objetos, expresiones, estructuras de decisión y ciclos. El libro se estructura en 4 capítulos 1) Estructuras contenedoras de tamaño fijo. El lector podrá utilizar estructuras repetitivas para resolver problemas que involucren el uso de estructuras contenedoras estáticas y conocerá los diferentes patrones para recorrer este tipo de estructuras. También se familiarizará con la metodología de Diseño por contrato y el manejo de excepciones. 2) Estructuras contenedoras de tamaño variable. El lector estará en capacidad de utilizar estructuras repetitivas para resolver problemas que involucren el uso de estructuras contenedoras. Además, conocerá el método de ordenamiento Burbuja y nuevos tipos de estructuras, tales como el foreach y enumeraciones. 3) Arreglos bidimensionales. El lector manejará el concepto de estructuras contenedoras en dos dimensiones y podrá aplicar los diferentes patrones de recorrido. 4) Serialización. El lector adquirirá reforzará su conocimiento respecto a estructuras contenedoras yserá capaz de lograr que la información sea persistente,
  • 16.
    para ello seincorporarán los temas de archivosProperties, serialización y Generics. De igual forma, hará uso de excepciones personalizadas que le permitirán garantizar que la información digitada es correcta.También, se introducirá el concepto de pruebas con el JUnit. Finalmente se reforzarán los conocimientos con respecto a métodos de ordenamiento y se incorporará el concepto de búsqueda binaria. El código fuente de cada uno de los ejemplos desarrollados en este libro se encuentra en el CD anexo. Es de anotar, que todos los proyectos explicados hacen uso de interfaz gráfica. Para finalizar este prefacio es importante agradecer a la Universidad de los Andespor su importante proyecto CUPI2, pues éste es fuente de inspiración para muchas universidades y un importante avance para la solución del típico problema de enseñar a programar. ESTRUCTURAS CONTENEDORAS DE TAMAÑO FIJO Objetivos Al finalizar la unidad el estudiante estará en capacidad de: Utilizar estructuras contenedoras de tamaño fijo para resolver problemas en los cuales es necesario almacenar una secuencia de elementos del mismo tipo Utilizar ciclos para poder manipular las estructuras contenedoras fijas Utilizar la metodología de Diseño por contrato logrando con ello que a medida que se programe se documente el código y se detecten errores. Utilizar la clase Exception para capturar y manipular errores que pueden surgir en tiempo de ejecución. Motivación En algunas ocasiones se requiere resolver problemas en los cuales es necesario almacenar una secuencia de elementos, por ejemplo: un listado de estudiantes, de productos o de empleados. Esta característica debe verse reflejada al momento de
  • 17.
    construir el diagramade clases. Además, al momento de plantear la soluciónese grupo de elementos se debe materializar, es aquí en donde el aplica el concepto de arreglos. En este capítulo además de los arreglos se estudiarán otras temáticas, tales como: ciclos, metodología de diseño por contrato y excepciones. Estás últimas permitirán capturar y tratar los errores inesperados que surgen durante la ejecución de un programa. Caso de estudio N.1 La Empresa (Código Fuente: unidadICaso01Empresa) Se desea crear una aplicación para manejar la información de una empresa, en la cual hay 6 empleados. Cada empleado tiene un nombre, un código, una edad y un salario. La aplicación debe permitir cambiar la información de cada empleado, incrementar en un 10% el salario de todos los empleados, informar la cantidad de empleados cuyo nombre inicia en la vocal especificada por el usuario, informar la cantidad de empleados con edad superior a 30 e imprimir el salario promedio.
  • 19.
    Descripción Requisito funcional 4 Requisitofuncional 5 Entrada Salida Nombre Descripción Entrada Salida Nombre Descripción Entrada Salida Modificar la información del empleado El usuario podrá modificar cualquiera de los 4 datos del empleado. 1)El número del empleado al que se le va a modificar la información 2) Los nuevos datos: nombre, código, edad o salario La información del empleado ha sido modificada incrementar en un 10% el salario Se requiere incrementar en un 10% el salario de todos los empleados Ninguna Se ha incrementado el salario a todos los empleados Informar la cantidad de empleados cuyo nombre inicia en la vocal especificada por el usuario El usuario selecciona una de las cinco vocales y la aplicación debe informar cuantos empleados tienen nombre que inicie en dicha vocal La vocal La cantidad de empleados con nombre que inicia en esa vocal Informar la cantidad de empleados con edad superior a 30 Se deben contar los empleados que tienen edad superior a 30 Ninguna La cantidad de empleados con edad superior a 30 Informar el salario promedio
  • 20.
    Se requiere calcularel salario promedio de la empresa Ninguna El salario promedio 3.2 Comprensión del mundo del problema El modelo conceptual se puede definir a través de dos clases: Empleado y Empresa, tal como se muestra a continuación:
  • 22.
    elementos que seconocerla cantidad de elementos que se van a almacenar. En Java todos los arreglos son objetos. Los arreglos pueden ser unidimensionales, bidimensionales o multidimensionales, pero esta unidad se concentra en los unidimensionales. Todo arreglo debe declararse y se le debe reservar memoria para poder ser utilizado. Un arreglo se declara de la siguiente forma: <tipo>[] <nombre>; También es válido: <tipo><nombre>[]; Un ejemplo concreto de cómo se declara un arreglo es: int[] edades; ó int edades[]; Es importante resaltar, que hasta ahora solo se ha declarado el arreglo, no ha sido creado. Para crear un arreglo se le debe reservar memoria, a través del operadornew: edades = new int[10]; También es posible iniciar un arreglo al momento de su declaración, ejemplo: int edades[]={4,56,34,13}; Luego de que se reserva memoria Java inicializa los arreglos dependiendo del tipo de dato, ejemplo si el arreglo es de enteros, se inicializa por defecto con ceros, pero si es de objetos se inicializa con null. Cuando se declara un arreglo se debe usar el operador de indexación “ []” . Este indica que se va a almacenar una lista de elementos del mismo tipo. Gracias a este operador es posible acceder a cada uno de los elementos almacenados en la estructura contenedora fija. Ello se logra escribiendo primero el nombre del array, seguido de los corchetes que tendrán en su interior una variable de tipo entero, denominada índice, que indicará la posición a la cual se desea acceder. Ejemplo, si se tiene el siguiente arreglo: Empleado misEmpleados[]; misEmpleados=new Empleado[MAXIMO_EMPLEADOS];
  • 23.
    y se deseatener acceso a la posición 2, una instrucción correcta sería: if(misEmpleados[2]!=null&& misEmpleados[2].getCodigo().equals(codigo)) {return true;} Lo anterior significa que si hay un empleado en la posición 2 y el código del empleado corresponde con el buscado se retorna true. Algunas características importantes de los arreglos son las siguientes: 1. Tienen una variable denominada length que permite conocer el tamaño del arreglo o array. 2. Para poder acceder a los elementos del arreglo se utilizan corchetes [] y un índice que varía entre 0 y la longitud del arreglo-1, es decir, arreglo length-1. 3. Se pueden crear arrays de objetos pero hay que tener precaución pues luego de reservarle memoria al arreglo será necesario crear cada uno de los objetos que van a almacenar. Retomando el desarrollo del caso de estudio será necesario entonces declarar un arreglo de Empleados, tal como se muestra a continuación: publicclass Empresa { //---------------------------------------------------- ------------// Atributos //---------------------------------------------------- ------------ private Empleado misEmpleados[]; //---------------------------------------------------- ------------// Constantes //---------------------------------------------------- ------------privatefinalstaticintMAXIMO_EMPLEADOS=6; //----------------------------------------------------
  • 24.
    ------------// Constructor //---------------------------------------------------- ------------ /** * Métodoconstructor de la clase * post: Se crea una empresa en la que pueden haber máximo 6 empleados */ public Empresa() { misEmpleados=new Empleado[MAXIMO_EMPLEADOS];} } 3.4 Recorrer los arreglos Para poder recorrer un arreglo es necesario hacer uso de una estructura repetitiva. Java posee tres estructuras repetitivas: el for, el while y el do-while. Toda estructura repetitiva posee tres partes básicas, a saber: Expresión condicional o Decisión Cuerpo del ciclo: en esta parte se ponen las instrucciones que se desea ejecutar repetitivamente un cierto número de veces. Salida del ciclo En general, los ciclos se controlan a través de un contador, una variable que aumenta o disminuye su valor en una cantidad fija cada vez que se efectúa la repetición. También, es común encontrar dentro de los ciclos variables acumuladoras, las cuales permiten almacenar una cantidad variable cada vez que se efectúa una repetición. Por ejemplo, cuando se requiere realizar una sumatoria o sacar un promedio. La primera estructura que se analizará será el while. Esta estructura tiene la siguiente forma:
  • 25.
    while ( condición) { acción 1 ........ acción n } En este tipo de estructura las acciones se repiten “ mientras” que se cumple una determinada condición, la cual se especifica al inicio dentro de paréntesis. Cuando se efectúa la última acción se debe volver a evaluar la condición que del "while" para verificar si nuevamente se ejecutan las instrucciones o si por el contrario se finaliza la ejecución del while. El do-while, es una estructura que permite que las acciones se ejecuten almenos una vez antes de que se verifique la condición de repetición. do { acción 1 ........ acción n } while( condición ); En el while en principio se ejecutan todas las acciones y luego se evalúa la condición, si ésta da como resultado true nuevamente se repiten las acciones, de lo contrario se finaliza el ciclo. La última estructura repetitiva, y la más usada para trabajar con arreglos, es el ciclo for,que funciona de la siguiente forma: for ( inicialización; condicion; iteración) { acción 1 ........
  • 26.
    acción n } En elfor lo primero que se ejecuta es la inicialización, la cual normalmente es una expresión de asignación. La inicialización solo se efectúa una vez. A continuación, se evalúa la condición y si da verdadero se ejecuta el cuerpo del ciclo. En caso de que de false, el ciclo finaliza. Luego se efectúa la iteración, que consiste en aumentar o disminuir la variable de control del ciclo. Ahora bien, luego de esta conceptualización se continuará con el desarrollo de este caso de estudio Para responder a los requisitos funcionales es necesario construir varios métodos, algunos de los cuales se explicarán a continuación: El métodoincrementarEn10() se encarga de aumentar el salario de todos los empleados en un 10% . Este método no requiere de parámetros. El método funciona de la siguiente forma: Se crea un ciclo for que inicia en 0 y va hasta la cantidad de empleados. Es importante preguntar en cada posición si se ha registrado un empleado, es decir, si no es null. En caso de que sea así, se llama al método setSalario para ese empleado y se le fija el nuevo salario. publicvoid incrementarEn10() { for(int i=0; i<MAXIMO_EMPLEADOS;i++) { if(misEmpleados[i]!=null) { misEmpleados[i].setSalario(misEmpleados[i].getSalario( } } }
  • 27.
    El método contarVocales el encargado de informar la cantidad de empleados cuyo nombre inicia en la vocal especificada por el usuario. Este método tiene un parámetro, la vocal. Para poder conocer la cantidad de empleados cuyo nombre inicia en dicha vocal se debe plantear una estructura repetitiva que permita recorrer todo el arreglo y verificar en caso de que exista un empleado si su nombre inicia en esa vocal. publicint contarVocal(char vocal) { int contador=0; String nombre=""; for (int i=0; i<MAXIMO_EMPLEADOS; i++) { if(misEmpleados[i]!=null) { nombre=misEmpleados[i].getNombre().toUpperCase(); if(nombre.charAt(0)==vocal) { contador++; } } } return contador; } Observe que a través de la instrucción: nombre=misEmpleados[i].getNombre().toUpperCase(); Se captura el nombre del empleado y se pasa a mayúscula. Es importante que tenga claro, que los códigos de las letras mayúsculas son diferentes a los de las minúsculas. En el método anterior se hizo uso del método charAt. Este permite obtener un caracter de un String indicando la posición deseada, ejemplo si se desea obtener
  • 28.
    la posición cerola instrucción válida es nombre.charAt(0), si se requiere la posición 1 la instrucción es nombre.charAt(1), si se necesita la posición i se escribe nombre.charAt(i). El método contarEmpleadosMayores30() permite obtener la cantidad de empleados con edad superior a 30. En éste se recorre todo el arreglo y a cada empleado existente se le pregunta la edad. En caso de que la edad sea superior a 30 se debe contabilizar. publicint contarEmpleadosMayores30() { int contador=0; for (int i=0; i<MAXIMO_EMPLEADOS; i++) { if(misEmpleados[i]!=null&&misEmpleados[i].getEdad()>30 { contador++; } } return contador; } 3.5 Patrones para instrucciones repetitivas Un patrón es una solución genérica para un problema. Son tres los patrones que se trabajarán referentes a estructuras repetitivas, ellos son1 : a) Patrón de recorrido Total Mediante este patrón se tiene acceso a cada una de las posiciones del arreglo, por ello es necesario que el índice inicie en cero y se incremente de uno en uno hasta llegar a la cantidad de elementos del arreglo-1. También, el índice podría iniciar en la cantidad de elementos del arreglo-1 e ir decrementando de uno en uno hasta llegar a cero. Un ejemplo de este tipo de patrón es el siguiente:
  • 29.
    publicdouble calcularPromedio() { doubleacumulador=0; int contador=0; for (int i=0; i<MAXIMO_EMPLEADOS;i++) { if(misEmpleados[i]!=null) { acumulador+=misEmpleados[i].getSalario(); contador++; } } b) Patrón de Recorrido Parcial Se recorre el arreglo y por cada elemento se verifica si ya se cumplió la condición de finalización del ciclo, es decir, si el problema ya fue resuelto. Por ejemplo, se necesita obtener el primer empleado con edad superior a 35 años, o buscar el empleado cuya cédula es 415. Luego de encontrar el dato requerido no tiene sentido seguirse moviendo en el arreglo. 1Estos patrones están descritos en el libro Fundamentos de Programación. Aprendizaje activo Basado en Casos de Jorge Villalobos y Rubby Casallas publicint buscarEmpleado(String codigo) { for(int i=0; i<MAXIMO_EMPLEADOS;i++) { if(misEmpleados[i]!=null&&misEmpleados[i].getCodigo().e { return i;} } return -1; }
  • 30.
    Este mismo métodose pudo haber planteadotambién de la siguiente forma: publicint buscarEmpleado(String codigo) { boolean centinela=false; int posicion=-1; for (int i=0; i<MAXIMO_EMPLEADOS&&centinela==false;i++) { if(misEmpleados[i]!=null&& misEmpleados[i].getCodigo().equals(codigo)) { posicion=i; centinela=true; } } return posicion; } En esta última forma se declara un booleano que controla la finalización del ciclo. c) Patrón de doble recorrido En este tipo de patrón por cada elemento del array se realiza un recorrido completo. public Empleado determinarMayorFrecuencia() { int edad, contador = 0, mayorFrecuencia = 0, guardaContador = 0; for ( int i = 0 ; i < misEmpleados.length ; i++ ) { //Aquí se obtiene cada uno de los elementos del array edad = misEmpleados [i].getEdad(); contador = 0;
  • 31.
    for ( intj = 0 ; j < misEmpleados.length; j++ ) { if( i != j ) { if( edad == misEmpleados[j].getEdad() ) { contador++; } } } //Aquí se compara el contador de ocurrencias del elemento actual con el contador //general if( contador > guardaContador ) { guardaContador = contador;mayorFrecuencia = i; } }//Cierra el for return misEmpleados[mayorFrecuencia]; } 3.6 El manejo de la memoria en Java La memoria está dividida en tres zonas, a saber: la Zona de Datos, el Stack o Memoria de pila y el Heap, o Memoria de montículo. En la primera de ellas, se almacenan las instrucciones del programa, las constantes, los métodosy las clases. En el Stack se guardan las referencias a objetos (es decir, instancias creadas con new) y las variables de tipo de dato primitivo, másconcretamente, parámetros y variables locales. En el Heap, la zona de memoria dinámica, se almacenan los objetos creados. La forma como el heap y el stack interaccionan puede verse en el siguiente gráfico: Empleado misEmpleados[]; finalstaticintMAXIMO_EMPLEADOS=3; misEmpleados=new Empleado[MAXIMO_EMPLEADOS]; misEmpleados[0]= new Empleado(2,3000);
  • 34.
    edad, salario); } catch (Exceptione1) { JOptionPane.showMessageDialog(null, e1.getMessage()); } } Lo anterior puede interpretarse como: Si se produce un error al llamarse el método agregarEmpleado se genera una excepción que es capturada, logrando con ello que la ejecución del programa salte al catch. Dentro del catch se solicita el mensaje del error que ha ocurrido a través de la variable e1, el cual se imprime haciendo uso del JOptionPane. Para forzar a que se ejecute algo después de generada una excepción se escribe finally. El formato general es: try {… } catch (Exception e) {… } finally {… } Si el objetivo es generar una excepción dentro de un método se utiliza throw. Dichas excepciones se definen creando una subclase de Exception. Cuando dentro de un método se lanza una excepción derivada de Exception es necesario añadir la palabra reservada throws en la cabecera del método seguida de la lista de excepciones que se pueden producir, ejemplo:
  • 35.
    publicboolean agregarEmpleado(int posicion,String codigo, String nombre, int horasTrabajadas,double valorHora)throws EmpleadoRepetidoException { if(buscarEmpleado(codigo)==-1) { Empleado miE=new Empleado(codigo,nombre,horasTrabajadas,valorHora); misEmpleados[posicion]=miE; verificarInvariante( ); returntrue; } else thrownew EmpleadoRepetidoException("El empleado ya existe"); } En el caso anterior se creó un nuevo tipo de excepción denominadoEmpleadoRepetidoException. Ello se logró definiendo una subclase del tipo Exception. publicclass EmpleadoRepetidoException extends Exception{ public EmpleadoRepetidoException(String mensaje) { super (mensaje); } } El proceso que se sigue para crear este tipo de clases consiste en crear una nueva clase que extienda de Exception. En su interior se pone solamente un método constructor, que recibe como único parámetro el mensaje de error que se desea mostrar. En este caso, la instrucción super hace referencia al constructor de la clase base, es decir, al constructor de Exception.
  • 36.
    Es muy comúnque en los programas se definan excepciones propias que hereden de la clase Exception, pues gracias a ello es posible representar situaciones particulares para cada problema. 3.8 Diseño por contrato El Diseño por contrato es una metodología que se popularizó por el lenguaje de programación Eiffel y sefundamenta en la idea de que cada elemento de diseño es un participante dentro de una relación análoga a un contrato de negocios. Es decir, las relaciones entre las clases y sus clientes pueden interpretarse como un acuerdo o contrato, en el que se expresan los deberes y derechos de cada uno de los participantes. Esto permite que si ocurre algún problemacon remitirse al contrato sea posibledeterminar quién era el responsable de ejecutar la tarea que falló. Para complementar lo anterior, es importante recordar que para asignar responsabilidades es posible apoyarse en la técnica del experto o en la técnica de descomposición por requerimientos. La primera de ellas se basa en la idea de que el dueño de la información es el responsable de ella y la segunda, en que para satisfacer un requisito funcional una forma apropiada es descomponerlo en subproblemas para poder solucionar al requisito completo. El Diseño por Contrato hace posible diseñar componentespartiendo del hecho que se efectuaránunas determinadas condiciones de entrada y que se garantizará el cumplimiento de ciertas condiciones de salida. De igual forma,considera que debe haber propiedades que no varíen sin importar el procesamiento que se realice dentro de un componente. Partiendo de lo anterior, se puede afirmar que un contrato incluye tres tipos de restricciones: invariante, precondición y postcondición. - Una invariante es una condición booleana cuyo resultado siempre debe ser true para todas las instancias de la clase. La invariante permite verificar la
  • 37.
    consistencia de losatributos de la clase. - Una precondición es un predicado que debe haberse efectuado antes de que se realice una determinada operación. - Una postcondición es un predicado que, luego de haber ejecutado una determinar operación, debe ser verdadero. El Diseño por Contrato ofrece entre otras ventajas las siguientes: Un efectivo sistema para detectar y disminuir errores en el código, debido a la clara definición de las especificaciones. Una forma sencilla de documentar el codigo fuente a medida que se programa. a. El contrato de un método El contrato de un método incluye la especificación de las precondiciones y las postcondiciones. Por ejemplo, si se considera el siguiente método: publicboolean agregarEmpleado(int posicion, String codigo, String nombre, int horasTrabajadas,double valorHora) Se puede decir que las condiciones previas, o precondiciones, que deben cumplirse para que este método se ejecute son: El array de empleados ya se declaró y se le reservó memoria El código no es null, ni vacío El nombre no es null, ni vacío La cantidad de horas trabajadas es un número positivo El valor de la hora es un número positivo No se sabe si hay un empleado con este código La precondición expresa las restricciones necesarias para que la operación funcione de forma adecuada. El resultado de la ejecución del método debe ser: Se agregó el empleado Se produjo un error y no se pudo agregar
  • 38.
    La precondición sonlas condiciones impuestas para que se dé el desarrollo del método, mientras que la postcondición son los compromisos aceptados. b.Documentación de los contratos Para documentar los contratos es necesario apoyarse en Javadoc. Javadoc es una herramienta que permite generar un conjunto de páginas web a partir de los archivos de código que contengan los delimitadores /**… */.Javadoc permiteque la arquitectura de la solución sea mucho más comprensible. Para lograr una adecuada documentación del contrato se debenagregar comentarios a cada uno de los métodos que componen el programa. Un comentario permite agregar información suficiente para que otras personas puedan entender lo que se ha hecho y el porqué de lo que se ha hecho. Documentar no sólo es un acto de buena programación, es además una necesidad para poder entender el programa a medida que crece y poder identificar posibles fuentes de error. Una correcta documentación facilita que un software pueda ser modificado a futuro, ya sea por su creador o por cualquier otro programador que lo reemplace. Cuando se documenta se debe explicar lo que no es evidente. Es decir, se debe explicar por qué se hacen las cosas, en lugar de repetir lo que se hace. Cuando se empiece la construcción del software es importante explicar: Función de cada clase o paquete La labor de cada método y cuál es su uso esperado Por qué se declaró una variable Cómo funciona el algoritmo que se está utilizando y que limitaciones tiene Posibles mejoras que podrían realizarse Es obligatorio poner documentación javadoc en los siguientes casos: Al inicio de cada clase Acada atributo Al inicio de cada método
  • 39.
    La escritura deun comentario Javadoc exigen seguir una sintaxis. Deben iniciar por "/**" y terminar por "*/": /** * Descripción clara, breve y contundente de lo que hace. * * @etiqueta texto para la etiqueta */ Una descripción de las posibles etiquetas a utilizar para documentar una clase se muestra a continuación: @author Nombre del autor @version Información sobre la versión y fecha @see Referencia con otras clases y métodos En la documentación de los constructores y métodos se deben utilizar al menos las etiquetas siguientes: @param @return @exception ó @throws La siguiente tabla ilustra las posibles etiquetas que pueden utilizarse para documentar un método: @param Nombre del parámetro @return Si el métodono es void @exception Nombre de la excepción ó @throws Descripción, uso y valores válidos Descripción de lo que se debe devolver
  • 40.
    Excepciones que puedensurgir durante la ejecución Acontinuación se muestra un ejemplo de uso de algunas etiquetas Javadoc para documentar el código: - Al inicio de la clase /** * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * $Id$ * Universidad del Quindío(Armenia- Colombia) * Programa de Ingeniería de Sistemas y Computación * Licenciado bajo el esquema Academic Free License * Fundamentos de Algoritmia * Ejercicio: unidadICaso01Empresa * @author Sonia Jaramillo Valbuena * @author Sergio Augusto Cardona * @author Leonardo Hernández * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ package uniquindio.fundamentos.unidadICaso01Empresa.mundo; /** * Clase que representa una Empresa */ publicclass Empresa { } - Por cada método /**
  • 41.
    * Permite agregarun empleado. * @param posicion La posicion del empleado que se desea agregar. posicion>=0&& * posicion<MAXIMO_EMPLEADOS * @param codigo El código del empleado. codigo!=null && !codigo.equals(" ") * @param nombre El nombre del empleado. nombre!=null && !nombre.equals(" ") * @param horasTrabajadas Es la cantidad de horas que trabaja el empleado. * horasTrabajadas>0 * @param valorHora Es el valor que se le paga al empleado por cada hora * trabajada. valorHora>0 * @throws Exception Si existe un empleado con el mismo codigo se lanza una * excepción indicando que no se pudo agregar */ publicboolean agregarEmpleado(int posicion, String codigo, String nombre, int horasTrabajadas,double valorHora)throws EmpleadoRepetidoException { if(buscarEmpleado(codigo)==-1) { Empleado miE=new Empleado(codigo, nombre,horasTrabajadas,valorHora); misEmpleados[posicion]=miE; returntrue; } else thrownew EmpleadoRepetidoException("El empleado ya existe"); } Luego de finalizar la documentación se puede generar el archivo html con la documentación. Los pasos para ello son:
  • 44.
    Es de anotar,que los modificadores utilizados y el tipo devuelto no forman parte de la signatura del método.También, es importante recalcarque no puede haber dos métodos que con la misma signatura en una misma clase. Para el diseño de la signatura de un método se debe tener en cuenta las entradas y salidas del requisito funcional que el método pretende resolver, además, del tipo de dato de cada uno de los parámetros requeridos. Por ejemplo, si se tiene el método: publicboolean agregarEmpleado(int posicion, String codigo, String nombre, int horasTrabajadas,double valorHora)throws EmpleadoRepetidoException Para poder cumplir con la responsabilidad de agregar un empleado el método agregarEmpleado de la clase Empresa debe recibir la posición donde desea agregar el empleado y los datos referentes a éste. d. La invariante de la clase El Diseño por Contrato requiere también la incorporación del concepto de invariante. Una invariante es una condición booleana cuyo resultado siempre debe ser true para todas las instancias de la clase. La invariante permite verificar la consistencia de los atributos de la clase La invariante debe usarse al final del constructor y de los métodos que modifican el estado del objeto. La invariante hace uso de la instrucción assert. Un assert es una condición que se debe dar en todo momento en un programa para que no se produzcan errores Hay dos formas de escribir aseveraciones en Java: assert (Expresión con resultado booleano) : (Descripción del error) ; ó assert (Expresión con resultado booleano) ;
  • 45.
    Observe que enambas declaraciones se inicia con la palabra assert. Por cada clase debe construirse un método para verificar la invariante. Acontinuación se incluyen los métodos verificarInvariante para la cada una de las clases del caso de estudio de la Empresa. verificarInvariante para la clase Empleado // --------------------------------------------------- -------------// Invariante // --------------------------------------------------- -------------/** * Verifica que el invariante de la clase se cumpla. Si algo falla, lanza un error * <br> * <b>inv: </b><br> * misEmpleados !=null<br> * los códigos de los empleados son únicos <br> */ publicvoid verificarInvariante( ) { assert (misEmpleados!=null) : "El arreglo no puede ser null"; assert (verificarConsistencia()==true):"Hay códigos repetidos"; } verificarInvariante para la clase Empresa // --------------------------------------------------- -------------// Invariante // --------------------------------------------------- ------------- /** * Verifica que el invariante de la clase se cumpla. Si algo falla, lanza un * error <br> * <b>inv: </b><br>
  • 46.
    * misEmpleados !=null<br> *los códigos de los empleados son únicos <br> */ publicvoid verificarInvariante( ) { assert (misEmpleados!=null) : "El arreglo no puede ser null"; assert (verificarConsistencia()==true):"Hay c�digos repetidos"; } publicboolean verificarConsistencia() {boolean centinela=true; int contador=0; for(int i=0; i<MAXIMO_EMPLEADOS; i++) { contador=0; for(int j=0; j<MAXIMO_EMPLEADOS; j++) { if(misEmpleados[i]!=null&& misEmpleados[j]!=null&&misEmpleados[i].getCodigo().equa go())) {contador++;} } if(contador!=1) { returnfalse; } } return centinela; } Los assert en Eclipse no están habilitados por defecto. Para habilitarlos es necesario dar clic en: Windows -> Preferences -> Java -> Installed JREs. Luego hay que seleccionar el JDK y dar click el boton Edit y en el campo "Default
  • 47.
  • 49.
    permitir eliminar unareservación indicando la cédula del cliente que la realizó.
  • 51.
    1)cedula, 2)edad, 3)tipo,4) Fecha de la solicitud (día, mes, año), 5)Hora de llegada (discriminada por hora y minuto) Se asigna una silla al cliente, siempre y cuando exista disponibilidad de acuerdo a las preferencias del cliente y se le informa el valor a pagar Liberar una silla Se requiere cancelar una reservación ingresando para ello la cédula del cliente que la realizó cedula Si efectivamente el cliente tenía reservada una silla, ésta reservación se cancela. 4.2 Comprensión del mundo del problema El modelo conceptual se puede definir a través de 6 clases:Cine, Puesto, Reservación, Fecha y Persona. El diagrama de clases de este caso de estudio se muestra a continuación:
  • 54.
    privateint dia, mes,anio; privateint hora, minuto, segundo; } Adicionalmente, se requiere de los siguientes métodos: - Un método constructor que permite crear una fecha con los datos del dia de hoy. public Fecha() { // Usamos un calendario Gregoriano inicializado en el día de hoy GregorianCalendar gc = new GregorianCalendar( ); // Se obtienen los valores de dia, mes y año del calendario dia = gc.get( Calendar.DAY_OF_MONTH ); mes = gc.get( Calendar.MONTH ) + 1; anio = gc.get( Calendar.YEAR ); hora=gc.get( Calendar.HOUR ); minuto=gc.get( Calendar.MINUTE ); } - Un método constructor par crear una fecha con el día, mes y año que el usuario ingresa, además de la hora y de los minutos. public Fecha(int dia, int mes, int anio, int hora, int minuto) { this.dia = dia; this.mes = mes; this.anio = anio; this.hora = hora; this.minuto = minuto; verificarInvariante();
  • 55.
    } El método calcularDiferenciaEnMinutoses el encargado de calcular la diferencia en minutos entre dos fechas. Recibe como parámetro una fecha. public Fecha calcularDiferenciaEnMinutos(Fecha miFechaMayor) { GregorianCalendar menor=devolverGregorianCalendar(this); GregorianCalendar mayor=devolverGregorianCalendar(miFechaMayor); long diferencia = mayor.getTime().getTime()- menor.getTime().getTime(); double minutos = diferencia / (1000 * 60); int horas = (int) (minutos / 60); int minuto = (int) (minutos%60); returnnew Fecha(0,0,0,horas,minuto); } El método devolverGregorianCalendar recibe un objeto de tipo Fecha y lo convierte a Calendario Gregoriano public GregorianCalendar devolverGregorianCalendar(Fecha miFecha) { GregorianCalendar gcMenor = new GregorianCalendar( ); gcMenor.set(miFecha.getAnio(), miFecha.getMes()-1, miFecha.getDia(), miFecha.getHora(), miFecha.getMinuto()); return gcMenor; } Acontinuación se sobreescribe el método equals. Este método tiene como
  • 56.
    objetivo comparar dosobjetos de tipo Fecha, si son iguales devuelve true, de lo contrario false. publicboolean equals(Object o) { Fecha miFecha=(Fecha)(o); if(dia==miFecha.getDia()&&anio==miFecha.getAnio()&&mes= { returntrue;} else {returnfalse;} } Adicionalmente, se requiere construir la clase Persona ACTIVIDAD Complete la declaración de la clase Persona. Debe incluir los atributos, el constructor y los métodos get y set. publicclass Persona { //---------------------------------------------------- --------//Atributos //---------------------------------------------------- -------- //---------------------------------------------------- --------//Constructor //---------------------------------------------------- --------public Persona(String cedula, int edad) { } //---------------------------------------------------- --------//Métodos //---------------------------------------------------- --------
  • 57.
    public String getCedula(){ return cedula; } publicvoidsetCedula(String cedula) { } publicint getEdad() { } publicvoid setEdad(int edad) { } } Por otro lado, en la clase Puestose deben declarar los siguientes atributos: //---------------------------------------------------- ------------// Atributos //---------------------------------------------------- ------------/** * Es el número del puesto */ privateint numero; /** * Es el tipo del puesto, puede tomar los valores de GENERAL O PREFERENCIAL */ privateint tipo; /** * Es el estado del puesto. El estado del puesto puede ser ESTADO_LIBRE o * ESTADO_OCUPADO */ privateint estado; /** * Es el arreglo de reservaciones */
  • 58.
    private Reservacion misReservaciones[];/** * Es el contador de reservaciones */ privateint contadorReservaciones=0; //---------------------------------------------------- ------------//Constantes //---------------------------------------------------- ------------/** * Representa al tipo general */ publicstaticfinalintGENERAL=1; /** * Representa al tipo preferencial */ publicstaticfinalintPREFERENCIAL=0; /** * Representa al estado libre */ publicstaticfinalintESTADO_LIBRE=0; /** * Representa al estado ocupado */ publicstaticfinalintESTADO_OCUPADO=1; Se declara una estructura contenedora de 200 posiciones para poder manejar todo lo referente a las reservaciones que se hagan sobre un puesto específico. Se declaran 4 constantes, las dos primeras permiten representar los posibles tipos de puestos (GENERAL y PREFERENCIAL) y las dos últimas permiten representar los posibles valores del atributo estado (ESTADO_LIBRE y ESTADO_OCUPADO) Algunos de los métodos más relevantes de la clase Puesto son:
  • 59.
    - El constructorde la clase Puesto permite reservarle memoria al array de Reservaciones. public Puesto() { misReservaciones=new Reservacion[200]; } - El método agregarReservacion tiene varios parámetros: String cedula, int edad,int dia, int mes, int anio, int hora, int minuto yint tipo. Este método es el encargado de crear una nueva reservación, siempre y cuando no se exceda el máximo de reservaciones por puesto, es decir, 200. Cada vez que se genera una reservación el estado del puesto se pone en ocupado. public boolean agregarReservacion(String cedula,int edad,int dia, int mes, int anio, int hora, int minuto, int tipo) { Reservacion nueva=new Reservacion(new Persona(cedula, edad),new Fecha(dia,mes,anio,hora,minuto),tipo); if(contadorReservaciones<200) { misReservaciones[contadorReservaciones]=nueva; contadorReservaciones++; estado=ESTADO_OCUPADO; return true; } return false; } Por último, se tiene la clase Cine, en la cual es necesario declarar un arreglo de Puestos. Algunos de los métodos de esta clase son:
  • 60.
    - El métodoconstructor de la clase Cine. Aquí se le reserva memoria al arreglo de puestos y también a cada puesto. public Cine () { //Se le reserva memoria al arreglo misPuestos=new Puesto[MAXIMO]; //Se le reserva memoria a cada uno de los puestos que hay en el arreglo for(int i=0; i<MAXIMO; i++) { misPuestos[i]= new Puesto(); misPuestos[i].setNumero(i+i); misPuestos[i].setEstado(Puesto.ESTADO_LIBRE); if (i>14) misPuestos[i].setTipo(Puesto.GENERAL); else misPuestos[i].setTipo(Puesto. PREFERENCIAL); } } - El método ubicarPersona tiene varios parámetros: String cedula, int edad, int tipo, int dia, int mes, int anio, int hora yint minuto. Este método recorre el arreglo de puesto, para ello se apoya en la preferencia que el cliente desea. Cuando encuentra un puesto libre acorde a la preferencia solicitada le agrega una reservación. publicint ubicarPersona(String cedula, int edad, int tipo, int dia, int mes, int anio, int hora, int minuto) { int inicio=0, finaliza=14;
  • 61.
    //Se verifica quela persona no esté ya sentada en el cine if(buscarPersona(cedula, new Fecha(dia, mes, anio,hora, minuto))==false) { if(tipo==Puesto.GENERAL) { inicio=14; finaliza=56; } for(int i=inicio; i< finaliza;i++) { if(misPuestos[i].getEstado()==Puesto.ESTADO_LIBRE) { misPuestos[i].agregarReservacion(cedula, edad, dia, mes, anio, hora, minuto,tipo); return i; } } } return -1; } El método buscarPersona recibe la cédula de la persona y la fecha en la cual se le realizó la reservación, en caso de que exista la reservación devuelve true. publicboolean buscarPersona(String cedula, Fecha miF) { Fecha actual=new Fecha(); for (int i=0; i<MAXIMO; i++) { if(misPuestos[i].getContadorReservaciones()>=1&& misPuestos[i].getMisReservaciones()
  • 62.
    [misPuestos[i].getContadorReservaciones()1].getMiPerson misPuestos[i].getEstado()==Puesto.ESTADO_OCUPADO&& misPuestos[i].getMisReservaciones() [misPuestos[i].getContadorReservaciones()1].getMiFechaE { returntrue; } } returnfalse; } El método liberarEspaciorecorre el arreglo de puestos y por cada uno de ellos verifica si está ocupado. En tal caso compara la cedula de la persona que está ocupando el puesto con la del cliente buscado, si son iguales pone el estado de la silla en libre. Finalmente devuelve la posición donde estaba ubicada la persona y el valor que debe pagar. public ResultadoLiberacion liberarEspacio(String cedula) { for(int i=0; i<MAXIMO; i++) { if(misPuestos[i].getContadorReservaciones()>=1&&misPue ()[misPuestos[i].getContadorReservaciones() 1].getMiPersona().getCedula().equals(cedula)&& misPuestos[i].getEstado()==Puesto.ESTADO_OCUPADO) { misPuestos[i].setEstado(Puesto.ESTADO_LIBRE); returnnew ResultadoLiberacion(misPuestos[i].getMisReservaciones( [misPuestos[i].getContador Reservaciones()-1].calcularValorAPagar(), i); }
  • 63.
    } returnnull; } } Hoja de trabajo1 La Biblioteca (Código Fuente: unidadIHoja01Biblioteca) Un cliente requiere una aplicación para manejar la información de una Biblioteca. La Biblioteca tiene un listado de autores, uno de libros, uno de clientes y otro de préstamos. Cada una de estas listas tiene una cantidad máxima de 100. La aplicación debe permitir: Agregar un nuevo cliente, para lo cual se solicita su nombre y código Agregar un nuevo autor, para lo cual se ingresa el código y nombre del autor Agregar un nuevo libro ingresando código, nombre, cantidad de existencias, género y listado de autores, los cuales deben previamente existir en el sistema. Realizar un nuevo préstamo. Informar cuál ha sido el libro más prestado Informar que libros ha escrito un determinado autor Listar los libros prestados por un determinado usuario Listar los autores de un libro
  • 65.
    Requisito funcional 4Salida Nombre Descripción Entrada Requisito funcional 5 Requisito funcional 6 Salida Nombre Descripción Entrada Salida Nombre Descripción Entrada Requisito funcional 7 Salida Nombre Descripción Entrada Requisito funcional 8 Salida Nombre Descripción Entrada Salida Agregar un nuevo cliente Se debe agregar un nuevo cliente proporcionando para ello su información básica. No se podrán agregar clientes que existan ya en el sistema. 1)nombre y 2)código Un nuevo cliente ha sido agregado. Agregar un nuevo autor Se debe agregar un nuevo autor proporcionando para ello su información básica. No se podrán agregar autores que existan ya en el sistema.
  • 66.
    1)nombre y 2)código Unnuevo autor ha sido agregado. Agregar un nuevo libro Se debe agregar un nuevo libro. No se podrán agregar libros que existan ya en el sistema. 1) codigo,2)nombre, 3)cantidad de existencias, 4)género y 5)listado de autores Un nuevo libro ha sido agregado Realizar un nuevo préstamo Se debe permitir agregar un nuevo préstamo. Es importante estar verificando que si haya libros disponibles para prestar y que ha ese cliente no se le hay prestado ese libro ya. 1) La posición en la cual está ubicado el libro dentro del arreglo de libros, 2) La posición donde está ubicado el cliente que desea hacer el préstamo dentro del arreglo de clientes Un nuevo préstamo ha sido creado Informar cuál ha sido el libro más prestado Se debe devolver el libro que ha sido más prestado Ninguna El libro más prestado Informar que libros ha escrito un determinado autor Se selecciona el autor de un listado y se envía la posición donde estaba ubicado para poder buscar los libros que éste ha escrito La posición donde está ubicado el autor dentro del arreglo de autores. El listado de libros Listar los libros prestados por un determinado usuario Se deben listar los libros prestados por un determinado usuario La posición donde está ubicado el usuario dentro del arreglo de usuarios El listado de libros prestados Listar los autores de un libro Se debe permitir listar los autores de un libro
  • 67.
    1)posición donde estáubicado el libro dentro del arreglo de libros El listado de autores del libro 5.2 Comprensión del mundo del problema Se pueden identificar diferentes entidades: Biblioteca, Cliente, Autor, Libro y Préstamo:
  • 70.
    } public String toString() { return"cedula "+cedula+ " nombre "+nombre; }} El método toString devuelve la representación en String del objeto, en el caso del Autor se devuelve la cédula y el nombre. publicclass Cliente { private String cedula, nombre; public Cliente (String cedula, String nombre) { this.cedula = cedula; this.nombre = nombre; } public String toString() { return "cedula "+cedula+ " nombre "+nombre; }} Por otro lado, en la clase Libro se requiere declarar los siguientes atributos: publicclass Libro { //---------------------------------------------------- ------------// Atributos //---------------------------------------------------- ------------/** * Ese el código isbn del libro */ private String codigo; /**
  • 71.
    * Es elnombre del libro */ private String nombre; /** * La cantidadDeExistencias representan la cantidad de copias que hay por libro. */ privateint cantidadDeExistencias; /** * El género es un entero 0--> Programación, 1-->Bases de datos, * 2-->Compiladores, 3-->Arquitectura */ privateint genero; /* * El array que contiene el listado de autores */ private Autor misAutores[]; /* * Lleva la cuenta de los autores agregados */ privateint contadorAutores; //---------------------------------------------------- ------------//Constantes //---------------------------------------------------- ------------ /** * Es la cantidad máxima de autores */ publicstaticfinalintMAXIMO_AUTORES=5;
  • 72.
    El constructor dela clase Libro permite inicializar los atributos de la clase, por ello recibe el código del libro, el nombre, la cantidad de existencias y el género. En este mismo método se le reserva memoria al arreglo de autores. public Libro(String codigo, String nombre, int cantidadDeExistencias, int genero) { this.codigo=codigo; this.nombre=nombre; this.cantidadDeExistencias=cantidadDeExistencias; this.genero=genero; misAutores=new Autor[MAXIMO_ACTORES]; } El método agregarAutor tiene como parámetro un objeto de tipo autor. Antes de asignar el autor al libro se debe verificar que no se exceda la cantidad de autores máxima, es decir, 5. publicvoid agregarAutor(Autor miAutor) { if(contadorAutores<misAutores.length) { misAutores[contadorAutores]=miAutor; contadorAutores++; } } En la clase Préstamo se declaró como atributo el libro y el cliente que va a realizar la solicitud. En esta clase solo es necesario construir el método constructor, que lleva dos parámetros, y los respectivos métodos get para cada uno de los atributos de la clase. publicclass Prestamo { //---------------------------------------------------- ------------// Atributos //----------------------------------------------------
  • 73.
    ------------/** * Es ellibro que se va a prestar */ private Libro miLibro; /** * Es el cliente al que se le va a prestar el libro */ private Cliente miCliente; } Finalmente, se debe construir la clase Biblioteca. En esta clase se han declarado los siguientes atributos: publicclass Biblioteca{ //---------------------------------------------------- ------------// Atributos //---------------------------------------------------- ------------/** * Es el arreglo de autores */ private Autor[] misAutores; /** * Es el arreglo de clientes */ private Cliente[] misClientes; /** * Es el arreglo de libros */ private Libro[] misLibros; /** * Es el arreglo de prestamos
  • 74.
    */ private Prestamo[] misPrestamos; /** *Es el contador de autores */ privateint contadorAutores; /** * Es el contador de clientes */ privateint contadorClientes; /** * Es el contador de libros */ privateint contadorLibros; /** * Es el contador de prestamos */ privateint contadorPrestamos; //---------------------------------------------------- ------------//Constantes //---------------------------------------------------- ------------publicstaticfinalintMAXIMO=100; } ACTIVIDAD Acontinuación se muestran algunos de los métodos más relevantes de la clase Biblioteca. Rellene los métodos que así lo requieran. El método buscarCliente recibe el código del cliente y recorre el arreglo de clientes en su búsqueda. public Cliente buscarCliente(String codigo) { for(int i=0; i<contadorClientes; i++) { if(misClientes[i].getCodigo().equals(codigo)) return
  • 75.
    misClientes[i]; } returnnull; } /** * Estemétodo permite agregar un cliente, para ello se recibe un codigo * y un nombre. Es de anotar que antes de agregar se verifica que el * cliente no exista en el sistema, porque no pueden haber clientes con * el mismo codigo, para ello se hace uso del método buscarCliente. En * caso de que buscarCliente retorne null es porque el cliente no existe, * de lo contrario se retorna el cliente encontrado * @param codigo El código del cliente, codigo!=null * @param nombre El nombre del cliente, nombre!=null * @return true en caso de que el cliente se agregue satisfactoriamente */ publicboolean agregarCliente(String codigo, String nombre) { if(buscarCliente(codigo)==null&& contadorClientes<MAXIMO) { } returnfalse; El método asignarAutorLibro recibe la posición del autor dentro del arreglo de autores, con dicha posición obtiene el autor y se lo asigna al último libro. publicvoid asignarAutorLibro(int i) { Autor miAutor=misAutores[i];
  • 76.
    misLibros[contadorLibros-1].agregarAutor(miAutor); } /** * Permite listartodos los autores de un libro * @param posicion Es la posicion en la cual está ubicada el libro dentro * del array de Libros * @return un array de String con el listado de autores del libro */ public String[] listarAutoresLibro(int posicion) { String salida[]=new String[5]; Libro miLibro=misLibros[posicion]; for(int i=0; i< miLibro.getContadorAutores();i++) { } return salida; } /** * Permite listar los libros que un usuario tiene prestados * @param posicion La posicion del usuario dentro del array de usuarios * @return un array de string con el listado de los libros */ public String[] listarLibrosPrestadosPorUsuario(int posicion) { Cliente miCliente=misClientes[posicion]; String prestados[]=new String[100]; int contador=0; for(int i=0; i<contadorPrestamos; i++) { } return prestados; }
  • 77.
    devolverCantidadExistenciasPrestadasPorLibro permite devolverla cantidad de existencias prestadas que hay de un libro. Con un for se recorre el array de préstamos y se busca el libro si lo encuentra se debe contar. Al final se devuelve el contador. publicint devolverCantidadExistenciasPrestadasPorLibro(String codigo) { int contador=0; for(int i=0; i<contadorPrestamos; i++) { if(misPrestamos[i].getMiLibro().getCodigo().equals(cod { contador++; } } return contador; } El método prestarLibro recibe la posición del libro y la posición del cliente para poder realizar el préstamo. /** * Permite prestar una libro * @param posicionL La posicion del libro dentro del arreglo de libros * @param posicionCliente La posicion del cliente dentro del array de * clientes * @return true si se pudo prestar el libro */ publicboolean prestarLibro(int posicionL, int posicionCliente ) { /*
  • 78.
    * Se debeobtener el libro y el cliente, al igual que la cantidad de * existenciasprestadas por ese libro. Es importante tener en cuenta que * si solo hay por ejemplo 3 existencias de ese libro y ya todos están * prestados no podrá prestar más. * De igual forma se verifica que ese prestamo no haya sido efectuado ya, * eso quieredecir que si el cliente con codigo 123 prestó el libro 45, * entonces este cliente no podrá volver a prestar ese libro */ Libro miLibro=misLibros[posicionL]; Cliente miCliente=misClientes[posicionCliente]; int cantidadPrestamos=devolverCantidadExist if (cantidadPrestamos<miLibro.getCantidadDeExistencias()& o(miLibro, miCliente)==false) { Prestamo miP = new Prestamo(miLibro, miCliente); misPrestamos[contadorPrestamos]=miP; contadorPrestamos++; verificarInvariante(); returntrue; } returnfalse; /** * Devuelve el libro mas prestado * @return El libro mas prestado */
  • 80.
    6.1 Requisitos funcionales Pararesolver este caso de estudio se identificaron los siguientes requisitos funcionales: Requisito funcional 1 Nombre Descripción Requisito funcional 2 Entrada Salida Nombre Descripción Entrada Requisito funcional 3 Salida Nombre Descripción Entrada Requisito funcional 4 Requisito funcional 5 Requisito funcional 6 Salida Nombre Descripción Entrada Salida Nombre Descripción Entrada Salida Nombre Descripción Entrada Salida Agregar un docente Se debe permitir agregar un docente al listado general de docentes. Es importante
  • 81.
    verificar que eldocente no exista en el sistema. 1)código, 2)nombre Un nuevo docente ha sido agregado Agregar un grupo Se debe permitir agregar un grupo al listado general. Es importante verificar que el grupo no exista ya en el sistema. 1) numero,2) nombre del Grupo,3) código del líder del grupo,4)el listado de integrantes del grupo Un nuevo grupo ha sido agregado Asignar un producto a un grupo Se debe permitir asignar un producto a un grupo 1)La posición del grupo dentro del arreglo de grupos, 2) el tipo de producto ,3) El código del grupo, 4) el listado de docentes que crearon el producto Un nuevo producto se le asigna al grupo Listar todos los grupos Se debe generar un listado con la totalidad de grupos Ninguna El listado de grupos Listar productos de un grupo Se debe permitir el listado de productos de un determinado grupo 1) La posición del grupo dentro del arreglo de grupos El listado de productos del grupo indicado Listar todos los docentes Se debe permitir listar todos los docentes que hay en la universidad Ninguna El listado de docentes 6.2 Comprensión del mundo del problema Se pueden identificar diferentes entidades: Universidad, GrupoDeInvestigacion, Docente y Producto.
  • 84.
    También es necesarioun método constructor, los correspondientes métodos get para cada uno de los atributosy el método toString. public String toString() { return " Código: "+codigo+" Nombre: "+ nombre; } La clase GrupoDeInvestigacion tiene entre otros los siguientes métodos: El método agregarProducto tiene 4 parámetros, a saber: el tipo, el codigo y el listado de docentes que crearon el producto. Antes de agregar el producto se debe verificar que no se exceda el máximo de productos, es decir, 100. publicvoid agregarProducto(int tipo, String codigo, Docente misDocentes[] ) { if(contadorProductos<MAXIMO) { Producto aux=new Producto(tipo,codigo,misDocentes); misProductos[contadorProductos]=aux; contadorProductos++; } } El método agregarIntegranteGrupo se encarga de agregar un nuevo integrante al grupo. Es importante verificar que dicho docente ya no existe en el grupo, con el objetivo de evitar repeticiones. publicvoid agregarIntegranteGrupo(Docente miIntegrante) { if(buscarDocente(miIntegrante.getCodigo(),misIntegrante { for (int i=0; i<misIntegrantes.length;i++) { if(misIntegrantes[i]==null) {
  • 85.
    misIntegrantes[i]=miIntegrante; } } } } Elmétodo devolverProductosGrupo() devuelve el listado de productos del grupo. public String[] devolverProductosGrupo() { //Se recorre el arreglo de misProductos y se verifica si en esa posición //hay producto, en tal caso se agrega al arreglo productos la //representación en String de dicho producto String productos[]=new String[MAXIMO]; return productos; } Por otro lado, de la clase Producto los atributos son los siguientes: //---------------------------------------------------- ------------// Atributos //---------------------------------------------------- ------------/** * Es el tipo del producto. Puede ser articulo (1) o libro (0) */ privateint tipo; /** * Es el código del producto */ private String codigo; /** * Es el listado de docentes que crearon el producto
  • 86.
    */ private Docente misDocentes[]; } Elconstructor de la clase Producto permite inicializar los 3 atributos de la clase. public Producto(int tipo, String codigo,Docente misDocentes[]) { this.misDocentes=misDocentes; this.tipo=tipo; this.codigo=codigo; } El método listarAutores Devuelve un String con el listado de autores. public String listarAutores() { String s=""; for(int i=0; i<misDocentes.length;i++) { if(misDocentes[i]!=null) s+=misDocentes[i].getNombre()+" , "; } return s; } Para finalizar la solución de este caso de estudio se debe construir la clase Universidad. Sus atributos se muestran a continuación: publicclass Universidad { //---------------------------------------------------- ------------// Atributos //---------------------------------------------------- ------------/** * Es el listado de grupos de investigacion
  • 87.
    */ private GrupoDeInvestigacion misGruposDeInvestigacion[]; /** *Es el listado general de docentes */ private Docente misDocentesGeneral[]; //---------------------------------------------------- ------------//Constantes //---------------------------------------------------- ------------/** * Es la constante para manejar el número máximo de docentes y grupos */ privatestaticfinalintMAXIMO=100; } Se destacan los siguientes métodos: El método agregar docente se encarga de insertar un nuevo docente en el arreglo de general de docentes. Tiene dos parámetros el código y el nombre. publicint agregarDocente(String codigo, String nombre) { int pos=GrupoDeInvestigacion.buscarDocente(codigo, misDocentesGeneral); if(pos==-1) { for (int i=0; i<misDocentesGeneral.length;i++) { if(misDocentesGeneral[i]==null) { misDocentesGeneral[i]=new Docente(codigo, nombre); return i; }
  • 88.
    } } return -1; } El métodobuscarGrupo recibe el código del grupo que se desea hallar. Debe recorrer el arreglo de grupos en su búsqueda. En caso de encontrarlo devuelve la posición donde está, de lo contrario retorna -1. publicint buscarGrupo(int numero) { } El método agregarGrupo recibe la información necesaria para crear un nuevo grupo de investigación, a saber: el número del grupo, el nombre, el código del líder y un arreglo con las posiciones dentro del array de docentes de las personas que van a incorporarse. publicint agregarGrupo(int numero,String nombreGrupo,String codigoLid,int integrantes[]) { int posicionEnArregloDelGrupo=0; int posicionLiderEnArregloGeneral=GrupoDeInvestigacion.bus misDocentesGeneral); Docente misDocentesDelGrupo[]=new Docente[integrantes.length]; for(int i=0; i<misDocentesDelGrupo.length; i++) { misDocentesDelGrupo[i]=misDocentesGeneral[integrantes[ if(misDocentesDelGrupo[i].getCodigo().equals(misDocente regloGeneral].getCodigo())) {
  • 89.
    posicionEnArregloDelGrupo=i; } } GrupoDeInvestigacion miGrupo= new GrupoDeInvestigacion(); miGrupo.setMisIntegrantes(misDocentesDelGrupo); miGrupo.setNombreGrupo(nombreGrupo); miGrupo.setNumero(numero); miGrupo.setPosicionLider(posicionEnArregloDelGrupo); if(buscarGrupo(numero)==-1) { for(int i=0; i<misGruposDeInvestigacion.length;i++) { if(misGruposDeInvestigacion[i]==null) { misGruposDeInvestigacion[i]=miGrupo; return i; } } } return -1; } Finalmente, el método agregarProductoAGrupo recibe la posicion del grupo al cual se le asignará, ya sea el libro o el artículo, además del listado de integrantes que elaboró el producto. publicvoid agregarProductoAGrupo(int posGrupo, int tipo, String codigo, int integrantes[]) { Docente misDocentesDelGrupo[]=new Docente[integrantes.length]; for(int i=0; i<misDocentesDelGrupo.length; i++)
  • 90.
    { misDocentesDelGrupo[i]=misDocentesGeneral[integrantes[ } Producto miProducto=new Producto(tipo,codigo, misDocentesDelGrupo); misGruposDeInvestigacion[posGrupo].agregarProducto(tipo codigo, misDocentesDelGrupo); } ESTRUCTURAS CONTENEDORAS DE TAMAÑO VARIABLE 1 Objetivos Al finalizar la unidad el estudiante estará en capacidad de: Utilizar estructuras contenedoras de tamaño variable para resolver problemas en los cuales es necesario almacenar una secuencia de elementos cuya cantidad no se conoce con anterioridad. Utilizar ciclos para poder manipular las estructuras contenedoras variables 2 Motivación Algunas veces se requiere resolver problemas en los cuales es necesario almacenar una secuencia de elementos, pero no se sabe cuántos. Esta característica obviamente debe verse reflejada en el diagrama de clases. Además, al momento de plantear la solución, ese grupo de elementos se debe materializar, es aquí en donde el aplica el concepto de ArrayList. 3 Caso de estudio N.1 Conjuntos (Código Fuente: unidadIICaso01Conjuntos) Se requiere de una aplicación que permita realizar las operaciones de intersección y unión entre varios conjuntos. Se debe permitir también que se eliminen todos los conjuntos que se han agregado hasta el momento. El resultado de las operaciones de unión e intersección se deben mostrar ordenados alfabéticamente.
  • 92.
    Requisito funcional 4Entrada Salida Nombre Descripción Entrada Salida Nombre Descripción Entrada Salida Hallar la intersección entre varios conjuntos Se debe hallar la intersección entre todos los conjuntos que el usuario haya ingresado hasta el momento. La intersección consiste en encontrar los elementos que son comunes en todos los conjuntos. Ninguna Un nuevo conjunto con el resultado de la intersección Hallar la unión entre varios conjuntos Se debe hallar la unión entre todos los conjuntos que el usuario haya ingresado hasta el momento. Ninguna Un nuevo conjunto con el resultado de la unión Ordenar alfabéticamente los elementos de un conjunto Se recibe un conjunto y se aplica un método de ordenamiento para lograr que los elementos queden ubicados de menor a mayor Un conjunto El conjunto ordenado Eliminar los conjuntos Se debe permitir borrar todos los conjuntos que se han ingresado hasta el momento Ninguna Los conjuntos han sido eliminados
  • 93.
    3.2 Comprensión delmundo del problema Se pueden identificar diferentes entidades: GrupoConjunto y Conjunto.
  • 95.
    3.3 Diseño yconstrucción de la solución del problema Este caso de estudio requiere de la utilización de estructuras contenedoras de tamaño variable, en la cuales no se requiere que se conozca su tamaño máximo tal como ocurre en los arreglos, pues crece o disminuye dinámicamente. En Java existen varias clases que permiten crear este tipo de estructuras, entre ellas la clase Vector o la clase ArrayList. En este documento se hará uso de la segunda. Cuando se debe representar en el diagrama de clases este tipo de asociaciones se coloca como cardinalidad los símbolos 0…* para aclarar que su tamaño puede variar. Todo ArrayList debe declararse y se le debe reservar memoria. Tal como se muestra a continuación: private ArrayList <Conjunto> misConjuntos ; public GrupoConjunto() { misConjuntos=new ArrayList<Conjunto>(); } En la clase GrupoConjunto se declara un Vector donde cada elemento corresponde a un conjunto. Para que esto sea posible es necesario importar el paquete java.util.*; Observe que al momento de reservarle memoria no fue necesario indicar la cantidad de elementos que iba a contener. Esto quiere decir, que automáticamente se arranca con 0 elementos dentro de él. No obstante, ArrayList también brinda la posibilidad de definir un tamaño inicial: misConjuntos=new ArrayList<Conjunto>(9); En este caso se ha creado un ArrayList con un tamaño inicial de 9. Algunos de los
  • 96.
    métodos más importantesde los ArrayList son: size(): Devuelve la cantidad de elementos que hay en la estructura isEmpty(): Devuelve true si no hay elementos en el ArrayList, de lo contrario devuelve false. add(elemento): permite agregar al final de la estructura contenedora un nuevo elemento. add(posición, elemento): permite agregar un elemento en la posición indicada. Si ya había un elemento en esa posición, el elemento que ya existe y todos los que se encuentran a su derecha se correrán una posición hacia la derecha. set(posición, elemento): Permite reemplazar el elemento que se encuentra en la posición por un nuevo elemento. remove (posición): borra el elemento que está en la posición indicada, esto implica que los elementos que estaban a la derecha del elemento eliminado se correrán hacia la izquierda para ocupar el lugar eliminado. Esta operación hace que el tamaño de la estructura se reduzca en 1. remove(elemento): en este caso se envía el objeto que se desea eliminar. Es importante aclarar, que si se crea un nuevo elemento con los datos del objeto que se desea eliminar no indica que sea el mismo elemento. Para que sean iguales deben ocupar la misma posición de memoria, es decir, deben ser la mismas instancia. contains(elemento): Devuelve true si el elemento exist, de lo contrario devuelve false. toArray().Copia los elementos que tiene el ArrayList a un arreglo de objetos. Partiendo del diagrama de clases anterior se iniciará con la construcción de las clases del paquete mundo. Primero se mostrarán los atributos de la clase conjunto. publicclass Conjunto {
  • 97.
    //---------------------------------------------------- ------------// Atributos //---------------------------------------------------- ------------/** * Sonlos elementos que forman parte del conjunto */ private ArrayList <String> misElementos; } La clase Conjunto tiene dos métodos constructores. El primero de ellos no tiene parámetros. Su objetivo es reservarle memoria al ArrayList de elementos del conjunto. public Conjunto() { misElementos=new ArrayList<String>(); } El segundo, recibe un ArrayList con los elementos del conjunto. public Conjunto(ArrayList<String> misElementos) { this.misElementos = misElementos; } Observe que hay dos constructores, el primero de ellos permite reservarle memoria al Arraylist, surgiendo entonces un conjunto con cero elementos. En el segundo constructorse reciben los elementos del conjunto por parámetro. public Conjunto(ArrayList<String> misElementos) Finalmente el método toString() devuelve un String con la representación del conjunto. public String toString()
  • 98.
    { return misElementos.toString(); } Porotra parte, en la clase GrupoConjuntos se encuentran, entre otros, los siguientes atributos. publicclass GrupoConjunto { //---------------------------------------------------- ------------//Atributos //---------------------------------------------------- ------------/** * Es el arreglo de conjuntos */ private ArrayList <Conjunto> misConjuntos ; } El método inicializar(ArrayList <ArrayList<String>> arreglo ) recibe por parámetro un ArrayList de un ArrayList de String, esto quiere decir, que se tendrá un ArrayList general llamado arreglo, que en la posición cero almacenará otro ArrayList de String (correspondiente al primer conjunto que ingresó el usuario). En la posiión 1, tendrá otro ArrayList con todos los elementos del segundo conjunto y así sucesivamente. El método publicvoid inicializar(ArrayList <ArrayList<String>> arreglo) se encarga de convertir los elementos que hay en la posición cero del arrayList que recibe en un nuevo conjunto, los elementos que hay en la posición 1 en un nuevo conjunto y así continúa hasta que recorra todo el ArrayList. Este objetivo se logra a través de las siguientes instrucciones: for(int i=0; i<arreglo.size(); i++)
  • 99.
    { misConjuntos add(new Conjunto(arreglo.get(i))); } publicvoidinicializar(ArrayList <ArrayList<String>> arreglo ) { misConjuntos=new ArrayList<Conjunto>(); for(int i=0; i<arreglo.size(); i++) { misConjuntos.add(new Conjunto(arreglo.get(i))); } } El método public Conjunto ordenarAlfabeticamente(Conjunto miConjunto)aplica el técnica de ordenamiento de Burbuja para ordenar ascendentemente los elementos del conjunto. public Conjunto ordenarAlfabeticamente(Conjunto miConjunto) {//Se aplica burbuja para ordenar ArrayList<String> auxiliar=miConjunto.getMisElementos(); for(int i=0; i<auxiliar.size();i++) { for(int j=0; j<auxiliar.size()-1;j++) { if(auxiliar.get(j).compareTo(auxiliar.get(j+1))>0) { String aux=auxiliar.get(j); auxiliar.set(j,auxiliar.get(j+1)); auxiliar.set(j+1, aux); } } }
  • 100.
    returnnew Conjunto(auxiliar); } Paraentender como funciona este algoritmo imagine que se tiene un arreglo cuyos elementos son: 66 39 4 35 y 2 y que se ordenará siguiendo la estrategia mostrada en la siguiente tabla. 66 39 4 35 2 39 66 4 35 2 39 4 66 35 2 39 4 35 66 2 39 4 35 2 66 4 39 35 2 66 4 35 39 2 66 4 35 2 39 66 4 35 2 39 66 4 2 35 39 66 4 2 35 39 66 4 2 35 39 66 2 4 35 39 66 2 4 35 39 66 2 4 35 39 66 2 4 35 39 66 Se puede observar que lo que se ha hecho es desplazar los elementos más pequeños hacia el inicio del arreglo (hacia el primer elemento) y los elementos mayores se movieron hacia el fondo del arreglo. Generalizando, lo que se hizo es tomar el elemento mayor, el cual se fue recorriendo de posición en posición hasta ponerlo en su lugar. Aeste método de ordenamiento se le conoce como Burbuja. Es importante anotar, que existen otros métodos de ordenamiento, entre ellos se destacan el método de inserción directa y el método de selección.
  • 101.
    El método deInserción directa se basa en tomar uno por uno los elementos de un arreglo y recorrerlo hacia su posición con respecto a los anteriormente ordenados. Así empieza con el segundo elemento y lo ordena con respecto al primero. Luego sigue con el tercero y lo coloca en su posición ordenada con respecto a los dos anteriores, así sucesivamente hasta recorrer todas las posiciones del arreglo. Otro método muy conocido es el de Selección, el cual consiste en encontrar el menor de todos los elementos del arreglo e intercambiarlo con el que está en la primera posición. Luego el segundo más pequeño, y así sucesivamente hasta ordenar todo el arreglo. Por otra parte, el método public ConjuntohallarUnion(), crea un ArrayList de String en el cual se incluyen todos los elementos de todos los conjuntos verificando que no se presenten repeticiones. public Conjunto hallarUnion() { ArrayList<String> resultado=new ArrayList<String>(); for (int i=0; i<misConjuntos.size(); i++) { for(int j=0;j<misConjuntos.get(i).getMisElementos().size();j++ { String dato=misConjuntos.get(i).getMisElementos().get(j); if(!resultado.contains(dato)) resultado.add(dato); } } returnnew Conjunto(resultado);
  • 102.
    } Para el métodohallarInterseccion() se require de 3 for. El primero de ellos recorre cada uno de los elementos del conjunto cero. Através del segundo for se obtienen todos los conjuntos (diferentes al conjunto cero) y con el tercer for, se recorren los elementos de cada uno de esos conjuntos. La idea general consiste en que cada elemento obtenido del conjunto cero debe compararse con cada uno de los elementos que hay en cada conjunto. Si al final se determina que un elemento del conjunto cero, está presente en todos los demás conjuntos, ese elemento se selecciona y se agrega al resultado. public Conjunto hallarInterseccion() { int k, j,l; ArrayList <String> misElementos=new ArrayList<String> (); String elemento="", elemento1=""; /*Se obtiene el conjunto 0 del conjunto 0 se obtiene cada uno de sus elementos es decir, se obtiene el elemento j*/ for(j=0;j<misConjuntos.get(0).getMisElementos().size() { elemento=misConjuntos.get(0).getMisElementos().get(j); /*El elemento obtenido debe compararse con cada uno de los elementos que hay en cada conjunto. Por lo tanto se toma cada uno de los conjuntos que son diferentes al conjunto 0 y se saca cada uno de los elementos para luego comparse con el elemento del conjunto 0*/ int contador=0;
  • 103.
    for(k=1; k<misConjuntos.size(); k++) { for(l=0; l<misConjuntos.get(k).getMisElementos().size();l++) { elemento1=misConjuntos.get(k).getMisElementos().get(l) if(elemento.equals (elemento1)) { contador++; } } } //si hay 4 conjuntos entonces el elemento comparado debe estar repetido 3 //veces if(contador==misConjuntos.size()-1) { String elem=misConjuntos.get(0).getMisElementos().get(j); if(!misElementos.contains(elem)) misElementos.add(elem); } } returnnew Conjunto(misElementos); } } 4 Caso de estudio N.2 Conjunto Cerrado (Código Fuente:unidadIICaso02ConjuntoCerrado) Se desea crear una aplicación para manejar la información de un conjunto cerrado. El conjunto cerrado tiene 55 casas, de las cuales las primeras 35 deben pagar 142000 por concepto de administración (pues son casas de dos plantas), las restantes deben pagar este mismo valor incrementado en un 10% ( son casas de tres plantas). Cada casa tiene un listado de habitantes, un número y una cantidad de pisos. Cuando una persona compra una casa, por cada habitante se registra el
  • 104.
    nombre, la identificación,la edad y un tipo. En el caso de los niños menores de 13 años la administración solicita al propietario de la vivienda que informe si el menor puede salir o no del conjunto. La aplicación debe permitir adicionalmente mostrar el listado de propietarios de viviendas y la cantidad de niños autorizados a salir del conjunto, también el total recaudado en administración.
  • 106.
    Nombre Descripción Entrada Salida Registrar unapersona en una determinada casa Se debe registrar una persona, para ello se ingresan sus datos personales y se indica si es o no el propietario. Si la persona es menor de 13 años el propietario debe informar si el niño puede salir del conjunto sin la compañía de un adulto. 1)el número de la casa en la que habitará la persona 2)nombre3)identificacion,4)autorización a salir 5) indicar si es propietario5)edad La persona ha sido registrada Listar todos los propietarios del conjunto Se debe recorrer el listado de casas y por cada una de ellas sacar el propietario. Ninguna La lista de propietarios Calcular el total recaudado en administración Para calcular el total recaudado en administración se debe tener en cuenta que las primeras 35 deben pagar 142000 por concepto de administración, las restantes deben pagar este mismo valor incrementado en un 10% . Si la casa no tiene propietario, es decir, aún pertenece a la constructora no debe pagar administración. Ninguna El total recaudado por concepto de administración 4.2 Comprensión del mundo del problema Las clases identificadas son: ConjuntoCerrado, Casa, Habitante
  • 108.
    //---------------------------------------------------- ------------//Constantes //---------------------------------------------------- ------------/** * Es elvalor de la cuota de administración */ privatefinalstaticdoubleVALOR=142000; } En el método constructor se le reserva memoria al ArrayList de Habitantes y se indica la cantidad de pisos que tiene la propiedad. public Casa(int numero) { this.numero = numero; misHabitantes=new ArrayList<Habitante>(); cantidadPisos=2; if(numero<ConjuntoCerrado.TIPO1) { cantidadPisos=3; } } El método agregar tiene varios parámetros String nombre, String identificacion, boolean autorizacionSalir, boolean propietario,int edad. Através de ellos es posible crear el nuevo habitante que luego será agregado al ArrayList de habitantes. publicvoid agregarHabitante(String nombre, String identificacion, boolean autorizacionSalir, boolean propietario,int edad) { misHabitantes.add( new Habitante(nombre, identificacion, autorizacionSalir, propietario, edad)); }
  • 109.
    El método calcularValorAPagarAdministracionverifica el número de la casa, si es menor de 35, entonces informa que debe pagar 142000, de lo contrario le aumenta un 10% a este valor. No se le cobra administración a viviendas que no tienen propietario, pues siguen siendo propiedad de la constructora. publicdouble calcularValorAPagarAdministracion() { if(misHabitantes.size()>0) {if(numero<ConjuntoCerrado.TIPO1) {returnVALOR;} else {returnVALOR*0.1;} } else return 0; } Por otro lado, en la clase ConjuntoCerrado se desarrollan métodos como los siguientes: Método constructor, en el que se crean la totalidad de casas. public ConjuntoCerrado() { misCasas=new ArrayList<Casa>(); for(int i=0; i<MAXIMO; i++) { misCasas.add( new Casa(i+1)); } } El método informarCantidadNinosAutorizados recorre el ArrayList de casas y por cada casa el ArrayList de habitantes y verifica si el habitante es menor de 13 años y si está autorizado a salir. Si esto es verdadero incrementa el contador. publicint informarCantidadNinosAutorizados()
  • 110.
    { int contador=0; for(int i=0;i<misCasas.size();i++) { for(int j=0; j<misCasas.get(i).getMisHabitantes().size(); j++) { if(misCasas.get(i).getMisHabitantes().get(j).getEdad() <13&& misCasas.get(i).getMisHabitantes().get(j).isAutorizacio contador++; } } return contador; } El método calcularTotalAdministracion recorre el ArrayList de casas y acumula el valor que se debe pagar por cada casa en la variable acum. publicdouble calcularTotalAdministracion() {double acum=0; for(int i=0; i<misCasas.size();i++) { acum+=misCasas.get(i).calcularValorAPagarAdministracion } return acum; } 5 Caso de estudio N.1 El Avión (Código Fuente: unidadIIHoja01Avion) Se desea crear una aplicación para manejar la información de un avión. El usuario de la aplicación deberá informar inicialmente cuantas filas y columnas están
  • 111.
    presentes en elavión. Se aceptarán valores entre 6 y 11 para las columnas y entre 4 y 14 para las filas. La aplicación debe permitir sentar a un pasajero indicando su información básica, su ubicación y clase de preferencia. Las posibles ubicaciones son Centro y Ventana y las posibles clases son Económica y Ejecutiva. La clase ejecutiva corresponde a los puestos ubicados en la diagonal principal y secundaria en las primeras 4 filas. En el avión siempre habrá una zona inactiva que corresponde a los elementos que se encuentran entre la diagonal principal y secundaria en las cuatro primeras filas.Todos los demás puestos corresponden a ubicación económica. Es muy importante que se conserve el registro de todos los pasajeros que se han sentado en cada una de las sillas. También se debe permitir eliminar un pasajero indicando su cédula y consultar la información de un pasajero indicando su posición.
  • 113.
    Salida Nombre Descripción Entrada Salida Ubicar unpasajero El pasajero llega a la aeropuerto y da sus datos personales y preferencias en torno a clase y ubicación 1)cedula, 2)nombre, 3)clase, 4)ubicación El pasajero ha sido ubicado Cancelar la reservación de un pasajero Para cancelar la reservación de un pasajero se debe solicitar la cédula La cédula La reservación ha sido cancelada Consultar la información de un pasajero Para consultar la información de un pasajero se debe informar la posición en la cual está ubicado La posición El pasajero que está ubicada en dicha posición 5.2 Comprensión del mundo del problema Se pueden identificar diferentes entidades: Avión, Puesto y Persona
  • 115.
    /** * Es lacedula de la persona */ private String cedula; } En esta clase se requiere de un constructor y los correspondientes métodos get y set. En la clase Puesto, además de los métodos get y set para número, clase, ubicación y estado se cuenta con los siguientes: - El método Constructor permite inicializar los atributos número y estado y reservarle memoria al ArrayList de personas. public Puesto(int numero, int estado) { this.numero = numero; this.estado=estado; misPersonas=new ArrayList<Persona>(); } - El método agregarPersona tiene como parámetros el nombre y la cédula. Con estos datos se crea la persona que se va a agregar al ArrayList. Luego de agregar una persona la variable estado se pone en 1. publicvoid agregarPersona(String nombre, String cedula) { Persona miPersona = new Persona(nombre,cedula); misPersonas.add(miPersona); estado=1; } - Para eliminar una persona sólo se pone el estado en cero. No se elimina físicamente puesto que se solicitó conservar el resgistro de todos los clientes que
  • 116.
    se han ubicadoen los puestos. publicvoid eliminarUltimaPersona() { estado=0; } Finalmente, algunos de los métodos de la clase Avion son: El método constructor del Avión. En éste se le reserva memoria al ArrayList y a cada uno de los Puestos. Es importante ir colocando la clase y la ubicación a cada puesto a mediad que se van creando. Observe que la clase se le asignó a cada puesto a través de una enumeración. Tal como se muestra a continuación: /*Aqui se crean todas las sillas que están en mantenimiento*/ for(int i=0; i<inicio.size(); i++) { for(int j=inicio.get(i)+1; j< finaliza.get(i); j++) { misPuestos.get(j).setClase(Clase.MANTENIMIENTO.getNumC } } public Avion(int filas,int columnas) { misPuestos=new ArrayList<Puesto>(); for(int i=0; i< columnas*filas; i++) { Puesto miPuesto=new Puesto(i,0); misPuestos.add(miPuesto); } ArrayList<Integer> inicio= new ArrayList<Integer>();
  • 117.
    ArrayList<Integer> finaliza=new ArrayList<Integer>(); intizq=columnas+1; int derecha=columnas-1; /*Aqui se crean todos los puestos de clase ejecutiva y se capturan todas las posiciones para poder crear las sillas inactivas*/ for(int i=0; i<4;i++) { inicio.add(i*izq); finaliza.add(derecha*(i+1)); misPuestos.get(i*izq).setClase(Clase.EJECUTIVA.getNumC misPuestos.get(derecha* (i+1)).setClase(Clase.EJECUTIVA.getNumClase()); } /*Aqui se crean todas las sillas que están en mantenimiento*/ for(int i=0; i<inicio.size(); i++) { for(int j=inicio.get(i)+1; j< finaliza.get(i); j++) { misPuestos.get(j).setClase(Clase.MANTENIMIENTO.getNumC } } /*No es necesario ponerle clase a las que falta, pues por defecto se inicializaron con tipo 0 que es económica. Ahora se fijan las ventanas. No es necesario fijar el centro pues por defecto se inicializó con cero. */ for(int i=0; i<=filas*columnas-columnas; i+=columnas ) { misPuestos.get(i).setUbicacion(Ubicacion.VENTANA.getNum misPuestos.get(i+columnas- 1).setUbicacion(Ubicacion.VENTANA.getNumUbicacion());
  • 118.
    } } El método ubicarPasajerose encarga de ubicar un pasajero en un puesto acorde a las preferencias expresadas con respecto a la clase y la ubicación. Si el pasajero ya existe, no puede ubicarse nuevamente en el avión. publicint ubicarPasajero(String nombre, String cedula, int numUbicacion, int numClase) { if(buscarPasajero(cedula)==-1) { for(int i=0; i< misPuestos.size(); i++) { if(misPuestos.get(i).getEstado()==0&&misPuestos.get(i) on&&misPuestos.get(i).getClase()==numClase) { misPuestos.get(i).agregarPersona(nombre, cedula); return i; } } } return -1;} 5.4 Enum como nuevo elementos de modelado Un nuevo elemento de modelado que se incorpora en este caso de estudio es el enum. Un enum se utiliza para limitar el contenido de una variable a una lista de valores definidos con anterioridad. Un tipo enumerado es una instancia del tipo enumerado del cual se declaró. No se puede considerar como un String o un entero.
  • 119.
    publicenum Clase { //Clasesde puestos EJECUTIVA (1), ECONOMICA(0), MANTENIMIENTO(2); privateint numClase; private Clase(int numClase) { this.numClase = numClase; } publicint getNumClase() { return numClase; } publicvoid setNumClase(int numClase) { this.numClase = numClase; } } Si en un momento dado se requiere imprimir la clase de cada uno de los puestos que hay en el avión sería posible apoyarnos en esta misma enumeración, mediante la instrucciónClase.values()[tipo],lo cual se puede interpretar como: Si tipo toma el valor de cero, entonces Clase. values()[0] devolverá EJECUTIVA, si toma el valor de 1, Tipo.values()[1] devolverá ECONOMICA, si toma el valor de 2, Tipo.values()[2] devolverá MANTENIMIENTO. ACTIVIDAD Construya un método que genere un listado con la información de todos los puestos que hay en el Cine. Es importante mostrar como mínimo el número de puesto, el estado del puesto y la clase del puesto. Para este caso de estudio también se creó una enumeración para trabajar la Ubicación del puesto.
  • 120.
    publicenum Ubicacion { //Clasesde puestos VENTANA (1), CENTRO(0); privateint numUbicacion; private Ubicacion(int numUbicacion) { this.numUbicacion = numUbicacion; } publicint getNumUbicacion() { return numUbicacion; } publicvoid setNumUbicacion(int numUbicacion) { this.numUbicacion = numUbicacion; } } 5.5 foreach en Java En el método buscar pasajero se utilizó la estructura repetitiva for-each, la cual permite iterar sobre colecciones de objetos.Toda Collection tiene un tamaño y puede recorrerse para conocer cada uno de los elementos que almacena. En Java hay clases que manejan colecciones y permiten realizar sus operaciones básicas, a saber: add(element): Agrega un elemento. iterator(): Obtiene un iterador. Un iterador es un objeto a través del cual es posible ir obteniendo uno a uno los objetos al ir llamando repetitivamente método next(). size(): Devuelve el tamaño de la colección contains(element): Pregunta si el elemento se encuentra dentro de la colección. Un ejemplo del uso de Iterator es el siguiente:
  • 121.
    void recorrer(Collection<Puesto> misP){ Iterator<Puesto> it = misP.iterator(); while(it.hasNext()) { Puesto miP = it.next(); } } Luego de la versión 6 de Java se ofrece una manera muy sencilla de recorrer una collección, que es sumamente útil en el caso de que no se requiera eliminar elementos. Esta estructura es el foreach. Tiene la siguiente sintáxis: for (TipoBase variable: ArrayDeTiposBase) {..} La utilización de esta estructura se muestra a continuación: publicint buscarPasajero(String cedula) { //Se recorren todos los puestos que hay en el ArrayList for(Puesto miPuesto: misPuestos) { //Por cada puesto se verifica que haya persona y que la cedula de dicha persona //coincida con la cédula de la persona buscada if(miPuesto.getMisPersonas().size()>0&&miPuesto.getMis MisPersonas().size()-1).getCedula().equals(cedula)&&mi { return miPuesto.getNumero(); } } return -1; }
  • 123.
    6.1 Requisitos funcionales Pararesolver este caso de estudio se identificaron los siguientes requisitos funcionales: Requisito funcional 1 Nombre Descripción Requisito funcional 2 Entrada Salida Nombre Descripción Entrada Requisito funcional 3 Requisito funcional 4 Salida Nombre Descripción Entrada Salida Nombre Descripción Entrada Salida Registrar un nuevo cliente Se debe registrar un nuevo cliente, para ellos se debe solicitar el código y el nombre. No se podrán registrar clientes que ya existan en el sistema. 1)código, 2)nombre Un nuevo cliente ha sido registrado Agregar una nueva cuenta Se debe permitir registrar una nueva cuenta 1)número de la cuenta, 2)el monto, 3)el tipo de cuenta (ahorro o corriente), 4)La posición donde se encuentra ubicado el cliente al cual se le va a crear la cuenta Se ha creado una nueva cuenta
  • 124.
    Generar el listadode las cuentas ordenado por monto Se debe generar el listado de cuentas ordenadas por mont Ninguna El listado de las cuentas ordenadas por monto Generar listado de cuentas por cliente Se debe generar listado de cuentas por cliente. Se podrá discriminar también por el tipo de cuenta 0 ó 1 o todas. 1) Posición del cliente dentro del ArrayList de clientes, 2) El tipo de consulta deseada ( Ahorro, corriente, todas) El listado de cuentas que tiene el cliente, de acuerdo al tipo seleccionado 6.2 Comprensión del mundo del problema Se pueden identificar diferentes entidades, a saber: Banco, Cliente y Cuenta.
  • 126.
    /** * Es elnombre del cliente */ private String nombre; } En esta clase se construyó un método constructor con dos parámetros y los métodos get para cada uno de los atributos. En la clase Cuenta se encuentran los siguientes atributos: publicclass Cuenta { //---------------------------------------------------- ------------// Atributos //---------------------------------------------------- ------------/** * Es el numero de la cuenta */ private String numero; /** * Es el cliente dueño de la cuenta */ private Cliente miCliente; /** * Es el tipo de la cuenta( 0-> ahorro, 1->corriente) */ privateint tipo; /** * Es la cantidad de dinero que hay en la cuenta */ privatedouble cantidadDinero; //----------------------------------------------------
  • 127.
    ------------//Constantes //---------------------------------------------------- ------------/** * Es laconstante para manejar la cuenta de tipo ahorro */ publicstaticfinalintTIPO_AHORRO=0; /** * Es la constante para manejar la cuenta de tipo corriente */ publicstaticfinalintTIPO_CORRIENTE=0; } Algunos de los métodos más importantes de esta clase son los mostrados a continuación: El método constructor que permite inicializar los atributos numero, tipo y cantidadDinero. public Cuenta(String numero, int tipo, double cantidadDinero) { this.numero = numero; this.tipo = tipo; this.cantidadDinero = cantidadDinero; } El método agregarCliente permite inicializar el atributo miCliente. publicvoid agregarCliente(Cliente miCliente) { this.miCliente=miCliente; }
  • 128.
    El método toString()devuelve un String con la representación en String de la cuenta. public String toString() {String cuenta="Corriente "; if(tipo==0) cuenta="Ahorro "; return "Número "+numero+ " Tipo: "+cuenta+" Dinero "+cantidadDinero; } Finalmente, en la clase Banco se tienen entre otros los siguientes métodos. El método agregarCuenta lo primero que hace es verificar que la cuenta que se va a crear no exista. Si es así, entonces se crear una nueva cuenta y se le agrega el cliente que le usuario indicó. Antes de poder agregar esta cuenta, se debe comprobar a través de buscarCantidadCuentasTipo que el usuario no exceda el tope de cuentas por tipo, que es de 3. publicboolean agregarCuenta(String numero, int tipo, double cantidadDinero, ArrayList <Integer> posClientes) { if(buscarCuenta(numero)==-1) { Cuenta miC= new Cuenta(numero, tipo, cantidadDinero); for(int i=0; i<posClientes.size(); i++) { Cliente cliente=misClientes.get(posClientes.get(i)); if(buscarCantidadCuentasTipo(tipo, cliente.getIdentificacion())<3) {miC.agregarCliente(cliente); }
  • 129.
    } misCuentas.add(miC); returntrue; } returnfalse; } El método buscarCantidadCuentasTiporecibe el codigo de la persona y el tipo de cuenta que se pretende crear. La idea es recorrer el ArrayList de cuentas e ir preguntado por cada cuenta si el propietario es el mismo cliente y si el tipo de la cuenta coincide con el tipo de la cuenta que se desea crear, si es así se contabiliza. publicint buscarCantidadCuentasTipo(int tipoCuenta ,String codPersona) { int contador=0; for(int i=0; i<misCuentas.size(); i++) { if(misCuentas.get(i).getMiCliente().getNombre().equals misCuentas.get(i).getTipo()==tipoCuenta) { contador++; } } return contador; } El método buscarCuentasClienteTipo recorre el ArrayList comparando el tipo de la cuenta con el tipo buscado y el codigo del propietario de la cuenta con el código buscado, si coinciden se agrega a uno de los ArrayList creados. Hay dos ArrayList: en cuentasClienteTipo se agregan las cuentas si la solicitud corresponde a corriente o ahorro, en todasCuentasCliente se agregan todas las cuentas, pues el usuario ha solicitado ver todas las cuentas, sin discriminar entre corriente y ahorro.
  • 130.
    public String[] buscarCuentasClienteTipo(int tipoCuenta,int posPersona) { String codPersona=misClientes.get(posPersona).getIdentificacio ArrayList <Cuenta> cuentasClienteTipo=new ArrayList<Cuenta>(); ArrayList <Cuenta> todasCuentasCliente=new ArrayList<Cuenta>(); for (int i=0; i<misCuentas.size(); i++) { if(misCuentas.get(i).getMiCliente().getIdentificacion( { todasCuentasCliente.add(misCuentas.get(i)); if(misCuentas.get(i).getTipo()==tipoCuenta) { cuentasClienteTipo.add(misCuentas.get(i)); } } } if (tipoCuenta==2) return pasarArrayListAArreglo(todasCuentasCliente); else return pasarArrayListAArreglo(cuentasClienteTipo); } Finalmente el método ordenarCuentas genera el listado de cuentas ordenado por monto, utilizando el método burbuja. public String[] ordenarCuentas() { for(int i=0; i< misCuentas.size(); i++)
  • 131.
    { for(int j=0; j<misCuentas.size()-1; j++) { if(misCuentas.get(j).getCantidadDinero() <misCuentas.get(j+1).getCantidadDinero()) { Cuenta temp=misCuentas.get(j); misCuentas.set(j, misCuentas.get(j+1)); misCuentas.set(j+1, temp); } } } return pasarArrayListAArreglo(misCuentas); }} ARRAY BIDIMENSIONAL 1 Objetivos Al finalizar la unidad el estudiante estará en capacidad de: Utilizar estructuras contenedoras de tamaño fijo en dos dimensiones para resolver problemas en los cuales es necesario almacenar una secuencia de elementos Utilizar ciclos para poder manipular las estructuras contenedoras fijas de dos dimensiones Conocer y aplicar los patrones de algoritmo para recorrido de matrices. 2 Motivación Frecuentemente se presentan muchos casos en los cuales se requiere trabajar con estructuras contenedoras de dos dimensiones. Por ejemplo, un cine en el cual hay una serie de puestos distribuidos en filas y columnas. En este nivel se explicará cómo se declaran y crean este tipo de estructuras contenedoras, a las cuales se les conoce como matrices.
  • 132.
    3 Caso deestudio N.1 El cine (Código Fuente: unidadIIICaso01Cine) Se desea crear una Aplicación para un Cine en cual hay 180 puestos distribuidos en 12 filas y 15 columnas. Cada puesto tiene un número (formado por una letra y un número entre 0 y 14) y un estado. El puesto o no estar ocupado por una persona. Una persona tiene una cédula. La numeración de los puestos inicia en A0… A14, continúa en B0… B14…. y así sucesivamente hasta llegar a L0…. L14. Se requiere que se pueda ubicar una persona en el cine informando para ello su cédula, tipo de preferencia, cantidad de sillas que desea y si requiere o no que éstas sean consecutivas. El usuario podrá indicar la fila de su preferencia para realizar su reservación. También se necesita eliminar una reservación indicando la posición del puesto, calcular el total recaudado en categoría general y calcular el total recaudado en categoría preferencial.
  • 134.
    columna La reservación hasido eliminada Calcular el total recaudado por tipo de preferencia Se debe calcular el total recaudado por tipo de preferencia El tipo de preferencia El total recaudado 3.2 Comprensión del mundo del problema Se pueden identificar diferentes entidades, a saber:
  • 136.
    3.3 Diseño yconstrucción de la solución del problema Para resolver este caso de estudio se requiere la incorporación del concepto de arreglos dimensionales o matrices. Los Array Bidimensionales también se conocen como tablas o matrices. Es de anotar, que Java no soporta los arreglos multidimensionales de forma directa. No obstante, permite trabajar con un arreglo de arreglos. La propiedad length permite obtener el tamaño del arreglo. Para obtener el número de filas se utiliza matriz.length y para obtener el número de columnas se utiliza matriz[0] length. Toda matriz debe ser declarada y se le debe reservar memoria. La sintaxis utilizada para la declaración es la siguiente: <TipoDato> nombreMatriz[][]; ó <TipoDato> [][] nombreMatriz; Para reservarle memoria se usa el operador new. Ejemplo: nombreMatriz=new <TipoDato>[cantidadDeFilas] [cantidadDeColumnas]; La declaración y reservada de memoria también se puede hacer en una sola línea. int matriz[][]=new int[4][5]; Puesto misPuestos[][]= new Puesto[12][15]; Como puede verse es posible crear arraysen dos dimensiones de objetos, pero hay que tener precaución pues luego de reservarle memoria al arreglo será necesario crear cada uno de los objetos que va a almacenar. Luego de que se reserva memoria, Java inicializa los arreglos dependiendo del tipo de dato, ejemplo si el arreglo es de enteros, se inicializa por defecto con ceros, pero si es de objetos se inicializa con null. También es posible inicializar los arreglos al momento de la declaración: int edad[][]={{3,4,5},{5,6,7}};
  • 137.
    Cada elemento dentrodel array bidimensional tiene una posición dada, la cual está formada por una fila y una columna. Esto quiere decir que para moverse dentro de este tipo de estructuras se requiere de dos índices, normalmente i y j. El primero de ellos se desplaza en las filas, y toma valores entre 0 y matriz length y el segundo, se mueve en las columnas y toma valores entre 0 y matriz[0].length. La siguiente tabla está formada por 4 filas y 4 columnas. Dentro de cada celda se han colocado, en la parte superior los respectivos índices. El primero de ellos corresponde a la fila (i) y el segundo a la columna(j). Ejemplo si se tiene la posicion 0,3 quiere decir que se está ubicado en lafila 0 y en la columna 3. Es importante tener claro que una cosa es la posición y otra lo que se encuentra almacenado en dicha posición. Por ejemplo, en la posicion 0,3 se encuentra almacenado un 1 En la posicion 1,3 se encuentra almacenado un 70, en la posicion 32 se encuentra almacenado un 4. Columna Fila 00 01 02 03 0 5 6 1 10 11 12 13 8 1 7 70 20 21 22 23 10 30 0 80 30 31 32 33 2 7 4 8 Observe que: la i toma valores entre 0 y matriz.length-1 la j toma valores entre 0 y matriz[0] length-1 Una importante estrategia que permite el desarrollo de la lógica sobre las matrices
  • 138.
    consiste en ponerlos índices sobre cada uno de los elementos que la matriz puede contener, pues gracias a ello es posible identificar aspectos importantes que permitan realizargeneralizaciones . Por ejemplo: Se desea sumar todos los elementos de la diagonal: En la diagonal, la i y la j son iguales: 00, 11, 22, 33… Se desea sumar los los elementos de la primera y última columna: En este caso, j==0 || j== matriz[0].length-1 Se desea obtener los elementos de la diagonal secundaria: Observe que las posiciones correspondientes a esta diagonal son 03, 12, 21 y 30. En este caso la sumatoria del valor en i con el valor de j siempre da 3. Es decir, (i+j)== matriz[0] length-1 El caso de estudio del Cine requiere la creación de la clase Persona, que cuenta con un solo atributo, además del correspondiente método constructor y get. publicclass Persona { //---------------------------------------------------- ------------// Atributos //---------------------------------------------------- ------------/** * Es la cedula de la persona */ private String cedula; } En la clase Puesto se tienen, además de los métodos set y get de los atributos numero, tipo, estado, los siguientes métodos: - El método constructor que permite inicializar los atributos de la clase. public Puesto(String numero, int tipo, int estado) {
  • 139.
    super(); this.numero = numero; this.tipo= tipo; this.estado = estado; } - En la clase Puesto se crearon dos métodos setMiPersona, apoyándose en la sobrecarga de métodos. El primero de ellos, permite fijar la persona en null y el estado en cero, es decir cumple la función de eliminar la persona. El segundo permite inicializar la persona con la información que el usuario ingresa. publicvoid setMiPersona() { this.miPersona = null; estado=0; } publicvoid setMiPersona(String cedula) { this.miPersona = new Persona(cedula); estado=1; } Por último, se presentan algunos de los métodos de la clase Cine. En el constructor de Cine se le reserva memoria a la matriz y luego a cada uno de los puestos. Amedida que se crea un puesto se le asigna el número, la categoría y el estado. El número se calcula apoyado en la variable char letra. public Cine() { misPuestos=new Puesto[12][15]; char letra='A'; for(int i=0; i<misPuestos.length; i++) { for(int j=0; j<misPuestos[0].length; j++)
  • 140.
    { if(i<9) misPuestos[i][j]=new Puesto(letra+""+j,Puesto.GENERAL,0); else misPuestos[i][j]=new Puesto(letra+""+j,Puesto.PREFERENCIAL,0); } letra++; } } El métodoliberar recibe la fila y la columna donde está ubicado el puesto que se desea liberar. Si el puesto no está ocupado se genera una excepción. publicboolean liberar(int i, int j) throws Exception { if(misPuestos[i][j].getEstado()==1) { misPuestos[i][j].setMiPersona(); returntrue; } else thrownew Exception("El puesto no tiene personas y por ello no se puede liberar"); } El método obtenerDineroPorTipo, tiene como parámetro el tipo deseado y se encarga de calcular el total recaudado, para ello se apoya en el método contarPorTipo. publicdouble obtenerDineroPorTipo(int tipo) { double res=0; if(tipo==0)
  • 141.
    res=contarPorTipo(tipo)*Puesto.PRECIO_GENERAL; else res= contarPorTipo(tipo)*Puesto.PRECIO_PREFERENCIA; return res; } publicint contarPorTipo(int tipo) { int contador=0; for(int i=0; i<misPuestos.length; i++) { for(int j=0; j<misPuestos[0].length; j++) { if(misPuestos[i] [j].getMiPersona()!=null&&misPuestos[i][j].getTipo( )==tipo) {contador++;} }} return contador; } 3.4 Patrones para recorrido sobre matrices Los patrones para recorrer estructuras contenedoras de dos dimensiones son los siguientes: a) Patrón de recorrido Total Mediante este patrón se tiene acceso a cada una de las posiciones del arreglo bidimensional. Se requieren dos for, el primero de ellos maneja la fila y el segundo de ellos la columna. Un ejemplo de este tipo de patrón es el siguiente: publicint contarPorTipo(int tipo) { int contador=0; for(int i=0; i<misPuestos.length; i++) { for(int j=0; j<misPuestos[0].length; j++) { if(misPuestos[i]
  • 142.
    [j].getMiPersona()!=null&&misPuestos[i] [j].getTipo()==tipo) {contador++;} }} return contador;} b) Patrón de Recorrido Parcial Se recorre el arreglo bidimensional y por cada elemento se verifica si ya se cumplió la condición de finalización del ciclo, es decir, si el problema ya fue resulto. Por ejemplo; public int buscarPersona(String codigo) { for(int i=0; i<misPuestos.length; i++) { for(int j=0; j<misPuestos[0].length; j++) { if(misPuestos[i] [j].getMiPersona()!=null&&misPuestos[i] [j].getMiPersona().getCedu la().equals(codigo)) {return i;} }} return -1; } 4 Caso de estudio N.2 El Bingo (Código Fuente: unidadIIICaso02Bingo) Se requiere de una aplicación para jugar Bingo. La aplicación debe generar tantos tableros aleatorios como clientes deseen jugar. Cada tablero está formado por 5 filas y 5 columnas. Los números correspondientes a la columna B pueden tomar valores entre 0 y 9, los valores válidos para la columna I son entre 10 y 19, para la N entre 20 y 29, para la G entre 30 y 39 y para la última columna entre 40 y 49. Cada tablero debe ser único.
  • 145.
    Descripción Entrada Generar untablero Cada vez que llega un cliente a comprar un tablero debe informar sus datos personales para que el sistema lo genere. Se debe verificar que el tablero sea válido, es decir, que ese tablero no exista ya. 1) teléfono, 2)nombre, 3) cedula Un nuevo tablero ha sido generado Sacar una balota. El sistema aleatoriamente deberá seleccionar un número entre 0 y 49. Ninguna Un número entre 0 y 49 Actualizar todos los tableros luego de que se selecciona una balota Para cada tablero se debe verificar si la balota seleccionada por el sistema está incluida dentro de dicho tablero. En tal caso, esto se debe registrar. 1)El número de la balota seleccionada Requisito funcional 4 Requisito funcional 5 Salida Nombre Descripción Entrada Salida Nombre Descripción Entrada Salida Los tableros han sido actualizados Listar todos los tableros vendidos Se debe permitir mostrar los listados vendidos Ninguna El listado de tableros vendidos
  • 146.
    Verificar si hayganador Luego de que se seleccione una balota el sistema debe verificar si algún tablero se ha llenado completamente. Puede ocurrir que se completen varios tableros Ninguna El listado de tableros ganadores 3.6 Comprensión del mundo del problema Se pueden identificar diferentes entidades, a saber Bingo, Tablero, Posición y Propietario. 3.7 Diseño y construcción de la solución del problema Para resolver este caso de estudio se iniciará con la clase Posición. Una posición está formada por un número, una letra y un estado (seleccionado o no seleccionado). publicclass Posicion { //---------------------------------------------------- ------------// Atributos //---------------------------------------------------- ------------/** * Es el número de la posicion */ privateint numero; /** * Seleccionado es cero si el sistema no ha sacado este número sino es 1. */ privateint seleccionado; /** * Es una letra de la palabra Bingo */ privatechar letra; }
  • 147.
    Adicionalmente a losmétodos get y set para cada uno de los atributos se tienen el siguiente método: public Posicion(int numero, int seleccionado) { this.numero = numero; this.seleccionado = seleccionado; } En la clase Tablero, se tiene entre otros métodos los siguientes: En el constructor de Tablero se le reserva memoria a cada una de las posiciones del tablero, pero no se les asigna número. public Tablero(int numero) { matriz=new Posicion[Bingo.CANTIDAD_FILAS] [Bingo.CANTIDAD_FILAS]; for(int i=0; i<Bingo.CANTIDAD_FILAS;i++) { for(int j=0; j<Bingo.CANTIDAD_FILAS;j++) { matriz[i][j]=new Posicion(0,0); } } this.numero=numero; } El número luego se modifica con base en el número seleccionado aleatoriamente por el sistema para crear el tablero, para ello se utiliza el método modificarNumero. Cuando se piensa modificar un número se debe verificar que en esa columna ya no exista.
  • 148.
    publicboolean modificarNumero(int colu,int fil, int numero) { for(int i=0; i<Bingo.CANTIDAD_FILAS; i++) { if(matriz[i][colu].getNumero()==numero) { returnfalse; } } matriz[fil][colu].setNumero(numero); returntrue; } Luego de que el juego ha iniciado y el sistema selecciona la balota, se debe verificar si el número de la balota está presente en el tablero. Si es así, se debe actualizar el tablero, poniendo a la variable seleccionado de la posición donde se encuentra en uno. publicvoid actualizarTablero(int aleatorio) { for(int i=0; i<matriz.length; i++) { for (int j=0; j<matriz.length; j++) { if(matriz[i][j].getNumero()==aleatorio) { matriz[i][j].setSeleccionado(1); } } } } Finalmente, algunos de los métodos de la clase Bingo se presentan a continuación: El métodocrearTablero generaun nuevo tablero con números aleatorios y por último verifica que el creado no haya sido generado con anterioridad. public Tablero crearTablero(String telefono, String nombre, String cedula) { boolean centinela=true;
  • 149.
    while(centinela) { int inicio=0, finaliza=9,aleatorio; boolean res=false; Tablero miTablero=new Tablero(misTableros.size()+1); for (int j=0; j<CANTIDAD_FILAS;j++) { inicio=j*10; finaliza=inicio+9; for (int i=0; i<CANTIDAD_FILAS; i++) { res=false; while(res==false) { do { aleatorio= (int)(Math.random()*finaliza); }while(! (aleatorio>=inicio&&aleatorio<=finaliza)); res=miTablero.modificarNumero(j,i, aleatorio); } } } if(verificarTableroValido(miTablero)==true) { miTablero.setMiPropietario(telefono, nombre, cedula); misTableros.add(miTablero); centinela=false; return miTablero; } } returnnull;
  • 150.
    } El método generarPosicion,es el encargado de seleccionar una nueva balota con número entre 0 y 49. Las balotas que ya se han seleccionado se van almacenando para evitar repeticiones. public Posicion generarPosicion() { if(hayGanador()==null) { char letra[]={'B','I','N','G','O'}; int rango=0, aleatorio=0; boolean centinela=false; while(centinela==false) { aleatorio= (int)(Math.random()*49); rango=0; if (aleatorio>=10&&rango<=19) rango=1; if(aleatorio>=20&&rango<=29) rango=2; if(aleatorio>=30&&rango<=39) rango=3; if(aleatorio>=40&&rango<=49) rango=4; if(aleatorio!=0&&!posicionesGanadoras.contains(aleator { posicionesGanadoras.add(aleatorio); actualizarTodosLosTableros(aleatorio); centinela=true; }
  • 151.
    } Posicion p=new Posicion(aleatorio,0); p.setLetra(letra[rango]); returnp; } returnnull; } El método hayGanador() se encarga de verificar si alguien ya hizo bingo, es decir ha cubierto completamente los 25 números de su tablero. public ArrayList<Integer> hayGanador() { ArrayList<Integer> ganadores=new ArrayList<Integer>(); for(int i=0; i<misTableros.size(); i++) { if(misTableros.get(i).contarAciertos()==25) { ganadores.add(i+1); } } if(ganadores.size()>0) return ganadores; else returnnull; } El método actualizarTodosLosTableros se encarga de actualizar los tableros con base en la balota seleccionada aleatoriamente por el sistema. La actualización consiste en registrar, en el caso de tableros que tienen el número de la balota un acierto. publicint actualizarTodosLosTableros(int aleatorio) { for(int i=0; i<misTableros.size(); i++) {
  • 154.
    ACTIVIDAD Complete la tablasiguiente con los requisitos funcionales que hacen falta Requisito funcional 1 Nombre Descripción Entrada Requisito funcional 2 Requisito funcional 3 Requisito funcional 4 Requisito funcional 5 Salida Nombre Descripción Entrada Salida Nombre Descripción Entrada Salida Nombre Descripción Entrada Salida Nombre Descripción Entrada Salida Realizar una jugada Uno de los jugadores selecciona una posición del tablero 1) valor en la fila,2) valor en la columna, 3) nickName de quien realiza la jugada Ninguna Verificar si hay ganador del triqui Luego de que se ha realizado una jugada se deberá verificar si se hizo triqui. Ninguna El nombre del jugador que hizo triqui, si lo hay.
  • 155.
    4.2 Comprensión delmundo del problema Se pueden identificar diferentes entidades, a saber: Triqui, Posicion y Jugador
  • 157.
    * Es elvalor en la fila */ privateint i; /** * Es el valor en la columna */ privateint j; /** * Es el jugador que dio clic en esa posicion */ private Jugador miJugador; } El constructor de la clase recibe respectivamente la columna y la fila que conforman la posición. public Posicion(int i, int j) { super(); this.i = i; this.j = j; verificarInvariante(); } El método setMiJugador permite fijar el jugador en la posicion publicvoid setMiJugador(Jugador miJugador) { this.miJugador = miJugador; } Por otra parte, la clase Jugador tiene entre otros métodos los siguientes: El constructor que permite inicializar el nombre y Nick del jugador public Jugador(String nombre, String nick) { super();
  • 158.
    this.nombre = nombre; this.nick= nick; } El método equals, que verifica si dos objetos son iguales. publicboolean equals(Object objeto) { if ( this == objeto ) returntrue; if ( objeto == null ) returnfalse; if ( this.getClass() != objeto.getClass() ) returnfalse; if ( this.nombre== this.getClass().cast(objeto).nombre &&this.nick== this.getClass().cast(objeto).nick ) returntrue; if ( this.nombre != null&&this.nick!=null) if( this.nombre.equals( this.getClass().cast(objeto).nombre )&&this.nick.equals( this.getClass().cast(objeto).nick )) returntrue; if ( this.nombre != null&&this.nick==null) if( this.nombre.equals( this.getClass().cast(objeto).nombre )) returntrue; if (this.nick==null) if( this.nick.equals( this.getClass().cast(objeto).nick)) returntrue; returnfalse ; } }
  • 159.
    Finalmente, se tienela clase Triqui. Algunos de sus métodos son: El método constructor, en el que se le reserva memoria a la matriz y también a cada uno de las posiciones dentro de la matriz. public Triqui() { misPosiciones=new Posicion[3][3]; for (int i=0; i<misPosiciones.length; i++) { for(int j=0; j<misPosiciones[0].length; j++) { misPosiciones[i][j]=new Posicion(); misPosiciones[i][j].setI(i); misPosiciones[i][j].setJ(j); } } } El método jugar recibe la fila y la columna de la celda que el usuario seleccionó y también su nickName. El método lo que hace es marcar la posición como seleccionada. Por último, identifica cual es el jugador que debe realizar la próxima jugada. public Jugador jugar(int i, int j, String nickName) { centinela=false; if(misPosiciones[i][j].getMiJugador()==null&& turnoJugador.getNick().equals(nickName)) { misPosiciones[i] [j].setMiJugador(buscarJugador(nickName)); turnoJugador=buscarJugadorContrario(nickName); centinela=true; return verificarTriqui(); }
  • 160.
    returnnull; } Finalmente, el métodoverificarTriqui() verifica si se realizó triqui en la diagonal principal, en la diagonal secundaria, en la columnas o en las filas. public Jugador verificarTriqui() { int i; //Triqui en la diagonal principal if( misPosiciones[0][ 0 ].getMiJugador()!=null&&misPosiciones[2] [2].getMiJugador()!=null&&misPosiciones[1 ] [1].getMiJugador()!=null&& misPosiciones[ 0 ][ 0].getMiJugador().getNick().equals( misPosiciones[2][2].getMiJugador().getNick()) && misPosiciones[0] [0].getMiJugador().getNick().equals(misPosiciones[1] [1].getMiJuga dor().getNick())) { return misPosiciones[ 0 ][ 0 ].getMiJugador(); } //Triqui en la otra diagonal if( misPosiciones[0][ 2 ].getMiJugador()!=null&&misPosiciones[1] [1].getMiJugador()!=null &&misPosiciones[ 2 ][ 0 ].getMiJugador()!=null&& misPosiciones[ 0 ][ 2 ].getMiJugador().getNick().equals( misPosiciones[ 1 ][ 1 ].getMiJugador().getNick()) && misPosiciones[ 0 ][ 2 ].getMiJugador().getNick().equals( misPosiciones[ 2 ]
  • 161.
    [0 ].getMiJugador().getNick())) { return misPosiciones[0 ][ 0 ].getMiJugador(); } for( i = 0 ; i < 3 ; i++ ) { if ( misPosiciones[i][ 0 ].getMiJugador()!=null&&misPosiciones[i] [1].getMiJugador()!=null &&misPosiciones[ i ][ 2 ].getMiJugador()!=null&& misPosiciones[ i ][ 0 ].getMiJugador().getNick().equals( misPosiciones[ i ][ 2 ].getMiJugador().getNick()) && misPosiciones[ i ][ 0 ].getMiJugador().getNick().equals( misPosiciones[ i ][ 1 ].getMiJugador().getNick())) { return misPosiciones[ i ][ 0 ].getMiJugador(); } } for( i = 0 ; i < 3 ; i++ ) { if( misPosiciones[0][i ].getMiJugador()!=null&&misPosiciones[1] [i].getMiJugador()!=null &&misPosiciones[ 2 ][ i].getMiJugador()!=null&&misPosiciones[0] [i].getMiJugador().getNick().equals(misP osiciones[ 1 ][ i ].getMiJugador().getNick()) && misPosiciones[ 1 ][ i ].getMiJugador().getNick(). equals(misPosiciones[2][i].getMiJugador().getNick())) {
  • 162.
    return misPosiciones[ 0][ i ].getMiJugador(); } } returnnull; } 5 Hoja de Trabajo N.2 Concéntrese (Código Fuente: unidadIIIHoja02JuegoParejas) Se desea crear una aplicación para el juego de parejas. El juego consiste en seleccionar consecutivamenente dos casillas sobre un tablero, buscando parejas de fotos.
  • 166.
    en el tablerocon su respectiva pareja de forma aleatoria. Ninguna Un nuevo tablero ha sido creado Realizar jugada Se debe seleccionar una casilla en el tablero. Cada vez que se hayan seleccionado números pares de casillas se deberá verificar si el jugador encontró una pareja o no. 1) fila 2)columna Si se halló una pareja se devuelven las dos últimas jugadas realizadas, sino no se devuelve null Calcular el puntaje total Luego de que el usuario encuentra una pareja, dependiendo de los iconos hallados se acumula el puntaje obtenido Ninguna El puntaje obtenido 5.2 Comprensión del mundo del problema Se pueden identificar diferentes entidades, a saber: Juego, Posicion e Icono.
  • 168.
    mismo icono. publicclass Icono{ //---------------------------------------------------- ------------//Atributos //---------------------------------------------------- ------------/** * Es el nombre del icono */ private String nombre; /** * Es el estado del icono */ privateboolean estado; /** * Es el puntaje que da este icono */ privateint puntaje; } En esta clase además del método constructor, que inicializa los atributos de la clase se cuenta con los métodos get y set para los atributos. public Icono(String nombre, boolean estado, int puntaje) { this.nombre = nombre; this.estado = estado; this.puntaje=puntaje; verificarInvariante(); } La siguiente clase es la clase Posicion, cuyos atributos se muestran a
  • 169.
    continuación. publicclass Posicion { //---------------------------------------------------- ------------//Atributos //---------------------------------------------------- ------------/** * Es el valor en la fila */ privateint i; /** * Es el valor en la columna */ privateint j; /** * Es el estado del icono */ privateint estado; /** * Es la ruta de la foto del icono */ private Icono foto; } Esta clase tiene,entre otros métodos, un constructor que permite inicializar los atributos i, j y estado. Además tiene el método setFoto, el cual permite iniciar el atributo foto. public Posicion(int i, int j, int estado) { this.i = i; this.j = j; this.estado = estado;
  • 170.
    verificarInvariante(); } publicvoid setFoto(Icono miIcono){ this.foto = miIcono; } Finalmente, la clase Juego tiene un método constructor en el cual se le reserva memoria al tablero apoyándonse en el método inicializarFotos y crearMatriz. public Juego() { misFotos=new ArrayList<Icono>(); misPosiciones=new Posicion[TAMANIO][TAMANIO]; dosUltimasJugadas=new ArrayList<Posicion>(); inicializarFotos(); crearMatriz(); verificarInvariante(); } publicvoid inicializarFotos() { //Se agregan al ArrayList las diferentes fotos misFotos.add(new Icono("fotos/baby1.jpg",false,2)); misFotos.add(new Icono("fotos/cupeiro1.jpg",false,-5)); misFotos.add(new Icono("fotos/flor1.jpg",false,3)); misFotos.add(new Icono("fotos/hongo1.jpg",false,3)); misFotos.add(new Icono("fotos/honguito1.jpg",false,4)); misFotos.add(new Icono("fotos/images1.jpg",false,-8)); misFotos.add(new Icono("fotos/mario1.jpg",false,5)); misFotos.add(new Icono("fotos/orejitas1.jpg",false,3));
  • 171.
    misFotos.add(new Icono("fotos/pez1.jpg",false,2)); misFotos.add(new Icono("fotos/princess1.jpg",false,4)); misFotos.add(new Icono("fotos/rosalina1.jpg",false,2)); misFotos.add(new Icono("fotos/luigi1.jpg",false,4));} En el método crearMatriz se crean cada una de las posiciones del tablero y a cada celda se le asigna un icono. Siempre que se ponga un icono en una posicion se debe poner en otra celda ese mismo icono, pues se requiere formar parejas. La selección de los iconos debe ser aleatoria.La única posición a la que no se le pone ícono es la posición [2][2]. publicvoid crearMatriz() { do{ int x=0, y=0, icono=0; boolean centinela=false; ArrayList<Integer> posicionesIconos=new ArrayList<Integer>(); int contador=0; //Se crean todas las posiciones for(int i=0; i<misPosiciones.length; i++) { for(int j=0; j<misPosiciones[0].length; j++) { misPosiciones[i][j]=new Posicion(i,j,0) ; } } //Aqui se asignan los iconos }
  • 173.
    permanente. Construir un programacompleto, siguiendo todas las etapas requeridas para resolver un problema. Construir pruebas unitarias que permitan probar el correcto funcionamiento del software 2 Motivación En la vida real se presentan muchos casos en los cuales se requiere manejar el estado inicial de un problema y que esta información sea leida a través de un archivo Para poder dar respuesta a esta necesidad en este nivel se tratará el tema de archivos Properties y serialización. 3 Caso de estudio N.1La Empresa (Código Fuente: unidadIVCaso01Empresa) Se desea crear una aplicación para manejar la información de una empresa. En la empresa hay empleados. Cada uno tiene un codigo, un nombre, una fecha de nacimiento y un salario. La aplicación debe permitir: - Agregar un nuevo empleado - Leer la información de la empresa de un archivo de entrada. - Generar un archivo con la información de la empresa - Obtener la edad promedio de los empleados - Mostrar la información de los empleados ordenada por salario utilizando el método de inserción - Mostrar la información de los empleados ordenada por edad utilizando el método de selección. - Buscar empleado que tenga el salario especificado por el usuario
  • 175.
    Descripción Entrada Salida Requisito funcional4 Requisito funcional 5 Nombre Descripción Entrada Salida Nombre Descripción Requisito funcional 6 Entrada Salida Nombre Descripción Requisito funcional 7 Entrada Salida Nombre Descripción Entrada Salida Agregar un nuevo empleado Se requiere añadir un nuevo empleado 1)id, 2)nombre, 3)dia, 4) mes, 5)anio, 6)salario Un nuevo empleado ha sido agregado a la empresa Leer la información de la empresa de un archivo de entrada. La información de la empresa se lee desde el archivo y constituye el estado inicial de la empresa Nombre del archivo con la información de la empresa Se inicializó el estado de la empresa, a partir de lo que se encontraba almacenado en el archivo.
  • 176.
    Generar un archivocon la información de la empresa Se requiere generar un archivo con la información de la empresa Nombre del archivo de la salida Un nuevo archivo ha sido generado con la información de la empresa Obtener la edad promedio de los empleados Se requiere obtener la edad promedio de los empleados Ninguna La edad promedio Mostrar la información de los empleados ordenada por salario Se requiere generar un listado con la información de los empleados ordenada por salario. Para resolver este requisito se hará uso del método de inserción. Ninguna El listado ordenado por salario Mostrar la información de los empleados ordenada por edad Se requiere generar un listado con la información de los empleados ordenada por edad. Para resolver este requisito se hará uso del método de selección. Ninguna El listado ordenado por edad Buscar empleado que tenga el salario especificado por el usuario Se requiere buscar el primer empleado que tenga el salario especificado por el usuario, utilizando el método de búsqueda binaria. El salario buscado Un empleado que tenga el salario buscado 3.2 Comprensión del mundo del problema Se pueden identificar diferentes entidades, a saber: Empresa, Empleado y Fecha.
  • 178.
    3.3 Diseño yconstrucción de la solución del problema Dado que la clase Empresa contiene la información de los empleados, esta clase es la responsable de: - Dar la información de los empleados - Dar la edad promedio de los empleados - Dar el listado de los empleados ordenada por salario y por edad - Dar el empleado que tenga el salario especificado por el usuario - Generar un archivo con la información de la empresa. Esta clase también tiene las siguientes responsabilidades referentes a la modificación de su estado: - Registrar un nuevo empleado - Leer desde un archivo la información de la empresa y guardarla en el ArrayList de empleados. Con base en las anteriores responsabilidades identificadas se definirán los métodos de la clase Empresa. 3.4 Archivos Un archivo es una colección de información almacenada como una unidad en algún dispositivo de almacenamiento secundario. Entre las características más generales de los archivos se tienen las siguientes: * Nombre y extensión: Todo archivo debe tener nombre y una extensión. La extensión indica su formato. * Datos sobre el archivo: por cada archivo se almacena datos relacionados,tales como: tamaño, fecha de creación, modificación y de último acceso, * Ubicación, ruta o path: Todo archivo está ubicado dentro de una carpeta o subcarpeta. El path de un archivo suele iniciar con la unidad lógica que lo contiene, seguida de las sucesivascarpetas hasta llegar al directorio que lo almacena, por ejemplo:
  • 179.
    "C:eclipsepluginsedu buffalo.cse.green.relationship.association.source_3.5.0". Desde javaes posible cargar la información de los archivos almacenados en disco. Los archivos que se manejarán en los siguientes casos de estudio tienen un formato especial, que recibe el nombre de properties. Un archivo con extensión properties es utilizado principalmente para almacenar parámetros de configuración de una aplicación. Tambiénse puede utilizar para almacenarcadenasparala internacionalizaciónylocalización. Cadaparámetrosealmacenacomo unpareja de Strings, el primero almacenar elnombredelparámetro(llamado clave), yel segundo, el valor. Acontinuación se muestra el formato del archivo que se utilizará: Nombre Valor de la propiedad empleados properties empresa.empleados=5 empresa.empleado0=1234,Juan Perez,23-02-1987,324345 empresa.empleado1=65643,Maria Perez,23-02-1987,4545 empresa.empleado2=443,Rocio Rosero,23-02-1987,3332 empresa.empleado3=12439,Liliana Rodriguez,23-02- 1987,435 empresa.empleado4=5643,Diana Lopez, 23-02- 1987,3232 Cada línea dentro del archivo corresponde a una propiedad. Para poder aplicar el concepto de properties al caso de estudio de la empresa en la ventanaPrinicipal se requiere agregar el siguiente método: publicvoid cargarEmpleados( ) throws Exception { JFileChooser fc = new JFileChooser( "./data" ); fc.setDialogTitle( "Abrir archivo de empleados" ); int resultado = fc.showOpenDialog( this ); if( resultado == JFileChooser.APPROVE_OPTION ) {
  • 181.
    inicializarEmpleados(datos); } El método cargarInfoEmpresase encarga de cargar la información de los empleados de la empresa en un objeto de tipo Properties, recibe como parámetro el archivo que contiene la descripción de los empleados de la empresa y devuelve un objeto de la clase Properties con la información del archivo. private Properties cargarInfoEmpresa( File arch ) throws Exception { Properties datos = new Properties( ); FileInputStream in = new FileInputStream( arch ); try { datos.load( in ); in.close( ); } catch( Exception e ) { thrownew Exception( "Formato inválido" ); } return datos; } El método inicializarEmpleados tiene como función inicializar el arreglo de empleados con la información que recibe en el parámetro de entrada. Tiene como parámetro una un objeto de tipo Properties, al cual se le llamó datos. En datos está la información cargada del archivo para inicializar la empresa. privatevoid inicializarEmpleados( Properties datos ) throws Exception { //A medida que se cargan los empleados se llenará un archivo log //con el reporte de los problemas ocurridos.
  • 182.
    FileWriter salida=null; BufferedWriter salida1=null; salida=newFileWriter("./data/logCarga.txt"); salida1=new BufferedWriter(salida); copiarLineaEnArchivoLog("En el proceso se generaron los siguientes errores: ", salida1); copiarLineaEnArchivoLog("n", salida1); //Se inicia el proceso de carga del archivo String strNumeroEmpleados = datos.getProperty( "empresa.empleados" ); int maxEmpleados = Integer.parseInt( strNumeroEmpleados ); int idConfirmacion=0; // Lee el nombre de cada empleados de la respectiva propiedad y crea el objeto que lo representa for( int i = 0; i < maxEmpleados; i++ ) { String id="",nombre=""; int dia=0, mes=0, anio=0; double salario=0; String infoEmpleado = datos.getProperty( "empresa.empleado" + i ); StringTokenizer st2=new StringTokenizer(infoEmpleado,"-,"); for (int j=0; st2.hasMoreTokens(); j++) { String elemento=st2.nextToken().trim(); if(j==0) id=(elemento); else if(j==1) nombre=(elemento); else if(j==2)
  • 183.
    dia=Integer. parseInt(elemento); else if(j==3)mes=Integer.parseInt(elemento); else if(j==4) anio=Integer.parseInt(elemento); else salario=Double.parseDouble(elemento); } idConfirmacion=Integer.parseInt(id); try { agregarEmpleado(id, nombre, dia, mes, anio, salario) ; } catch(Exception e) { copiarLineaEnArchivoLog("Id "+id+" Nombre "+nombre+" Fecha "+dia+"/"+mes+"/"+anio+" Salario: "+salario, salida1); } } salida1.close(); } copiarLineaEnArchivoLog se encarga de registrar los errors ocurridos durante el proceso de carga. publicvoid copiarLineaEnArchivoLog(String linea, BufferedWriter salida1)throws Exception { salida1.write("n"); salida1.write(linea); salida1.write("n"); }
  • 184.
    El método generarPropertiesrecorre el ArrayList de empleados y va tomando cada empleado para poder agregar una nueva línea al archivo. publicvoid generarProperties(String nombreArch) throws Exception { FileWriter salida=null; BufferedWriter salida2=null; salida=new FileWriter(nombreArch); salida2=new BufferedWriter(salida); copiarLineaEnArchivoLog("empresa.empleados="+misEmplead salida2); for(int i=0; i<misEmpleados.size(); i++) { String id=misEmpleados.get(i).getId(); String nombre=misEmpleados.get(i).getNombre(); String fecha=misEmpleados.get(i).getMiFechaNacimiento().getDia "+misEmpleados.get(i).getMiFechaNacimiento().getAnio() double salario=misEmpleados.get(i).getSalario(); String total=id+","+nombre+","+fecha+","+salario; System.out.println(total); salida2.write("n"); salida2.write("empresa.empleado"+i+"="+total); salida2.write("n"); } salida2.close(); } 3.5 Métodos de ordenamiento y búsqueda El método de Inserción directa se basa en tomar uno por uno los elementos de un arreglo y recorrerlo hacia su posición con respecto a los anteriormente ordenados. Así empieza con el segundo elemento y lo ordena con respecto al primero. Luego
  • 185.
    sigue con eltercero y lo coloca en su posición ordenada con respecto a los dos anteriores, así sucesivamente hasta recorrer todas las posiciones del arreglo. public String[] ordenarPorInsercionSalario() { String array[]= new String[misEmpleados.size()]; Empleado temp; int i,j; for (i=0; i<misEmpleados.size(); i++) { temp = misEmpleados.get(i); for (j=i; j>0;j--) { if ( misEmpleados.get(j-1).getSalario()<= temp.getSalario()) break; misEmpleados.set(j,misEmpleados.get(j-1)); } misEmpleados.set(j,temp); } for(i=0; i<misEmpleados.size(); i++) { array[i]=misEmpleados.get(i).getId()+" "+misEmpleados.get(i).getNombre()+ " Edad: "+misEmpleados.get(i).calcularEdad()+ " Salario: "+misEmpleados.get(i).getSalario(); } return array; } ACTIVIDAD Básese en este código para llenar la siguiente tabla y al final escriba un
  • 186.
    comentario en tornoa cómo funciona el algoritmo. Otro método muy conocido es el de Selección, el cual consiste en encontrar el menor de todos los elementos del arreglo e intercambiarlo con el que está en la primera posición. Luego el segundo más pequeño, y así sucesivamente hasta ordenar todo el arreglo public String [] ordenarEdadPorSeleccion() { String array[]= new String[misEmpleados.size()]; Empleado temp; int i,j; for (i=0; i<misEmpleados.size()-1; i++) { for (j=i+1; j<misEmpleados.size();j++) { if ( misEmpleados.get(i).calcularEdad()> misEmpleados.get(j).calcularEdad()) {temp = misEmpleados.get(i); misEmpleados.set(i,misEmpleados.get(j)); misEmpleados.set(j,temp); } } } for(i=0; i<misEmpleados.size(); i++) { array[i]=misEmpleados.get(i).getId()+" "+misEmpleados.get(i).getNombre()+ " Edad: "+misEmpleados.get(i).calcularEdad()+ " Salario: "+misEmpleados.get(i).getSalario(); } return array; }
  • 187.
    ACTIVIDAD Básese en ordenarEdadPorSeleccion()para llenar la siguiente tabla y al final escriba un comentario en torno a cómo funciona el algoritmo. Para buscar un elemento dentro de un arreglo se puede utilizar la técnica de búsqueda binaria. Esta técnica requiere que los elementos del arreglo ya se encuentran ordenados. Su funcionamiento es el siguiente: Para iniciar lo que se hace es tomar un elemento central (el encuentra a la mitad del arreglo), y se compara con el elemento buscado. En caso de que el elemento buscado sea menor, se selecciona el intervalo que va desde el elemento central al principio, de lo contrario, se elegirá el intervalo que va desde el elemento central hasta el final del intervalo. Este proceso se repetirá sucesivamente hasta que se llegué a un intervalo indivisible, que indique si el elemento buscado está o no en el vector. El código es el siguiente: public Empleado busquedaBinaria(double salario) { DecimalFormat formatoDecimal; int inicio, fin, medio; inicio=0; fin=misEmpleados.size()-1; ordenarPorInsercionSalario(); formatoDecimal = new DecimalFormat ( "0.0" ); String dato= formatoDecimal.format ( salario); dato=dato.replace(',','.'); salario=Double.parseDouble(dato); while(inicio<=fin) { medio=(inicio+fin)/2; if(salario==misEmpleados.get(medio).getSalario())
  • 188.
    return (misEmpleados.get(medio)); else if(salario>misEmpleados.get(medio).getSalario()) inicio=medio+1; else fin=medio-1; } returnnull; } ACTIVIDAD Apliqueel método de busquedaBinaria para hallar a 5 . 3.5 Pruebas de software Las pruebas o test son utilizadas durante el desarrollo de software para identificar posibles errores y revelar el grado de cumplimiento en relación a las especificaciones que inicialmente se plantearon para el sistema. Las pruebas contribuyen a garantizar la calidad del software construido. En Java se dispone del Framework JUnit para la realización y automatización de pruebas. Para crear una clase de prueba ubíquese en el paquete test, de clic sobre él y seleccione JUnit Test Case.
  • 192.
    tearDownAfterClass: Únicamente puedehaber un método con esta marca. Se ejecuta una sóla vez cuando ha finalizado la ejecución de todas las pruebas. tearDown:Seejecutadespuésde ejecutarse cada prueba. Este método se sustituye por la anotación @After. setUp: Se invoca antes de ejecutarcada prueba. Este método se sustituyó por la anotación @Before También puede usarse otras etiquetas: Test: Se le coloca @Test a la prueba que se va a ejecutar Ignore: El método que tenga esta marca no será ejecutado. Retomando la creación de la clase de prueba para Empleado de clic en Next. Luego seleccione los métodos donde se modifica el estado del objeto: constructores, set o donde se realicen cálculos. Para este caso se seleccionarán los siguientes métodos: Empleado(String, String, int, int, int, double) calcularEdad()
  • 195.
    publicclass EmpleadoTest { //---------------------------------------------------- ------------//Atributos //---------------------------------------------------- ------------ /** * Es la clase donde se realizarán las pruebas */ private Empleado miEmpleado; //---------------------------------------------------- ------------// Métodos //---------------------------------------------------- ------------ /** * Construye un nuevo empleado */ @Before publicvoid setupEscenario1( ) { miEmpleado= new Empleado("123", "luis", 23, 02, 1980, 5000000); } /** * Prueba del constructor */ @Test publicvoid testEmpleado() { assertEquals( "El codigo es inválido.", "123",miEmpleado.getId() ); assertEquals( "El nombre es inválido.", "luis",miEmpleado.getNombre() ); assertEquals( "El dia es inválido.",23,miEmpleado.getMiFechaNacimiento().getDia );
  • 196.
    assertEquals( "El meses inválido.", 02,miEmpleado.getMiFechaNacimiento().getMes() ); assertEquals( "El anio es inválido.", 1980 ,miEmpleado.getMiFechaNacimiento().getAnio() ); assertEquals( "El salario es inválido.", 5000000,miEmpleado.getSalario(),0 ); } @Test publicvoid testCalcularEdad() { assertEquals( "El salario es inválido.", 31,miEmpleado.calcularEdad() ); }} Para ejecutar las pruebas de clic en Run As JUnit Test
  • 198.
    implementados */ publicclass FechaTest { //---------------------------------------------------- ------------//Atributos //---------------------------------------------------- ------------ /** * Es la clase donde se realizarán las pruebas */ private Fecha miFecha; //---------------------------------------------------- ------------// Métodos //---------------------------------------------------- ------------ /** * Construye una nueva fecha */ @Before publicvoid setupEscenario1( ) { miFecha= new Fecha(23,02,1980); } /** * Prueba del constructor */ @Test publicvoid testFechaIntIntInt() { assertEquals( "El dia es inválido.", 23,miFecha.getDia() ); assertEquals( "El mes es inválido.",
  • 199.
    02,miFecha.getMes() ); assertEquals("El anio es inválido.", 1980 ,miFecha.getAnio() ); } @Test publicvoid testSetDia() { miFecha.setDia(24); assertEquals( "El dia es inválido.", 24,miFecha.getDia() ); } @Test publicvoid testSetMes() { miFecha.setMes(03); assertEquals( "El mes es inválido.", 03,miFecha.getMes() ); } @Test publicvoid testSetAnio() { miFecha.setAnio(1981); assertEquals( "El anio es inválido.", 1981 ,miFecha.getAnio() ); } @Test publicvoid testCalcularDiferenciaConFechaActual() { assertEquals( "La diferencia es incorrecta.", 373 ,miFecha.calcularDiferenciaConFechaActual(new Fecha(24,03,2010))); }} 4 Caso de estudio N.2 La Libreta Telefónica (Código Fuente:unidadIVCaso02LibretaTelefonica) Se requiere una aplicación para manejar una libreta telefónica en la cual sea posible registrar la información de varios contactos. La aplicación debe permitir: - Agregar un nuevo contacto
  • 200.
    - Leer lainformación de la libreta de un archivo de entrada. - Almacenar la información de forma persistente haciendo uso del concepto de serialización. - Eliminar un contacto indicando su posición - Modificar un contacto 4.1 Requisitos funcionales Para resolver este caso de estudio nos centraremos en los siguientes requisitos: Requisito funcional 1 Requisito funcional 2 Nombre Descripción Entrada Salida Nombre Descripción Entrada Salida Requisito no funcional Tipo: Persistencia Agregar un nuevo contacto Se debe agregar un nuevo contacto, para ello se debe ingresar el nombre, la dirección y el listado de teléfonos 1) nombre, 2) dirección 3) el listado de teléfonos Se ha agregado un nuevo contacto Leer la información de la libreta de un archivo de entrada. La información de la libreta se lee desde el archivo y constituye el estado inicial de la libreta Nombre del archivo con la información de la libreta Se inicializó el estado de la libreta, a partir de lo que se encontraba almacenado en el archivo.
  • 201.
    La información delmodelo del mundo debe persistente. Ello se logra haciendo uso de archivos de .dat 4.2 Comprensión del mundo del problema Se pueden identificar diferentes entidades, a saber: Libreta, Contacto, ContactoRepetidoException y Entidad. Esta última será la encargada de manejar todo lo referente a serialización.
  • 203.
    publicvoid agregarContacto(String nombre,String direccion,ArrayList<String> misTelefonos) throws ContactoRepetidoException { nombre=nombre.toUpperCase(); if(buscarContacto(nombre)==-1) misContactos.add(new Contacto(nombre,direccion, misTelefonos)); else thrownew ContactoRepetidoException("El contacto ya existe"); } La clase ContactoRepetidoException hereda de la clase Exception. Dentro de ella se llama al constructor de la superclase para poder inicializar la variable message con el mensaje que se le mostrará al usuario. Exception es la clase base de la que derivan todas las excepciones. Se podría concluir entonces que a través de ContactoRepetidoException es posible crear instancias de objetos de Exception. publicclass ContactoRepetidoException extends Exception { public ContactoRepetidoException (String message) { super(message); } } Para resolver el requerimiento de cargar la información de la libreta desde un archivo será necesario apoyarse en los Properties. En la clase Libreta deben ir los 3 siguientes métodos: publicvoid cargar( File arch ) throws Exception { Properties datos = cargarInfoLibreta( arch );
  • 204.
    inicializarContactos(datos); } El método cargarInfoLibretase encarga de cargar la información de los empleados de la empresa en un objeto de tipo Properties. private Properties cargarInfoLibreta( File arch ) throws Exception { Properties datos = new Properties( ); FileInputStream in = new FileInputStream( arch ); try { datos.load( in ); in.close( ); } catch( Exception e ) { thrownew Exception( "Formato inválido" ); } return datos; } El método inicializarContactos es el encargado de inicializar el arreglo de contactos con la información que recibe en el parámetro de entrada. Este método tiene como parámetro a datos. datos contiene la información cargada del archivo para inicializar la libreta. privatevoid inicializarContactos( Properties datos ) throws Exception { ArrayList <String> misTelefonos=new ArrayList<String> (); //Se inicia el proceso de carga del archivo String strNumeroContactos = datos.getProperty( "libreta.contactos" ); int maxEmpleados =
  • 205.
    Integer.parseInt( strNumeroContactos ); //Lee el nombre de cada persona de la respectiva propiedad y crea el objeto que //lo representa for ( int i = 0; i < maxEmpleados; i++ ) { String direccion="",nombre=""; String infoEmpleado = datos.getProperty( "libreta.contacto" + i ); StringTokenizer st2=new StringTokenizer(infoEmpleado,"[,]"); for (int j=0; st2.hasMoreTokens(); j++) { String elemento=st2.nextToken().trim(); if(j==0) nombre=(elemento); else if(j==1) direccion=(elemento); else { int telefono=Integer.parseInt(elemento); misTelefonos.add(elemento); } } try { agregarContacto(nombre, direccion, misTelefonos); } catch(Exception e) { } misTelefonos=new ArrayList<String>(); } }
  • 206.
    Por otro lado,en la VentanaPrincipal debe ir el método cargarContactos. Este método es el que carga los empleados a partir de un archivo seleccionado por el usuario /** Carga los empleados a partir de un archivo seleccionado por el usuario * @throws Exception */ publicvoid cargarContactos( ) throws Exception { JFileChooser fc = new JFileChooser( "./data" ); fc.setDialogTitle( "Abrir archivo de contactos" ); int resultado = fc.showOpenDialog( this ); if( resultado == JFileChooser.APPROVE_OPTION ) { File archivo = fc.getSelectedFile( ); miLibreta.cargar(archivo); } } Para resolver el requisito de ordenar por nombre en la clase se utilizará el método burbuja y la clase Collator, que ofrece más ventajas que el método compareTo. public String[] listarContactosPorNombre() { String arreglo[]=new String[misContactos.size()]; /*Collator posee unas constantes para trabajar diversos criterios relacionados con la comparación Collator.PRIMARY considera distintas dos letras si la letra base es distinta, por ejemplo si se tiene A, a y á, son iguales puesto que tiene la misma base Collator.SECUNDARY sólo considera iguales las mayúsculas y las minúsculas. No son iguales si tienen
  • 207.
    tilde. Collator.TERCIARY Son completamentediferentes las tres letras. Collator.IDENTICALLY sólo son iguales si su codigo interno es el mismo. Por ejemplo, existen varias formas de codificar internamente una á con tilde. No obstante cada codificación sería diferente aunque se vea igual. */ Collator comparador = Collator.getInstance(new Locale("es", "ES", "EURO")); // EURO es para estar al dia //Se configura para que ‘A’, ‘a’ y ‘á’ sean iguales comparador.setStrength(Collator.PRIMARY); for (int i = 0; i < misContactos.size(); i++) { for (int j = 0; j < misContactos.size()-1; j++) { // Compare elements of the array two at a time. if (comparador.compare(misContactos.get(j).getNombre(), misContactos.get(j+1).getNombre() ) > 0 ) { // Intercambia las palabras Contacto tmp = misContactos.get(j); misContactos.set(j,misContactos.get(j+1)); misContactos.set(j+1,tmp);; } } } for (int i = 0; i < misContactos.size(); i++) { arreglo[i]=misContactos.get(i).toString(); } return arreglo;
  • 208.
    } 4.4 Serializacion La serializaciónde objetos es una propiedad de Java a través de la cual es posible leer y escribir objetos en un archivo. Para serializar es necesario que cada una de las clases del paquete mundo implemente la interfaz serializable, la cual obliga a que todos los campos de datos del objeto sean serializables. La interfaz Serializable no tiene métodos, por ello su implementación es muy sencilla, basta con colocar implements Serializable en cada clase. Ejemplo: publicclass Contacto implements Serializable { } Para serializar es necesario utilizar las clases ObjectInputStream y ObjectOutputStream para leer y escribir los objetos. Si se desea especificarle a la máquina virtual de Java que un atributo no será parte persistente de un objeto debe utilizarse el modificador transient. Para automatizar el proceso de serialización se creó una clase “ genérica” llamada Entidad, la cual puede ser utilizada en cualquier aplicación que usted construya para que le agregue esta funcionalidad. La genericidad o parametrización surge a partir de Java 5 y su objetivo es permitir la creación de estructuras que almacenan elementos de un único tipo, siendo el compilador quien se encarga de comprobar que no se presenten inconsistencias. Java también permite la creación de clases genéricas. Siguiendo la sintaxis: NombreClase<T1,…,Tn>. Ejemplo: Entidad que almacena objetos de tipo T publicclass Entidad <T> { private T miObjeto; private String ruta;
  • 209.
    public Entidad (String ruta, T miObjeto) { this.ruta=ruta; this.miObjeto =miObjeto; // capacidad 0, contenido nada, incremento 0 } Recibe un objeto de tipo T, para inicializar el atributo de la clase public T load ( String nameFile ) throws Exception { FileInputStream fileIn; Devuelve un objeto de tipo T con la ObjectInputStream in; información que se cargó del archivoT readFile; try { fileIn = new FileInputStream ( nameFile ); in = new ObjectInputStream ( fileIn ); readFile = ( T ) (in.readObject()); } catch( Exception e ) { thrownew Exception("ERROR, no se pudo leer del archivo");} return readFile;} publicvoid leerDatosArchivo ( ) throws Exception { miObjeto = (T) load (ruta);} } La expresión de instanciación para este tipo de clases debe llevar el identificador completo del tipo que será creado, al igual que el argumento para los constructores de dicho tipo. Aesta clase se le reservará memoria en la VentanaPrincipal. A continuación se describen los pasos realizados.
  • 210.
    En la VentanaPrincipaldebe agregar un atributo de tipo Entidad: privatestatic Entidad <Libreta>miEntidad; Esta línea quiere decir que se va a almacenar una libreta teléfonica, es decir, se debe aclarar que es lo que se va a almacenar. Si la clase principal del mundo fue por ejemplo Empresa, entonces la línea sería privatestatic Entidad <Empresa>miEntidad; En la VentanaPrincipal se requiere también agregar los siguientes métodos: El método serializar tiene como parámetro la ruta donde está almacenado el archivo. En caso de que el archivo no exista se crea uno nuevo, sino se carga la información del archivo y se le asigna a la libreta. publicstaticvoid serializar(String ruta) throws Exception { miEntidad = new Entidad <Libreta> (ruta,miLibreta ); File fOrig = new File(ruta ); if(!fOrig.exists ( )) { miEntidad.save(ruta); } else { miEntidad.leerDatosArchivo(); miLibreta=miEntidad.getMiObjeto(); } jList1.setListData(miLibreta.listarContactosPorNombre( } El método guardar archivo almacena la información que hay en el mundo. publicvoid guardarArchivo() throws Exception { miEntidad.save(miEntidad.getRuta());}
  • 211.
    5 Hoja detrabajo N.1 El Ahorcado (Código Fuente: unidadIVHoja01Ahorcado) Se requiere una aplicación para el juego del Ahorcado. El usuario podrá agregar palabras al conjunto de palabras existentes. También deberá proporcionarse la funcionalidad de cargar palabras de un archivo. De igual forma, la aplicación deberá ofrecer persistencia mediante serialización. Cuando el juego inicie el sistema seleccionará aleatoriamente una palabra del banco de palabras existentes. El usuario ingresará una letra y el sistema verificará si está contenida dentro de la palabra seleccionada. Si el usuario se equivoca 4 veces el juego se dará por perdido. 5.1 Requisitos funcionales Para resolver este caso de estudio nos centraremos en los siguientes requisitos: Requisito funcional 1 Requisito funcional 1 Requisito funcional 2 Nombre Descripción Entrada Salida Nombre Descripción Entrada Salida Nombre Descripción Entrada Salida Requisito no funcional Tipo: Persistencia Agregar una palabra
  • 212.
    Cargar palabras desdeun archivo jugar El usuario ingresa una letra y se debe verificar si está o no contenida en la palabra que el sistema seleccionó aleatoriamente Una letra Si la letra está en la palabra se le informa al usuario las posiciones donde está ubicada la letra dentro de la palabra y se verifica si ya se completó la palabra, pues en este caso el juego terminaría. Si la letra no está entonces se contabiliza un nuevo errores y se verifica si ya completó los 4 errores. La información del modelo del mundo debe persistente. Ello se logra haciendo uso de archivos de .dat 5.2 Comprensión del mundo del problema Se pueden identificar diferentes entidades, a saber: 5.3 Diseño y construcción de la solución del problema En la clase Ahorcado se debe crear un método que permita seleccionar aleatoriamente una palabra. publicvoid iniciarJuego()throws SinPalabrasException { if(misPalabras.size()!=0) {palabraSeleccionada=misPalabras.get((int) (Math.random()*(misPalabras.size()1))); palabra=newchar[palabraSeleccionada.length()]; } else thrownew SinPalabrasException("No hay palabras almacenadas"); } El método agregarPalabra tiene como parámetro la palabra que el usuario desea agregar al banco de palabras.
  • 213.
    publicvoid agregarPalabra(String palabra)throws PalabraRepetidaException { if(!misPalabras.contains(palabra)) { misPalabras.add(palabra); } else thrownew PalabraRepetidaException("La palabra ya existe"); } El método jugar recibe una letra y mediante un for verifica si ésta se encuentra contenida en la palabra seleccionada aleatoriamente por el sistema. publicboolean jugar(char letra) { boolean centinela=false; System.out.println("letra "+letra+ " Seleccionada "+palabraSeleccionada); for(int i=0; i<palabraSeleccionada.length(); i++) { if(letra==palabraSeleccionada.charAt(i)) { palabra[i]=palabraSeleccionada.charAt(i); centinela=true; } } if(centinela==false) {contadorErrores++;} return centinela; }
  • 214.
    El método verificarGanorecorre la palabra seleccionada y compara con cada uno de los caracteres que hay en el arreglo de char llamado palabra. publicboolean verificarGano() { } El método verificarGano compara el contador de errores con 4. Si son iguales el usuario ha perdido. publicboolean verificarPerdio() { } Para cargar las palabras desde el archivo Properties se deben incluir en la clase Ahorcado los siguientes métodos: publicvoid cargar( File arch ) throws Exception { Properties datos = cargarPalabras( arch ); inicializarPalabras(datos); } El método cargarPalabras se encarga de cargar cada una de las palabras del ahorcado en un objeto de tipo Properties. private Properties cargarPalabras( File arch ) throws Exception { Properties datos = new Properties( ); FileInputStream in = new FileInputStream( arch ); try { datos.load( in ); in.close( ); } catch( Exception e ) {
  • 215.
    thrownew Exception( "Formatoinválido" ); } return datos; } El método inicializarPalabras inicializa el ahorcado con la información que recibe en el parámetro de entrada. privatevoid inicializarPalabras( Properties datos ) throws Exception { //Se inicia el proceso de carga del archivo String strNumeroPalabras = datos.getProperty( "ahorcado.palabras" ); int maxPalabras = Integer.parseInt( strNumeroPalabras ); // Lee cada palabra de la respectiva propiedad y crea el objeto que lo representa for( int i = 0; i < maxPalabras; i++ ) { //Complete } } Por otro lado, se cuenta con un archivo Properties en donde se encuentra la ruta del archivo en donde se va a serializar. Esta ruta se cargará a través de los siguientes dos métodos, incluidos también en la clase Ahorcado. public String cargarRutaSerializacion( File arch ) throws Exception { Properties datos = cargarPalabras( arch ); return inicializarRutaSerializacion(datos); }
  • 216.
    private String inicializarRutaSerializacion( Propertiesdatos ) throws Exception { //Se inicia el proceso de carga del archivo String ruta= datos.getProperty( "ahorcado.ruta" ); return ruta; } El archivo ahorcado properties tiene la siguiente forma: ahorcado.ruta=./data/archivo.dat En la VentanaPrincipal se debe declarar el siguiente atributo: privatestatic Entidad <Ahorcado>miEntidad; Y también hay que agregar el siguiente método publicstaticvoid serializar(String ruta) throws Exception { miEntidad = new Entidad <Ahorcado> (ruta,miAhorcado ); File fOrig = new File(ruta ); if(!fOrig.exists ( )) { miEntidad.save(ruta); } else { miEntidad.leerDatosArchivo(); miAhorcado=miEntidad.getMiObjeto(); } } 6 Caso de estudio N.2 La Tienda Paisa (Código Fuente: unidadIVHoja01TiendaPaisa) Se desea crear una aplicación para manejar la información de un minimercado. En el minimercado hay artículos, cada uno de los cuales tiene codigo, nombre,
  • 220.
    2)nombre, 3)cantidad deExistencias y 4)precio Un nuevo artículo ha sido agregado Generar venta o factura Se debe permitir generar una nueva factura, para ello el cliente debe informar cuales son los artículos que desea adquirir y la cantidad correspondiente por cada uno de ellos. Se debe verificar que si exista la cantidad solicitada por el usuario. 1)listado de articulo con la cantidad solicitada por cada uno de ellos Una nueva factura se ha generado La información del modelo del mundo debe persistente. Ello se logra haciendo uso de archivos de .dat 6.2 Comprensión del mundo del problema Se pueden identificar diferentes entidades, a saber:
  • 223.
    El método actualizarUltimoPedidopermite actualizar la cantidad de existencias en el ArrayList general de pedidos, es decir, cuando se adquiere un artículo en el minimercado la cantidad de existencias de ese artículo debe disminuir. public Pedido actualizarUltimoPedido(int cantidad) throws NoHayExistenciasDisponiblesException { misPedidosCompraActual.get(misPedidosCompraActual.size 1).setCantidadExistencias(cantidad); int pos=identificarYaExistePedido(misPedidosDisponibles, misPedidosCompraActual.get(misPedidosCompraActual.size if(pos!=-1) { if (misPedidosDisponibles.get(pos).getCantidadExistencias cantidad>=0&&misPedidosDisponibles.get(pos).getCantidad { misPedidosDisponibles.get(pos).setCantidadExistencias(m os).getCantidadExistencias()-cantidad); } else { misPedidosCompraActual.remove(misPedidosCompraActual.s thrownew NoHayExistenciasDisponiblesException("No hay existencias disponibles de ese articulo"); } } return misPedidosCompraActual.get(misPedidosCompraActual.size
  • 224.
    } El método calcularPrecioTotalVentarecorre el ArrayList de la venta y calcula el total a pagar. publicdouble calcularPrecioTotalVenta() { double acum=0; for (int i=0; i<misPedidosCompraActual.size(); i++) { acum+= (misPedidosCompraActual.get(i).getCantidadExistencias( ual.get(i).getPrecio()); } return acum; } Finalmente, de la clase Tienda se tienen entre otros los siguientes métodos: El método agregarPedido agrega un nuevo pedido al ArrayList general de pedidos. Si el pedido ya existe se genera una excepción. publicvoid agregarPedido(String codigo, String nombre, int cantidadExistencias, double precio)throws YaEstaElPedidoException { if(buscarPedido(codigo)==-1) { Pedido miP=new Pedido(codigo,nombre,cantidadExistencias,precio); misPedidos.add(miP); } else thrownew YaEstaElPedidoException("Este pedido ya
  • 225.
    existe en elsistema"); } El método crear Factura le reserva memoria a una nueva factura y la agrega al ArrayList general de ventas. publicvoid crearFactura() { Venta miVenta=new Venta(misPedidos); misVentas.add(miVenta); } El método agregarPedidoALaFactura agrega un nuevo pedido a la factura que se encuentra ubicada en la última posición del ArrayList de ventas. publicvoid agregarPedidoALaFactura(String codigo, String nombre, int cantidad,double precio)throws NoHayExistenciasDisponiblesException { misVentas.get(misVentas.size()-1).agregarPedido(codigo nombre, cantidad, precio); } BIBLIOGRAFIA ARBOLEDACOBO, Liliana María.Programación en red con java. Cali, Universidad ICESI, 2004 BISHOP, Judy. Java Fundamentos de programación. Addison-Wesley. Segunda Edición. Madrid. 1999. ISBN: 84-7829-022-2. BOOCH. Object Oriented Analysis & Design With Applications. Prentice Hall, 1998 BOOCH. UML El Lenguaje Unificado de Modelado. Addison Wesley CEBALLOS S ERRA, Francisco Javier. Java 2: curso de programación. Alfaomega, 2006. México DEJALÓN G. Javier y RODRÍGUEZ J. Ignacio, Aitor, Imaz. Aprenda Java como si estuviera en primero. Escuela Superior de Ingenieros Industriales. San Sebastian.
  • 226.
    Enero 2000. DEITEL, Hy DEITEl, P. Como programar en Java, Prentice Hall. Primera edición. México, 1994 ISBN: 970-17-0044-9. ECKEL, Bruce. Piensa en Java. Prentice-Hall, Pearson Educación. Segunda edicion. Madrid, 2003. ISBN: 84-205-3192-8. ER KSSON, H. UML 2 Toolkit. Indianapolis: Wiley 2004 FOWLER, Martín. UML, gota a gota. Addison Wesley Longman de México,SAde CV México 1.999. ISBN: 968-44-364-1 Goodrich, Michael y Tamassia, Roberto. Estructuras de datos y algoritmos en Java. CECSA. Segunda edición. 2002 HURTADO G L, Sandra Victoria. Conceptos Avanzados de Programación con JAVA. Universidad ICESI, 2002 LEE, Richard. Practical Object Oriented Development with UML and Java. Prentice-hall, 2002. LEMAY, Laura. Cadenhead Rogers. Aprendiendo java en 21 días. Prentice Hall. ISBN: 970-17-0229-8. Mexico.1999. 882570-9. RICHARDSON. Professional Java JDK 6. Wrox, 2007 0228-1. VILLALOBOS, Jorge. Introduccion a las Estructuras de Datos. Prentice Hall, 2008 VILLALOBOS S., Jorge Ay CASALLAS, Rubby. Fundamentos de programación Aprendizaje Activo Basado en casos. Prentice Hall. ISBN: 970-26-0846-5. 2006 ZHANG, Computer Graphics Using Java 2d & 3d,-Pearson, Enero de 2007.