Вы находитесь на странице: 1из 292

SSD3: Programacin y Diseo Orientado a Objetos

Unidad 1. Diseo de Clases


Unidad 2. Implementacin de Clases
Unidad 3. Implementacin Avanzada de Clases

Introduccin
Este curso introduce a los alumnos a la solucin de problemas por medio del diseo y la
programacin orientada a objetos. El nfasis est en el anlisis del problema y el diseo de
la solucin, la documentacin y la implementacin. Los alumnos utilizan bibliotecas
comerciales de software, y crean proyectos de software. Los ejercicios de programacin se
llevan a cabo en Java.

Libro

Barker, Jacquie. Beginning Java Objects: From Concepts to Code. Primera Edicin,
Apress, 2000.
o
Barker, Jacquie. Beginning Java Objects: From Concepts to Code. Segunda
Edicin, Apress, 2005.
Las tareas de lectura se indican dentro del contenido del curso. Adems, una lista
completa se encuentra en Apndice D. Lecturas.

Requerimientos de Software

Java 2 Platform Standard Edition 5.0


Eclipse 3.1.x con el plug-in EclipseUML , u otro ambiente de programacin de Java
con depurador y editor de UML.

El propsito de SSD3 es que los alumnos


1.
2.
3.
4.

Aprendan a programar utilizando tcnicas orientadas a objetos.


Aprender a disead clases extensibles y robustas.
Aprender a expresar diseos utilizando UML.
Aprender a escribir programas escribiendo clases e interfaces cooperativas.

Los alumnos que terminen exitosamente SSD3 sern capaces de


I.

Producir
1. Programas de java que exhiban elementos de programacin orientada a
objetos, incluyendo herencia, polimorfismo, clases abstractas e interfaces
2. Clases de Java robustas utilizando excepciones y modificadores de acceso
3. Diseos orientado a objetos utilizando UML
4. Implementaciones de Java a partir de una especificacin
5. Extensiones a programas de Java existentes para mejorar el desempeo o
aadir funcionalidad
6. Cdigo con calidad profesional aplicando convenciones de cdigo utilizados
en la industria

II.

III.
IV.

Utilizar
1. Herramientas profesionales comnmente utilizadas tales como depuradores
(debuggers), ambientes de desarrollo (IDE), y editores de UML
2. Clases y paquetes utilitarios que involucran E/S (I/O), y tokenizacin
3. Clases de Java Swing para implementar Interfaces Grficas de Usuarios
(GUI)
4. Recursos en lnea para mantenerse al corriente de los desarrollos de Java
5. Patrones de Diseo
6. Casos de prueba para la prueba de unidades (unit testing)
7. Colecciones e iteradores
Discutir de Manera Informada sobre
1. Conceptos avanzados de orientacin a objetos
Posicionarse como Programador de Java
Al completar exitosamente este curso, el estudiante ser capaz de (a) llevar a cabo
tareas de programacin tales como extender la funcionalidad de programas
existentes y mejorar el desempeo de mdulos de programas existentes, (b)
implementar Interfaces Grficas de Usuario (GUI) en Java, (c) implementar
programas que exhiban un comportamiento especificado, y (d) depurar y corregir
programas que no se comportan de acuerdo a una especificacin.

Unidad 1. Diseo de Clases

1.1 Aplicaciones de Java


1.2 Diseando Clases

1.1 Aplicaciones de Java

1.1.1 Aplicaciones en Java


1.1.2 Usando Eclipse
1.1.3 Comenzando con el API de Java
1.1.4 Consola E/S (I/O)
1.1.5 Objetos Excepcin
1.1.6 Convenciones de Cdigo
1.1.7 Javadoc
1.1.8 Depurando
1.1.9 Depurando con Eclipse

1.1.1 Aplicaciones en Java

Applets en Java
Aplicaciones en Java
Lecturas:

Requeridas:
o Barker, primera edicin, captulo 1 (pginas 137).
o Barker, segunda edicin, captulo 2 (pginas 1532).
Secuencia: Leer el libro de texto antes de leer esta pgina.

Applets en Java
Los programas de Java se presentan en muchas variantes: applets, servlets y aplicaciones.
Los applets son referenciados desde las pginas Web e interpretadas por navegadores Web.
Cada applet contiene una clase pblica que extiende la clase Applet.
El siguiente es un applet que genera un mensaje como salida:
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:

import java.applet.*;
import java.awt.*;
public class MyApplet extends Applet {
public void paint(Graphics g) {
g.drawString("This is an applet!\n", 10, 10);
}
}

Listado 1 MyApplet.java

Aplicaciones en Java
Las aplicaciones de Java son programas "autnomos", interpretados por un intrprete de
Java (no por un navegador Web) sobre un sistema anfitrin. Para ejecutar una aplicacin de
Java, el usuario escribe un comando que invoca el intrprete de Java en la aplicacin
especificada.

Figura 1 Comando para ejecutar MyApplication


En este ejemplo, el comando java llama al intrprete de Java y MyApplication es el
nombre de la clase que ser ejecutada. El sistema operativo comienza la ejecucin llamando
al mtodo main de la clase MyApplication. Las aplicaciones pueden consistir de una o
muchas clases; una de estas clases debe tener un mtodo main. El mtodo main tiene la
siguiente firma.
public static void

main(String[]

args)

El mtodo main tiene un parmetro de entrada, un arreglo String que contiene argumentos
de lnea de comando que el usuario puede haber especificado al teclear el comando java.
Los argumentos de lnea de comando permiten al usuario pasar informacin a la aplicacin.
No utilizaremos argumentos de lnea de comando en este curso.
La siguiente es una aplicacin simple que despliega las palabras en la pantalla: "This is
my first application!" ("sta es mi primera aplicacin!").
1: public class MyApplication {
2:
3:
public static void main(String[] args) {
4:
5:
System.out.println("This is my first application!");
6:
}
7: }

Listado 2 MyApplication.java
La clase que contiene el mtodo main debe ser public. La declaracin de clase puede o no
tener una clusula extends; en este aspecto, las aplicaciones difieren de los applets. Los
nombres de clases deben tener la primera letra de cada palabra en maysculas y no deben
contener ningn guin bajo ( _ ). Por ejemplo, el nombre WordCount cumple con la
convencin, mientras que wordCount, wordcount y word_count no lo hacen. El archivo
que contiene el cdigo fuente debe tener el mismo nombre que la clase que contiene y usar
la extensin .java. Por ejemplo, el archivo que contiene la clase WordCount debe ser
nombrado WordCount.java.
La siguiente figura muestra la salida de la clase MyApplication.

Figura 2 Ejecucin de MyApplication

1.1.2 Usando Eclipse

Introduccin
Crear el Proyecto
Crear la Clase
Compilar la Clase
Ejecutar la Aplicacin

Introduccin
Un Ambiente Integrado de Desarrollo (Integrated Development Environment o IDE por sus
siglas en ingls) es una herramienta utilizada por los desarrolladores de sistemas para
ayudarlos durante las diferentes fases del desarrollo de sistemas. Eclipse es un IDE de
cdigo abierto (open source) que soporta muchos lenguajes de programacin. Eclipse viene
con un Ambiente de Desarrollo de Java (Java Development Environment o JDE) que
incluye un editor de resalte de sintaxis, un compilador, un depurador, un navegador de
clases y un administrador de archivo/proyecto. La funcionalidad de Eclipse puede ser
extendido con plug-ins tales como plug-ins de UML para modelacin Orientada a Objetos.
En esta pgina, te mostraremos cmo crear y ejecutar la aplicacin MyApplication.

Crear el Proyecto
El primer paso es crear un proyecto de Java:
1. En el men File (archivo), apunta a New (nuevo) y despus haz un clic en Project
(proyecto).
2. En el asistente de New Project (nuevo proyecto), presiona Java en el panel
izquierdo, selecciona Java Project (proyecto de java) en el panel derecho y despus
da un clic en Next (siguiente).

Figura 1 Asistente de Proyecto Nuevo (New Project)


3. En el cuadro Project name (nombre de proyecto), escribe MyApplication.
Selecciona el cuadro Use default (utilizar predeterminado) y da un clic en Finish
(terminar).

Figura 2 Cuadro de Dilogo de Nuevo Proyecto de Java (New Java Project)


4. Eclipse crear un nuevo proyecto de Java y desplegar la perspectiva de Java, una
de las interfases de Eclipse para trabajar en un proyecto de Java. La perspectiva de
Java ofrece varias herramientas incluyendo un editor de cdigo, un navegador de
archivos y un navegador de clases.

Figura 3 Perspectiva de Java


5. Puedes cambiar la perspectiva del proyecto. En el men Window (ventana),
selecciona Open Perspective (abrir perspectiva) y elige la perspectiva deseada.
Tambin puedes dar un clic en el icono de la perspectiva deseada en la barra de
acceso directo en el extremo izquierdo de la ventana.

Figura 4 Barra de acceso directo de Perspectivas

Crear la Clase
1. En el men File (archivo), apunta a New (nuevo) y da un clic en Class (clase).
2. En el asistente de Nueva Clase de Java o New Java Class, escribe MyApplication en
el cuadro Name (nombre) y despus selecciona Finish (terminar).

Figura 5 Asistente New Class (Nueva Clase)


3. Eclipse desplegar una plantilla para una nueva clase llamada MyApplication.

Figura 6 Plantilla para una nueva clase


4. En el men Window (ventana), apunta a Open Perspective (abrir perspectiva) y
presiona en Java Browsing (navegacin en Java). Esta perspectiva contiene un
editor de Java y varias vistas del proyecto. Si el usuario presiona algn elemento en
las vistas Types (tipos) o Members (miembros), el editor desplegar el cdigo para
dicho elemento.
o La vista Projects (proyectos) muestra proyectos de Java, carpetas fuente,
libreras externas e internas.
o La vista Packages (paquetes) lista los paquetes de clases en el proyecto
seleccionado.
o La vista Types (tipos) lista las clases del paquete seleccionado.
o La vista Members (miembros) muestra las variables y los mtodos de la
clase seleccionada.
5. Introduce el cdigo de MyApplication. Ver el listado 2

Figura 7 Cdigo de MyApplication.java

Compilar la Clase
Eclipse incluye un compilador de Java incremental. Cuando introduces una lnea de cdigo
que contiene un error, el editor desplegar, en la derecha, una marca roja junto a dicha lnea
de cdigo.
1. Introduce un error de sintaxis borrando el punto y coma ( ; ) al final de la lnea que
contiene System.out.println. El editor desplegar una marca roja.
2. Apunta sobre la marca roja para desplegar el mensaje de error.

Figura 8 Mensaje de error de sintaxis


3. Corrige el error aadiendo el punto y coma ( ; ). La marca roja desaparecer.

Ejecutar la Aplicacin
1. Comienza por crear una configuracin inicial para el proyecto MyApplication. Da
un clic en MyApplication en la vista Projects (proyectos), presiona la flecha a la
derecha del botn Run (ejecutar) en la barra de herramientas y despus presiona
Run....

Figura 9 Ejecuta la aplicacin de Java


2. En el cuadro de dilogo de Run (ejecutar), escribe MyApplication en el cuadro
Main class (clase principal) y despus presiona Run (ejecutar).

Figura 10 Creando la configuracin


3. Una vez que se ha establecido la configuracin inicial, el usuario puede ejecutar la
aplicacin dando un clic en la flecha que se encuentra a la derecha del botn Run en
la barra de herramientas, apuntando a Run As (ejecutar como) y despus haciendo
clic en Java Application (aplicacin de Java).

Figura 11 Ejecutando la aplicacin


4. Si la clase de Java no ha sido guardada, Eclipse desplegar un cuadro de dilogo
para guardar los archivos del proyecto de Java. Presiona OK.

Figura 12 Guarda el proyecto de Java


5. Eclipse desplegar el mensaje en la vista Console (consola) que aparece en la parte
inferior de la ventana.

Figura 13 Salida de la Consola


6. La vista Console (consola) despliega la salida de la aplicacin. Si una aplicacin
utiliza avisos para solicitar la entrada del usuario, dichos indicadores son
desplegados en la vista Console. El usuario responde a un indicador escribiendo en
la vista Console. El color de la vista Console codifica la salida estndar, error
estndar y entrada estndar. Para una discusin del paquete java.io, ver la pgina
Consola E/S (I/O). Los colores predeterminados son:
o Azul para salida estndar
o Rojo para error estndar (mensajes de error e indicadores)
o Verde para entrada estndar

1.1.3 Comenzando con el API de Java

Introduccin
Paquetes y el Estatuto import
La Clase java.lang.String
La Clase java.util.StringTokenizer
Las Clases de Envoltura (Wrapper Classes)

Introduccin
El API (Interfaz de Programacin de Aplicaciones o Application Programming Interface)
de Java representa una librera de Java extensiva. Estas libreras son escritas
cuidadosamente, son robustas y estn probadas exitosamente.
La documentacin del API de Java es generada por la herramienta Javadoc. Javadoc
produce un conjunto de pginas HTML a partir de los comentarios Javadoc de un archivo
fuente de Java. Los comentarios Javadoc documentan las clases, variables y mtodos de
una aplicacin. Utilizaremos comentarios Javadoc en nuestro cdigo fuente para que la
documentacin de nuestras aplicaciones cuente con la misma organizacin y formato que el
API de Java.

Paquetes y el Estatuto import


Las clases del API de Java estn agrupadas en paquetes. Un paquete es simplemente una
coleccin de clases relacionadas. El siguiente es un ejemplo del nombre de un paquete:
java.util

El nombre completo calificado de una clase que es parte de un paquete es el nombre del
paquete y el nombre de la clase, separados por un punto.
java.util.GregorianCalendar

Para declarar dos variables de tipo GregorianCalendar, podemos escribir:


java.util.GregorianCalendar firstDate =
new java.util.GregorianCalendar(2004, 1, 1);
java.util.GregorianCalendar lastDate =
new java.util.GregorianCalendar(2004, 12, 31);

Escribir el nombre completo calificado de una clase es tedioso y el cdigo resultante es


difcil de leer. Por esta razn, Java ofrece el estatuto import. Se utiliza para "importar" una
clase o un paquete entero de clases en un archivo. Una clase importada puede ser
referenciada utilizando su nombre simple, el nombre completo calificado menos el nombre
del paquete. Un estatuto import est compuesto por la palabra clave import, un nombre
completo calificado y un punto y coma:

import java.util.GregorianCalendar;

Esta instruccin, colocada al inicio de un archivo, hace posible escribir:


GregorianCalendar
GregorianCalendar

firstDate = new GregorianCalendar(2004, 1, 1);


lastDate = new GregorianCalendar(2004, 12, 31);

Esto resulta ms conveniente, debido a que el nombre del paquete debe ser mencionado
slo una vez en el estatuto import. Continuamente, los programadores utilizan muchas
clases del mismo paquete. En vez de utilizar un estatuto import para cada clase, se importa
el paquete completo:
import java.util.*;

El asterisco (*) acta como un comodn, que representa a todas las clases del paquete
especificado.
El asterisco es conveniente. Por ejemplo, considera una aplicacin que utiliza el asterisco
para importar todas las clases del paquete java.io, pero utiliza slo una. El nuevo cdigo
que utilice otras clases de java.io puede ser agregado sin aadir ms estatutos import.
Muchos programadores utilizan el asterisco, an cuando requieren slo una clase de un
paquete, porque es rpido de escribir y no incurre en ninguna sobrecarga: importar un
paquete no disminuye la velocidad de compilacin o ejecucin, ni incrementa el tamao del
cdigo de bytes.
Finalmente, el paquete java.lang es implcitamente importado en todas las aplicaciones de
Java, de modo que nunca existe la necesidad de importar java.lang. Todas las
aplicaciones pueden hacer referencia a clases del paquete java.lang utilizando sus
nombres simples.
Para cada una de las clases presentadas a continuacin, se te proporciona una liga a su
documentacin API. Te alentamos a seguir estas ligas para que te familiarices con los
muchos mtodos tiles que tienen estas clases.

La Clase java.lang.String
Debido a que Java no provee un tipo string primitivo, la clase java.lang.String se utiliza
mucho. Java incluye la literal de la clase String, una secuencia de caracteres entre comillas
dobles, tales como "abc". Una literal de la clase String es una instancia de la clase String.
La siguiente es una lista de algunos mtodos definidos en la clase String:

String(). Construye un nuevo objeto String que representa una secuencia vaca
de caracteres.

String(char[] value). Construye un nuevo objeto String que representa la


secuencia de caracteres contenidos en el arreglo de caracteres.

String(String original).

int length().

Construye un nuevo objeto String que representa la


misma secuencia de caracteres que el argumento.
Obtiene el nmero de caracteres en el String.

char charAt(int index).

Regresa el carcter que se encuentra en el ndice

especificado.

boolean equals(Object anObject). Regresa verdadero


un String con la misma secuencia de caracteres.

int indexOf(int ch).

Regresa el ndice de la primera ocurrencia del carcter .

int indexOf(String
String.

str).

boolean startsWith(String prefix).

si anObject representa

Regresa el ndice de la primera ocurrencia del

Verifica si el String tiene el prefijo

especificado.

String substring(int beginIndex, int endIndex).

Regresa una subcadena.

Java tambin provee el operador de concatenacin de String ( + ). Es un operador binario


que requiere dos operandos de tipo String. Concatena estos operandos, regresando el
resultado en un nuevo String. Las siguientes dos lneas representan objetos String
equivalentes:
"uno" + "dos"
"unodos

Observa que no se coloca ningn separador entre los operandos en el resultado


Cada clase del API de Java tiene un mtodo llamado toString. Este mtodo regresa la
representacin String de un objeto. Esto significa que cada instancia del API de Java tiene
un String equivalente:
"hola " + anyObject.toString()

Convenientemente, si uno de los operandos del operador de concatenacin es un objeto


(diferente de un String, por supuesto), el mtodo toString de dicho objeto ser invocado
automticamente, permitiendo de este modo la concatenacin. Esto significa que podemos
escribir:
"hola " + anyObject

Si un primitivo es el operando del operador de concatenacin String, ser reemplazado por


un objeto equivalente y el mtodo toString de dicho objeto ser llamado. Esto significa
que podemos escribir:

"hola " + 5
Sin una traduccin automtica, tendramos que escribir:
"hola " + (new

Integer(5)).toString()

Debido a que el smbolo ms ( + ) es tambin utilizado para sumar, por lo menos uno de sus
operandos debe ser un String para que funcione como operador de concatenacin.
Observa lo siguiente:
stdOut.println(2 + 3 + "5"); // imprime 55, no 235
stdOut.println(2 + "" + 3 + "5"); // imprime 235

El siguiente ejemplo ilustra el uso de mtodos en la clase String:

1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:

El archivo StringClassDemo.java

import java.io.*; // aqu est la clase PrintWriter


// no es necesario importar String porque se encuentra en java.lang
/**
* Esta clase es una demostracin de la clase String
*
* @author
* version 1.0.0
*/
public class StringClassDemo {
private static

PrintWriter

stdOut = new

PrintWriter(System.out, true);

/**
* Mtodo principal, muestra el uso de la clase String
*
* @param args no utilizados
*/
public static void main(String[] args) {
String

strHello = new

String("Hello");

// la literal string ser reemplazado por el nuevo String("World")


String strWorld = "World";
// la concatenacin de cadenas imprime: Hello, World
stdOut.println(strHello + ", " + strWorld);
// imprime el caracter r
stdOut.println(strWorld.charAt(2));
// imprime el entero 2 que es el ndice de la primera 'l' en strHello
stdOut.println(strHello.indexOf('l'));

35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:

// imprime el entero 1 que es el ndice del inicio de la cadena


// "or" en strWorld
stdOut.println(strWorld.indexOf("or"));
// imprime el entero 6 que es el ndice de la primera 'o' en la
// cadena "HelloWorld" empezando por el ndice 5
stdOut.println((strHello + strWorld).indexOf('o', 5));
// imprime: "Hello" and "World" are equal in length
stdOut.print("\"" + strHello + "\" and \"" + strWorld + "\" are ");
if (strHello.length() != strWorld.length()) {
stdOut.print("not ");
}
stdOut.println("equal in length");
// re-asignar strWorld a un nuevo String podra
// imprimir: strWorld = "Hello";
strWorld = new String("Hello");
//
//
//
//
if

aqu no se imprime nada


Esto puede ser sorprendente, pero recuerda, debido a que los
Strings son objetos, el == compara las direcciones
de los objetos, no los objetos en s.
(strHello == strWorld) {
stdOut.println("The strings are equivalent according to ==");

}
// a continuacin se presenta lo que debe escribirse
// imprime: The strings are equivalent.
if (strHello.equals(strWorld)) {
stdOut.println("The strings are equivalent.");
}
// existe un grupo de mtodos estadsticos para convertir de
// un primitivo a una representacin String del mismo
String strValues;
strValues = String.valueOf(5.87); // strValues es ahora "5.87"
strValues = String.valueOf(true); // strValues es ahora "true"
strValues = String.valueOf(18); // strValues es ahora "18"
// concatenacin
stdOut.println(5.87 + "" + true + "" + 18);

// imprime 5.87true18

}
}

La Clase java.util.StringTokenizer
Tokenizacin (tokenizing) es el proceso de descomponer una cadena en piezas ms
pequeas llamadas tokens. Los tokens estn separados, o delimitados, por un carcter o un
grupo de caracteres. Por ejemplo, si consideramos que la siguiente cadena es tokenizada
utilizando espacios en blanco como delimitador, el resultado sera cinco tokens:

"Esta cadena tiene cinco tokens"

El espacio en blanco es el delimitador ms comn (espacio en blanco incluye el carcter de


espacio, el carcter tabulador, el carcter de nueva lnea, y el carcter retorno de carro).
Otros delimitadores de uso frecuente son el guin bajo ( _ ) y la coma ( , ).
"Esta_cadena_tiene_cinco_tokens"
"Esta,cadena,tiene,cinco,tokens"

Cualquier carcter puede usarse como delimitador. Por ejemplo, si la cadena "Esta
cadena tiene cinco tokens" es tokenizada utilizando el carcter "n" como
delimitador, el resultado ser cinco tokens:

"Esta cade"
"a tie"
"e ci"
"co toke"
"s"

Sin embargo, los delimitadores tales como "n", son poco comunes.
La clase StringTokenizer es parte del paquete java.util. La siguiente, es una lista de
algunos de los mtodos de la clase StringTokenizer:

StringTokenizer(String str).

StringTokenizer(String str, String delim).


cadenas. El argumento delim contiene los caracteres

Construye un tokenizador de cadenas. Utiliza el


delimitador predeterminado, el espacio en blanco.
Construye un tokenizador de
delimitadores para separar los

tokens.

boolean hasMoreTokens().

String nextToken(String delim).

int countTokens().

Verifica si hay ms tokens que extraer.


Regresa el siguiente token de la cadena.

Obtiene el nmero de tokens que an pueden ser extrados,


no el nmero de tokens de la cadena.

La siguiente aplicacin almacena los datos del inventario de un producto (nombre, cantidad
y precio) en un String. El String est delimitado por el carcter de guin bajo ( _ ). La
aplicacin utiliza un objeto StringTokenizer para extraer los tokens del String.
1: import java.util.*;
2:
3: public class ProductInfo {
4:
5:
public static void main(String[]
6:

args) {

7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19: }

String data = "Mini Discs 74 Minute (10-Pack)_5_9.00";


StringTokenizer tknzr = new StringTokenizer(data, "_");
String name = tknzr.nextToken();
String quantity = tknzr.nextToken();
String price = tknzr.nextToken();
System.out.println("Name: " + name);
System.out.println("Quantity: " + quantity);
System.out.println("Price: " + price);
}

Listado 1 ProductInfo.java
Cuando la aplicacin es ejecutada, los datos del inventario son desplegados.

Figura 1 Ejecucin de ProductInfo


El siguiente ejemplo ilustra el uso de la clase StringTokenizer.

1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:

El archivo StringTokenizerClassDemo.java

import
import

java.io.*; // la clase PrintWriter est aqu


java.util.*; // la clase StringTokenizer est aqu

/**
* Esta clase es una demostracin de la clase StringTokenizer
*
* @author
* version 1.0.0
*/
public class StringTokenizerClassDemo {
private static

PrintWriter

stdOut = new

PrintWriter(System.out, true);

/**
* Mtodo principal, muestra el uso de la clase StringTokenizer
*
* @param args no utilizado
*/

public static void

20:
21:
22:
23:
24:
25:
26:
27:
28:
29:

String

main(String[]

args)

str = "This string has five tokens";

// el delimitador predeterminado es la cadena "\t\n\r\f",


// por ejemplo, espacio en blanco
StringTokenizer tokenizer = new StringTokenizer(str);

stdOut.println("The input string:


stdOut.println();

30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:

" + str);

// imprime una lnea en blanco

// el siguiente bucle imprime cada palabra de la cadena,


// una por lnea
stdOut.println("The input string tokenized by " +
"the default delimiter (whitespace):");
int

i = 1;

while (tokenizer.hasMoreTokens()) {
stdOut.println("Token #" + i + ": " + tokenizer.nextToken());
++i;
}
stdOut.println();

// imprime una lnea en blanco

// el delimitador puede ser especificado como una


// cadena utilizando el siguiente constructor
tokenizer = new StringTokenizer(str, "i");

// este bucle imprimir las cuatro cadenas "Th",


// "s str", "ng has f", "ve tokens", una por lnea
stdOut.println("The input string tokenized by \"i\":");
i = 1;
while (tokenizer.hasMoreTokens()) {
stdOut.println("Token #" + i + ": " + tokenizer.nextToken());
++i;
}
}
}

Las Clases de Envoltura (Wrapper Classes)


Existen muchas clases en el API de Java y los programadores pueden definir an muchas
ms. Sin embargo, slo se tienen disponibles unos cuantos primitivos. En ciertos aspectos,
sera deseable que en los programas de Java pudiramos tratar todos los datos de la misma
manera consistente. Para hacer esto realidad, Java cuenta con clases que simulan a los tipos
primitivos. Para cada tipo primitivo existe una de estas clases. Estas clases constituyen en
conjunto las clases de envoltura:

java.lang.Byte

java.lang.Short
java.lang.Integer
java.lang.Long
java.lang.Character
java.lang.Float
java.lang.Double
java.lang.Boolean

Observe que los nombres de las clases de envoltura son muy similares a los nombres de sus
contrapartes primitivos. Una clase de envoltura contiene un campo simple cuyo tipo es el
primitivo correspondiente. Por ejemplo, la clase Integer contiene un campo de tipo int.
La siguiente aplicacin ilustra el uso de la clase de envoltura Integer.
1: public class WrapperConversion {
2:
3:
public static void main(String[] args) {
4:
5:
Integer objectValue = new Integer(100);
6:
7:
int intValue = objectValue.intValue();
8:
long longValue = objectValue.longValue();
9:
double doubleValue = objectValue.doubleValue();
10:
String stringValue = objectValue.toString();
11:
12:
System.out.println("objectValue: " + objectValue);
13:
System.out.println("intValue: " + intValue);
14:
System.out.println("longValue: " + longValue);
15:
System.out.println("doubleValue: " + doubleValue);
16:
System.out.println("stringValue: " + stringValue);
17:
}
18: }

Listado 2 WrapperConversion.java
Las clases de envoltura son parte del paquete java.lang y por lo tanto no necesita ser
importado explcitamente. La aplicacin crea un objeto de envoltura para almacenar un
entero y despus encuentra los valores long, double y String equivalentes. La siguiente
figura muestra el resultado de la ejecucin de WrapperConversion:

Figura 2 Ejecucin de WrapperConversion


Adems, las clases de envoltura proveen mtodos para convertir tipos primitivos a objetos
String y objetos String a tipos primitivos. Por ejemplo, Integer.toString(10)

convierte el valor entero 10 en el String "10" e Integer.parseInt("10") convierte el


String "10" al valor entero 10.
Podemos mejorar la aplicacin ProductInfo. El mtodo nextToken regresa un String,
que no es muy til cuando el token que ser extrado es un valor numrico como cantidad o
precio. Podemos utilizar la clase Integer para convertir el String que contiene la cantidad
en un valor entero; podemos usar la clase Double para convertir el String que contiene el
precio en un valor real (double). Ahora es posible calcular el valor total del producto.
1: import java.util.*;
2:
3: public class ProductValue {
4:
5:
public static void main(String[] args) {
6:
7:
String data = "Mini Discs 74 Minute (10-Pack)_5_9.00";
8:
9:
StringTokenizer tokenizer = new StringTokenizer(data, "_");
10:
11:
String name = tokenizer.nextToken();
12:
int quantity = Integer.parseInt(tokenizer.nextToken());
13:
double price = Double.parseDouble(tokenizer.nextToken());
14:
15:
System.out.println("Name: " + name);
16:
System.out.println("Quantity: " + quantity);
17:
System.out.println("Price: " + price);
18:
System.out.println("Total: "+ quantity * price);
19:
}
20: }

Listado 3 ProductValue.java
La siguiente figura muestra el resultado de la ejecucin de ProductValue:

Figura 3 Ejecucin de ProductValue

1.1.4 Consola E/S (I/O)

El Paquete java.io
Leyendo Valores Primitivos

El Paquete java.io
El paquete java.io tiene una gran cantidad de clases. Sin embargo, aqu slo estudiaremos
dos de ellas. La clase java.io.BufferedReader se utiliza para entrada. La clase
java.io.PrintWriter se utiliza para salida.
La siguiente es una plantilla para las clases que utilizan la consola E/S (entrada/salida):
1: import java.io.*; // contains BufferedReader and PrintWriter
2:
3: public class AnyClassUsingIO {
4:
5:
private static BufferedReader stdIn =
6:
new BufferedReader(new InputStreamReader(System.in));
7:
8:
private static PrintWriter stdOut =
9:
new PrintWriter(System.out, true);
10:
11:
private static PrintWriter stdErr =
12:
new PrintWriter(System.err, true);
13:
14:
/* other variables */
15:
16:
/*
methods
*/
17: }

Listado 1 Plantilla de una clase que utiliza ES


El modificador private lo estudiaremos posteriormente. En pocas palabras, este
modificador no permite que otras clases utilicen las variables stdIn, stdOut y stdErr.

es el flujo de entrada "estndar". Tpicamente, este flujo corresponde a


la entrada del teclado.
System.out es el flujo de salida "estndar". Tpicamente, este flujo corresponde a
la salida en pantalla.
System.err es el flujo de salida de "error". Tpicamente, este flujo corresponde a la
salida en pantalla.
System.in

se utiliza para desplegar la salida tpica y normal de los programas.


se usa para mostrar avisos y mensajes de error al usuario. Esto es slo una
convencin que facilita tanto a los programadores como a los usuarios identificar los
diferentes tipos de salida.

System.out
System.err

y System.err pudieran usarse para salida por s mismos. Sin embargo, es ms


conveniente incluir cada uno de ellos en un objeto PrintWriter. La clase PrintWriter
ofrece dos mtodos para imprimir: println y print. El primero agrega automticamente
un rengln a la salida, mientras que el segundo no lo hace. Los mtodos println y print
pueden tener muchos tipos de argumentos. Consideremos el siguiente ejemplo que utiliza
println:
System.out

1: import java.io.*;
2:
3: public class PrintlnDemo {
4:
5:
private static BufferedReader stdIn =
6:
new BufferedReader(new InputStreamReader(System.in));
7:
8:
private static PrintWriter stdOut =
9:
new PrintWriter(System.out, true);
10:
11:
private static PrintWriter stdErr =
12:
new PrintWriter(System.err, true);
13:
14:
public static void main(String[] args) {
15:
16:
stdOut.println("A line of output.");
17:
stdOut.println(5);
18:
stdOut.println(7.27);
19:
stdOut.println(true);
20:
21:
stdOut.println();
22:
}
23: }

Listado 2 PrintlnDemo.java
A continuacin se muestra la salida de PrintlnDemo:

Figura 1 Ejecucin de PrintlnDemo


Compara la salida de PrintlnDemo con la salida de PrintDemo, una clase que utiliza
print:
1: import java.io.*;
2:
3: public class PrintDemo
4:

5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23: }

private static BufferedReader stdIn =


new BufferedReader(new InputStreamReader(System.in));
private static PrintWriter stdOut =
new PrintWriter(System.out, true);
private static PrintWriter stdErr =
new PrintWriter(System.err, true);
public static void

main(String[]

args)

stdOut.print("A line of output.");


stdOut.print(5);
stdOut.print(7.27);
stdOut.print(true);
stdOut.println();
}

Listado 3 PrintDemo.java
A continuacin se presenta la salida de PrintDemo:

Figura 2 Ejecucin de PrintDemo


El operador de concatenacin String se utiliza frecuentemente para construir argumentos
para println y print:
stdOut.println("El nmero cinco:

" + 5);

El segundo argumento del constructor PrintWriter es un booleano que indica si debe o no


realizarse un vaciado (flushing) automtico. Cuando un programa produce salida para la
pantalla, esta salida no va directamente a la pantalla. Primero va a un rea de retencin
llamada bfer (buffer). Este bfer es vaciado en forma automtica cuando se llena y enva
sus contenidos directamente a la pantalla. Sin embargo, en la mayora de los casos las
instrucciones de salida no llenan el bfer y por lo tanto su salida permanece en el bfer en
vez de ser desplegada en pantalla. Puesto que es ms natural para el programador que la
salida ocurra inmediatamente, la clase PrintWriter cuenta con una caracterstica de
vaciado opcional y automtica llamada autovaciado (auto-flush). Cuando el segundo
argumento para el constructor PrintWriter es verdadero, se habilita el autovaciado y el
bfer es vaciado automticamente despus de cada llamada al mtodo printlnpero no
despus de las llamadas al mtodo print. El programador puede utilizar el mtodo flush

para vaciar el bfer despus de una llamada al mtodo print. El siguiente ejemplo ilustra
el uso del mtodo flush:
1: import java.io.*;
2:
3: public class Hello {
4:
5:
private static BufferedReader stdIn =
6:
new BufferedReader(new InputStreamReader(System.in));
7:
8:
private static PrintWriter stdOut =
9:
new PrintWriter(System.out, true);
10:
11:
private static PrintWriter stdErr =
12:
new PrintWriter(System.err, true);
13:
14:
public static void main(String[] args) throws IOException {
15:
16:
stdErr.print("Please enter you name on this line: ");
17:
stdErr.flush();
18:
19:
String input = stdIn.readLine();
20:
21:
stdOut.println("Hello " + input);
22:
}
23: }

Listado 4 Hello.java
La excepcin IOException ser estudiada en la pgina Objetos Excepcin. Observa que
stdErr, el flujo de salida estndar, se utiliza para desplegar mensajes. Si la llamada al
mtodo print que genera la salida del mensaje no es seguido por una llamada al mtodo
flush, el usuario probablemente no ver el mensaje adecuadamente. Usualmente, esto no
es deseable.
Para manejar las entradas, System.in puede usarse por s solo, pero sus capacidades son
limitadas ya que nicamente puede leer un carcter a la vez. Esto resultara fastidioso
cuando queremos leer toda una lnea de entrada. Encerrando System.in en un objeto
BufferedReader posibilita la lectura de lneas completas de entrada. El mtodo
BufferedReader empleado para este fin es readLine.
Una llamada al mtodo readLine ocasiona que el programa se detenga o que se bloquee
hasta que el usuario escriba una lnea de informacin. Cuando el usuario presiona la tecla
ENTER, la lnea es leda por el mtodo readLine y se regresa como String.
A continuacin se presenta la salida de Hello:

Figura 3 Ejecucin de Hello

Leyendo Valores Primitivos


No siempre deseamos que la entrada sea un String. Por ejemplo, en un programa podemos
pedir que se escriba un entero. Puede extraerse un entero de la entrada utilizando un mtodo
de las clases de envoltura (wrapper classes) para enteros. La siguiente lnea de cdigo
ilustra cmo se realiza esto:
int

value = Integer.parseInt(stdIn.readLine());

Utilizando el mtodo esttico parseInt de la clase Integer, la entrada, leda como un


String, es convertida a int de manera que sta pueda ser guardada en una variable int. La
mayora de las clases de envoltura tienen un mtodo similar para convertir (parse) una
cadena de caracteres: la clase Double tiene el mtodo parseDouble, mientras que la clase
Float cuenta con el mtodo parseFloat. La excepcin es la clase Boolean, que utiliza el
mtodo getBoolean. Para extraer un carcter de la entrada, se debe utilizar el mtodo
charAt para obtener el carcter en el String regresado por el mtodo readline. O bien,
se puede utilizar el mtodo read en vez del mtodo readLine. Sin embargo, si se desea
utilizar el mtodo read se requiere convertir el tipo (cast) antes de hacer la asignacin
debido a que el mtodo read regresa un int, no un char.
La siguiente clase utiliza un objeto StringTokenizer para leer tres enteros a partir de una
lnea de entrada:
1: import java.io.*;
2: import java.util.*;
3:
4: public class ReadThreeIntegers {
5:
6:
private static BufferedReader stdIn =
7:
new BufferedReader(new InputStreamReader(System.in));
8:
9:
private static PrintWriter stdOut =
10:
new PrintWriter(System.out, true);
11:
12:
private static PrintWriter stdErr =
13:
new PrintWriter(System.err, true);
14:
15:
public static void main(String[] args) throws IOException {
16:

17:
stdErr.print("Enter three integers on one line: ");
18:
stdErr.flush();
19:
20:
StringTokenizer tokenizer =
21:
new StringTokenizer(stdIn.readLine());
22:
23:
if (tokenizer.countTokens() != 3) {
24:
stdErr.println("Invalid input");
25:
} else {
26:
27:
int firstValue = Integer.parseInt(tokenizer.nextToken());
28:
int secondValue =
29: Integer.parseInt(tokenizer.nextToken());
30:
int thirdValue = Integer.parseInt(tokenizer.nextToken());
31:
32:
stdOut.println("First value: " + firstValue);
33:
stdOut.println("Second value: " + secondValue);
34:
stdOut.println("Third value: " + thirdValue);
35:
}
36:
}
}

Listado 5 ReadThreeIntegers.java
A continuacin se presenta la salida de ReadThreeIntegers:

Figura 4 Ejecucin de ReadThreeIntegers

1.1.5 Objetos Excepcin

Manejo de Excepciones
Objetos Excepcin
Clases de Excepciones
Excepciones Definidas por el Usuario
El Bloque try-catch
La Clusula throws
La Instruccin throw
Documentando Excepciones con Javadoc
Lecturas:

Requeridas:
o Barker, primera edicin, captulo 13 (pginas 3202).
o Barker, segunda edicin, captulo 13 (pginas 473
501).
Secuencia: Leer el libro de texto antes de leer esta pgina.

Manejo de Excepciones
Un cdigo robusto es un cdigo que responde apropiadamente a entradas invlidas y
condiciones ambientales inesperadas. Durante la ejecucin de un programa pueden ocurrir
muchas fallas o eventos excepcionales que interrumpen el flujo normal de un
programa. Por ejemplo, un programa puede tratar de abrir un archivo que no existe o dividir
un nmero entre cero. Un cdigo robusto maneja adecuadamente las fallas: contina la
ejecucin a pesar del problema o termina la ejecucin despus de desplegar un mensaje de
error.
En la programacin tradicional, debes incluir instrucciones condicionales para detectar y
manejar fallas en los programas. Frecuentemente, este cdigo es difcil de leer y mantener.
Por ejemplo, el siguiente es el pseudocdigo de un mtodo que lee un entero a partir de la
entrada estndar.
int readInteger () {
Lee una cadena de la entrada estndar
Convierte la cadena en un valor entero
Regresa el valor entero
}

Este pseudocdigo ignora las fallas que puedan ocurrir:

La cadena de caracteres no puede ser leda de la entrada estndar. Por ejemplo, la


entrada estndar puede ser un archivo daado.

La cadena de caracteres no contiene un entero. Por ejemplo, el usuario puede


introducir "2r" en vez de "25".

Para hacer que tu mtodo sea robusto, debes aadir cdigo para detectar y manejar las fallas
potenciales:
int readInteger () {
while (true) {
lee una cadena de la entrada estndar;
if (la lectura de la entrada estndar falla) {
maneja el error de la entrada estndar;
} else {
convierte la cadena en un valor entero;
if (la cadena no contiene un entero) {
maneja el error de formato de nmero invlido;
} else {
regresa el valor entero;
}
}
}
}

El manejo de excepciones es un mecanismo que permite que las fallas sean manejadas fuera
del flujo normal del cdigo. El cdigo resultante es claro, fcil de leer y fcil de mantener.
El siguiente es un pseudocdigo que utiliza manejo de excepciones:
int readInteger () {
while (true) {
try {
lee una cadena a partir de la entrada estndar;
convierte la cadena en un valor entero;
regresa el valor entero;
} catch (la lectura de la entrada estndar fall) {
maneja el error de entrada estndar;
} catch (la cadena no contiene un entero) {
maneja el error de formato de nmero invlido;
}
}
}

Con el manejo de excepciones, el flujo normal del cdigo es especificado en el cuerpo de


un bloque try y cada falla es manejada en un bloque catch que se encuentra separado del
flujo normal del cdigo.

Objetos Excepcin
En Java, una excepcin es un objeto que describe una situacin anormal. Un objeto
excepcin (exception object) contiene la siguiente informacin:

El tipo de excepcin
Una pila de llamadas (call stack) que indica donde ocurri la excepcin

Una cadena de caracteres con informacin adicional sobre la excepcin

Cuando ocurre una situacin anormal, un mtodo puede crear un objeto excepcin y
despus lanzarlo (throw). Si el mtodo que hace la llamada no est preparado para atrapar
(catch) el objeto excepcin, ste lanza el objeto excepcin al mtodo que lo llama y as
sucesivamente. El objeto excepcin pasa a travs de la secuencia de mtodos que han sido
llamados (la pila de llamadas) hasta que es atrapado. El mtodo que atrapa el objeto
excepcin utiliza la informacin que se encuentra en el objeto para manejar la excepcin.
Cuando un mtodo lanza una excepcin, ninguna de las instrucciones restantes en dicho
mtodo son ejecutadas. Si ninguno de los mtodos de la pila de llamadas atrapa la
excepcin y el mtodo que se encuentra en cima de la pila es main, el programa despliega,
en el flujo de error estndar, un mensaje que identifica la excepcin y finaliza. Para
prevenir la terminacin prematura de un programa, debes incluir bloques try-catch que
permitan que el programa se recupere de las fallas.
La siguiente figura ilustra cmo se lanzan y se atrapan las excepciones.

Figura 1 Lanzando y atrapando un objeto de excepcin

La siguiente clase contiene el cdigo de la secuencia de eventos ilustrada en la Figura 1.


(Las instrucciones que crean excepciones y que las manejan sern descritas posteriormente
en esta pgina).
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:

/**
* Esta clase demuestra cmo se lanzan y se atrapan excepciones.
*
* @author
* @version 1.0.0
*/
public class ExceptionDemo {
/**
* Llama a methodA
*
* @param args no utilizado
*/
public static void main(String[] args)

methodA();
System.out.println("MethodA passed");
}
/**
* Llama a

methodB. Si ocurre una excepcin; la atrapa, reporta

el
* error y termina el programa.
*/
public static void methodA() {
try {
methodB();
System.out.println("MethodB passed");
} catch (Exception e) {
e.printStackTrace();
System.exit(1);
}
}
/**
* Llama a methodC. Si ocurre una excepcin, la lanza al mtodo
que
* hizo la llamada.
*
* @throws Exception cuando methodC es llamado.
*/
public static void methodB() throws Exception {
methodC();
System.out.println("MethodC passed");
}
/**
* Llama a methodD. Si ocurre una excepcin, la lanza al mtodo
que

53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:

* hizo la llamada.
*
* @throws Exception cuando ethodD es llamado.
*/
public static void methodC() throws Exception

methodD();
System.out.println("MethodD passed");
}
/**
* Lanza una excepcin
*
* @throws Exception cada vez que methodD es llamado.
*/
public static void methodD() throws Exception {
throw new

Exception("This is an Exception Message");

}
}

Listado 1 ExceptionDemo.java
En la clase ExceptionDemo, el mtodo main llama a methodA, methodA llama a methodB,
methodB llama a methodC y methodC llama a methodD. El ltimo mtodo de la secuencia,
methodD, crea un nuevo objeto de excepcin y lo lanza al methodC. La excepcin pasa por
methodC y methodB hasta que es atrapado por methodA. methodA maneja la excepcin
imprimiendo un rastro de la pila y terminando el programa. El rastro de la pila muestra la
secuencia de mtodos que fueron llamados antes de que la excepcin fuera lanzada. La
siguiente figura muestra la consola de salida al ejecutar ExceptionDemo:

Figura 2 Ejecucin de ExceptionDemo.java


La consola despliega la informacin almacenada en el objeto Exception. Esta informacin
contiene:

El nombre de la excepcin: java.lang.Exception


El mensaje de la excepcin: This is an Exception Message
El rastro de la pila (stack trace), el cual es muy til al depurar las excepciones.
Muestra la secuencia de mtodos que fueron llamados antes de que la excepcin
fuera lanzada.

Observa que las instrucciones de imprimir que se encuentran en methodB y methodC nunca
fueron ejecutadas.
Los objetos excepcin cuentan con un grupo de mtodos comunes. Incluyen:

String getMessage(). Obtiene el argumento que fue pasado al constructor del objeto
de excepcin.

String toString(). El nombre de la excepcin (su tipo), seguido por dos puntos ( : ),
seguidos por el String regresado por el mtodo getMessage.

void printStackTrace(). Este mtodo despliega, en el flujo de error estndar, el


String regresado por el mtodo toString, seguido por la informacin que muestra
dnde fue lanzada la excepcin. La informacin incluye una lista de todos los
mtodos que fueron llamados antes de que ocurriera la excepcin.

Clases de Excepciones
Los objetos excepcin son instancias de clases que descienden de la clase Throwable.
Throwable tiene dos subclases: Error y Exception.

La clase Error es utilizada para problemas serios, donde es poco probable que una
aplicacin se recupere. Un ejemplo es el error "out of memory" (sin memoria).
La clase Exception es utilizada para las condiciones anormales que una aplicacin
puede esperar que sean manejadas.

Java divide las excepciones en dos categoras: las excepciones verificadas (checked
exceptions) y las excepciones no verificadas (unchecked exceptions). Las excepciones que
no son "verificadas" por el compilador son llamadas excepciones no verificadas; las
excepciones que son "verificadas" por el compilador, son llamadas excepciones verificadas.
El compilador no compilar un archivo si contiene un mtodo donde pueda ocurrir una
excepcin verificada y el mtodo no maneje la excepcin verificada en un bloque catch o
lo enliste en el encabezado del mtodo. Las clases RuntimeException, Error y sus
subclases son excepciones no verificadas. Todas las dems clases de excepcin son
excepciones verificadas.

Figura 3 Jerarqua de excepciones

Excepciones Definidas por el Usuario


Puede definirse nueva clase de excepcin verificada extendiendo la clase Exception; una
nueva clase de excepcin no verificada puede definirse extendiendo la clase
RuntimeException. La siguiente clase define una excepcin verificada para un error fuera
de rango:
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:

/**
* Lanzada cuando ocurre un error fuera de rango.
*
* @author nombre del autor
* @version 1.0.0
*/
public class OutOfRangeException extends Exception

/**
* Construye una nueva instancia de
<code>OutOfRangeException</code>.
*/
public OutOfRangeException() {
}
/**
* Construye una nueva instancia de
<code>OutOfRangeException</code>
* que incluye una explicacin.
*
* @param message Informacin adicional sobre esta excepcin.
*
Puede ser nulo.
*/
public OutOfRangeException(String message) {
super(message);
}
}

Listado 2 OutOfRangeException.java

El segundo constructor es utilizado cuando hay informacin disponible sobre la excepcin.

El Bloque try-catch
Si un mtodo elige manejar una excepcin, debe tener un bloque try-catch. Un bloque
try delimita el cdigo que puede lanzar una excepcin. Un bloque try tiene el siguiente
aspecto:
try

{
// cdigo que puede lanzar excepciones

A un bloque try le siguen uno o ms bloques catch. Un bloque catch tiene el siguiente
aspecto:
catch (TipoExcepcin

e)

// cdigo que maneja la excepcin


}
TipoExcepcin es el tipo, o el nombre de la clase de la excepcin que el bloque catch
manejar. Observa que un bloque catch se parece a un encabezado de mtodo porque toma
un argumento.

Pueden aparecer muchos bloques catch despus de un bloque try, cada uno atrapando una
excepcin diferente. Cuando se lanza una excepcin, cada bloque catch es examinado,
comenzando con el bloque catch que se encuentra inmediatamente despus del bloque
try. El tipo de la excepcin lanzada es comparado con el tipo del argumento del bloque
catch. Cuando encuentra una coincidencia, es ejecutado el cuerpo del bloque catch que
coincide. Entonces, la ejecucin sigue despus del ltimo bloque catch. Si ningn bloque
catch coincide, la excepcin se deja pasar a la pila de llamadas.
Considera el siguiente cdigo. La clase IntegerReader tiene un mtodo llamado
readInteger que lee un entero de la entrada estndar:
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:

import java.io.*;
/**
* Esta clase provee un mtodo que lee un entero de la
* entrada estndar.
*
* @author
* @version 1.0.0
*/
public class IntegerReader {
private static BufferedReader stdIn =
new BufferedReader(new InputStreamReader(System.in));
private static PrintWriter

stdErr =

16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55: }

new PrintWriter(System.err, true);


private static PrintWriter stdOut =
new PrintWriter(System.err, true);
/**
* Prueba el mtodo <code>readInteger</code>.
*
* @param args no utilizado.
*/
public static void main (String[] args) {
stdOut.println("The value is: " + readInteger());
}
/**
* Lee un entero de la entrada estndar.
*
* @return regresa el valor <code>int</code>.
*/
public static int readInteger() {
do

{
try

{
stdErr.print("Enter an integer >
stdErr.flush();

");

return Integer.parseInt(stdIn.readLine());
} catch (IOException ioe)
ioe.printStackTrace();
System.exit(1);

// Termina el programa

} catch (NumberFormatException nfe) {


stdErr.println("Invalid number format");
}
while (true);

Listado 3 IntegerReader.java
El mtodo BufferedReader.readLine que se encuentra en la lnea 43 puede lanzar una
excepcin de tipo IOException. El bloque catch de la lnea 45 maneja la excepcin
IOException desplegando, en el flujo de error estndar, la pila de llamadas y terminando el
programa. El mtodo Integer.parseInt de la lnea 43 puede lanzar una excepcin de tipo
NumberFormatException. El bloque catch de la lnea 50 maneja la excepcin
NumberFormatException desplegando, en el flujo de error estndar, el mensaje "Invalid
number format" y la ejecucin contina; es decir, se le da otra oportunidad al usuario de
introducir un entero.
El argumento de un bloque catch puede ser engaoso. Por ejemplo, el siguiente bloque
atrapar una excepcin IOException; tambin atrapar una excepcin

catch

FileNotFoundException
FileNotFoundException

una

porque
las
clases
y EOFException son subclases de la clase IOException. Ver
EOFException

Figura 3.
catch (IOException

e)

// cdigo para manejar IOException, FileNotFoundException y


EOFException
}

La Clusula throws
Si una excepcin verificada puede ocurrir en un mtodo y dicho mtodo no tiene un bloque
catch para manejar la excepcin verificada, entonces sta debe ser declarada en el
encabezado del mtodo utilizando una clusula throws. Por ejemplo, si puede ocurrir una
excepcin de tipo IOException en un mtodo readInteger y readInteger no lo maneja,
entonces readInteger debe tener el siguiente encabezado:
public int readInteger() throws IOException {
}

Si el mtodo readInteger no enlista IOException en su clusula throws, la compilacin


fallar y presentar un error sobre las excepciones verificadas. Las excepciones no
verificadas pueden ser enlistadas en una clusula throws, pero el compilador no lo
requiere.
En el siguiente cdigo, ni el mtodo readInteger ni el mtodo main( ) atrapan la
excepcin IOException; por lo tanto, ambos declaran IOException en sus clusulas
throws. Cuando un mtodo main lanza una excepcin IOException, el objeto de
excepcin es pasado a la Mquina Virtual de Java (Java Virtual Machine o JVM). La JVM
despliega la informacin de la excepcin y termina el programa.
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:

import java.io.*;
/**
* Esta clase provee un mtodo que lee un entero de la
* entrada estndar.
*
* @author
* @version 1.0.0
*/
public class IntegerReaderThrowsException {
private static BufferedReader stdIn =
new BufferedReader(new InputStreamReader(System.in));
private static PrintWriter stdErr =
new PrintWriter(System.err, true);

18:
private static PrintWriter stdOut =
19:
new PrintWriter(System.err, true);
20:
21:
/**
22:
* Prueba el mtodo <code>readInteger</code>
23:
*
24:
* @param args no utilizado
25:
* @throws IOException si hay error al leer de la entrada
26: estndar.
27:
*/
28:
public static void main (String[] args) throws IOException {
29:
30:
stdOut.println("The value is: " + readInteger());
31:
}
32:
33:
/**
34:
* Lee un entero de la entrada estndar.
35:
*
36:
* @return regresa el valor <code>int</code>.
37:
* @throws IOException si hay error al leer de la entrada
38: estndar.
39:
*/
40:
public static int readInteger() throws IOException {
41:
42:
do {
43:
try {
44:
stdErr.print("Enter an integer> ");
45:
stdErr.flush();
46:
47:
return Integer.parseInt(stdIn.readLine());
48:
49:
} catch (NumberFormatException nfe) {
50:
stdErr.println("Invalid number format");
51:
}
52:
} while (true);
}
}

Listado 4 IntegerReaderThrowsException.java

La Instruccin throw
Los mtodos definidos por el usuario tambin pueden lanzar excepciones. Para lanzar una
excepcin, utilizan la palabra clave throw, seguida por un objeto excepcin. Por ejemplo:
throw

new

OutOfRangeException();

El objeto excepcin es creado como cualquier otro objeto, utilizando el operador new y un
constructor. La siguiente sentencia utiliza el constructor de la excepcin
OutOfRangeException que acepta un argumento de tipo String.
throw

new

OutOfRangeException("Not a valid number");

Considera la clase PositiveInteger que envuelve un valor entero positivo. Tiene un


constructor y mtodos para inspeccionar y modificar el valor entero positivo.
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:

import java.io.*;
/**
* Envuelve un valor entero positivo.
*
* @author
* @version 1.0.0
*/
public class PositiveInteger {
private static BufferedReader stdIn =
new BufferedReader(new InputStreamReader(System.in));
private static PrintWriter stdErr =
new PrintWriter(System.err, true);
private static PrintWriter stdOut =
new PrintWriter(System.err, true);
private int value;
/**
* Prueba el mtodo <code>readInteger</code>
*
* @param args no utilizado
* @throws IOException si hay error al leer de la entrada
estndar.
*/
public static void main(String[] args) throws IOException
PositiveInteger object;
do

{
try

{
stdErr.print("Enter an integer> ");
stdErr.flush();
int value = Integer.parseInt(stdIn.readLine());
object = new PositiveInteger(value);
break;

} catch (NumberFormatException nfe) {


stdErr.println("Invalid number format");
} catch (OutOfRangeException ore) {
stdErr.println(ore.getMessage());
}
while (true);

stdOut.println("The value is: " + object.getValue());


}
/**

54:
* Construye un objeto <code>PositiveInteger</code> con el
55:
* valor especificado por el argumento.
56:
*
57:
* @param initialValue un entero. El valor debe ser positivo.
58:
* @throws OutOfRangeException si el valor es negativo.
59:
*/
60:
private PositiveInteger(int initialValue) throws
61: OutOfRangeException {
62:
63:
if (initialValue < 0) {
64:
65:
throw new OutOfRangeException("Number not positive");
66:
67:
} else {
68:
this.value = initialValue;
69:
}
70:
}
71:
72:
/**
73:
* Regresa el nmero positivo
74:
*
75:
* @return regresa el valor
76:
*/
77:
public int getValue() {
78:
79:
return this.value;
80:
}
81:
82:
/**
83:
* Modifica el nmero positivo.
84:
*
85:
* @param newValue el nuevo entero. El valor debe ser positivo.
86:
* @throws OutOfRangeException si el nuevo valor es negativo.
87:
*/
88:
private void setValue (int newValue) throws OutOfRangeException {
89:
90:
if (newValue < 0) {
91:
92:
throw new OutOfRangeException("Number not positive");
93:
94:
} else {
95:
this.value = newValue;
96:
}
}
}

Listado 5 PositiveInteger.java
En esta clase, tanto el constructor como el mtodo setValue crean y lanzan una excepcin
de tipo OutOfRangeException cuando el valor del argumento no es positivo (lneas 59 y
86). Observa que la excepcin OutOfRangeException es atrapada en el mtodo main que
se encuentra en la lnea 44.

Documentando Excepciones con Javadoc

La etiqueta Javadoc para una excepcin es la etiqueta @throws tambin puede emplearse
la etiqueta @exception. El comentario Javadoc para un mtodo debe tener una etiqueta
@throws por cada excepcin verificada que el mtodo pudiera lanzar. Tambin puede tener
etiquetas @throws para las excepciones no verificadas, pero no es necesario. El comentario
Javadoc no debe tener una etiqueta @throws para las excepciones atrapadas y manejadas
por el mtodo. Utiliza los siguientes lineamientos para documentar excepciones:

Cuando el mtodo lanza ms de una excepcin, cada excepcin debe estar


documentada en una lnea diferente y debe ser enlistada alfabticamente.
Ubica las etiquetas @throws despus de las etiquetas @param y @return.
Las etiquetas @throws deben describir la(s) situacin(es) que causarn la excepcin.

1.1.6 Convenciones de Cdigo


Lecturas:

Requerida:
o Software de Java, Sun Microsystems, Inc, Code
Conventions for the Java Programming Language
(Convenciones de Cdigo para el Lenguaje de
Programacin Java). Este documento contiene las
convenciones estndar que Sun Microsystems sigue y
recomienda a los dems. Cubre nombres de archivos,
organizacin de archivos, sangrado del cdigo,
comentarios, declaraciones, instrucciones, espacios
en blanco, convenciones de nombres y prcticas de
programacin. Tambin incluye un ejemplo de
cdigo.

Uno de los objetivos de este curso es que aprendas a utilizar un buen estilo de
programacin. Un buen estilo de programacin es un componente importante de la prctica
profesional de desarrollo de software.

El producto de tu trabajo profesional de programacin ser tu cdigo fuente. Al


igual que cualquier otro producto comercial, debes asegurarte de que tu cdigo tiene
la mayor calidad posible.

Tu cdigo existir por un tiempo largo. Debes asegurarte que tu cdigo sea legible y
fcil de entender para los dems. Un cdigo difcil de entender podra ser descartado
y reescrito.

Como parte de un equipo de desarrollo, debes esforzarte por lograr la consistencia


de entre tu cdigo y el cdigo de tus compaeros de equipo.

Tu estilo de programacin generalmente refleja el tipo de programador que eres. Un


cdigo claro y bien organizado usualmente refleja un programador bien organizado
y con ideas claras.

Adems, un buen estilo de programacin hace el cdigo ms fcil de rastrear, depurar y


clasificar. Existen muchas opiniones diferentes sobre lo que constituye un buen estilo. Cada
organizacin definir sus propias convenciones de cdigo. Sin embargo, es posible definir
algunos principios bsicos:

Las convenciones de cdigo deben asegurar que la estructura lgica del cdigo es
fcil de seguir. Por ejemplo, las instrucciones en el cuerpo de un bucle deben
sangrarse un nivel.

Las convenciones de cdigo deben mejorar la legibilidad. Por ejemplo, el nombre


de los identificadores debe seguir las convenciones de nombres para que sea fcil
reconocer las constantes, las clases, los mtodos y las variables.

Las convenciones de cdigo deben prevenir la introduccin de errores accidentales.


Por ejemplo, las llaves deben delimitar el cuerpo de un bucle an cuando el cuerpo
contenga una sola instruccin. Esto previene el error lgico que ocurre cuando un
programador aade una instruccin al cuerpo del bucle sin agregar un conjunto de
llaves.

La eleccin de un conjunto de convenciones sobre otra puede parecer completamente


arbitraria. Elegimos utilizar las convenciones de cdigo de Sun porque son reconocidas por
una comunidad muy grande de desarrolladores profesionales.
Como nota final, las convenciones de cdigo no deben ser aplicadas despus de escribir tu
cdigo. El nombre de una variable debe seguir la convencin de nombres al ser definido.
Una lnea de cdigo debe una sangra apropiada al momento de ser escrita. Una estructura
de control nunca debe escribirse sin llaves. Esto representa trabajo extra al principio, pero
en realidad es tiempo bien gastado porque tu cdigo ser mucho ms fcil de depurar!

1.1.7 Javadoc

Javadoc y el Programa Javadoc


Recomendaciones para la Documentacin
Sintaxis de Javadoc

Lecturas:

Requeridas:
o Java Software, Sun Microsystems, Inc., How to Write Doc
Comments for the Javadoc Tool (Cmo Escribir
Comentarios Doc para la Herramienta Javadoc). Este
documento describe las convenciones utilizadas para
escribir comentarios Javadoc en Sun.

Secuencia: Lee las secciones "Formato de un Comentario


Doc," "Descripciones," "Una Gua de Estilo" y
"Convenciones de Etiquetas".

Javadoc y el Programa Javadoc


Adems de los estilos de comentarios de una sola lnea y de mltiples lneas que existen en
Java, est disponible un nuevo y funcional estilo. Se llama Javadoc. Los comentarios
Javadoc son escritos por el programador y despus procesados por el programa Javadoc. El
programa analiza los comentarios Javadoc y la estructura general del programa,
produciendo un conjunto de pginas HTML que sirven como la documentacin del
programa.

Recomendaciones para la Documentacin


Resulta mucho ms costoso el mantenimiento que el desarrollo del software. El trabajo de
mantenimiento se simplifica en la medida en que el software est bien documentado.
Muchos programadores documentan el programa despus de terminarlo. Esto es un error.
La documentacin debe realizarse a la par de la codificacin. Dejarlo para despus
representa una tarea muy difcil al final que traer casi siempre como consecuencia un
programa mal documentado.
El uso de Javadoc mejora la documentacin. La documentacin de todo el API de Java est
en formato Javadoc. Tambin al emplear Javadoc se disminuye en gran medida la
necesidad de utilizar comentarios convencionales en el cdigo fuente.

Sintaxis de Javadoc
Los comentarios en Javadoc inician con la secuencia "diagonal-asterisco-asterisco" (/**) y
cierran con una secuencia "asterisco-diagonal" (*/), ya sea en una o ms lneas. Cuando

estos delimitadores se extienden a ms de una lnea, cada lnea interna comienza con un
solo asterisco ( * ), sangrado de tal manera que est alineado con el primer asterisco que
inici el comentario. La secuencia de cierre tambin debe alinearse con el primer asterisco
de la secuencia de apertura. El texto del comentario comienza un espacio despus del
asterisco que comienza la lnea. La estructura de varias lneas se muestra enseguida:
/**
* body text
* body text
* body text
*/

La estructura de una sola lnea, se muestra a continuacin:


/** body text */

La mayora de los comentarios en Javadoc incluyen etiquetas Javadoc. Estas etiquetas


comienzan con el smbolo "arroba" ( @ ), seguido del nombre de la etiqueta. Cada etiqueta
describe un atributo particular de la entidad que se est comentando. Existen muchas
etiquetas. A continuacin se presenta un subconjunto formado con las etiquetas ms
comunes:
Etiquetas de Javadoc Comunes
1.
2.
3.
4.
5.

@author nombre del programador; utilizado para clases


@version versin del programa; utilizado para clases
@param descripcin de un parmetro formal; utilizado para mtodos y constructores
@return descripcin de un valor de retorno; utilizado para mtodos
@exception (o @throws) descripcin de una excepcin; utilizado para mtodos y

constructores
6. @see referencia a una entidad relacionada; utilizada para clases, constructores, mtodos
y campos de datos

Cuando se utilizan diferentes etiquetas en un comentario Javadoc, deben aparecer en el


orden mencionado anteriormente.
Los comentarios Javadoc pueden contener etiquetas HTML. Utiliza etiquetas HTML
cuando sea apropiado.
El siguiente ejemplo ilustra el uso de varias etiquetas:
1:
2:
3:
4:
5:
6:
7:

/**
* <p>Esta clase almacena el valor de dos enteros.</p>
* <p>Esta clase es escrita con el propsito de hacer una demostracin
de los
* comentarios Javadoc. Los comentarios Javadoc para las clases,
pueden ser
* separados en dos partes: una parte de descripcin y una parte de
etiquetas.

8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:

* Esta es la parte de descripcin. Las partes deben estar separadas


por una
* lnea de comentario vaca.</p>
* <p>Tambin, no debe lneas entre el final del comentario Javadoc
* y el inicio de la entidad que describe.</p>
*
* @author Lily Hou
* @author Sean Bufano
* @version 1.0.0
*/
public class TwoInts {
private int
private int

first;
second;

/**
* Inicializa ambos enteros en <code>0</code>.
*/
public TwoInts() {
this.first = 0;
this.second = 0;
}
/**
* Inicializa ambos enteros con los argumentos.
*
* @param initialFirst valor al cual es inicializado el campo
*
<code>first</code>
* @param initialSecond valor al cual es inicializado el campo
*
<code>second</code>
*/
public TwoInts(int initialFirst, int initialSecond) {
this.first = initialFirst;
this.second = initialSecond;
}
/**
* Calcula la suma de dos enteros.
*
* @return regresa la suma de dos enteros
*/
public int sum() {
return

this.first + this.second;

}
/**
* Incrementa el campo <code>first</code> por el argumento.
*
* @param value el valor por el cual se incrementar el campo
*
<code>first</code>
*/
public void addToFirst(int value) {
this.first += value;

57:
58: }
59:
60:
61:
62:
63:

Listado 1 TwoInts.java

Una vez que los comentarios Javadoc estn completos, emplea el comando javadoc para
generar la documentacin del programa. La siguiente figura ilustra la sintaxis del comando
javadoc:

Figura 1 Comando Javadoc

Esto generar una coleccin de pginas HTML que sern la documentacin de la clase
TwoInts. Esta coleccin puede visualizarse en un navegador Web. Abre el archivo
index.html que se encuentra en el directorio que almacena el archivo fuente TwoInts.
Este curso solamente requiere comentarios Javadoc para las entidades public y protected
clases, constructores, mtodos y variables precedidas por las palabras clave public o
protected.

1.1.8 Depurando

El Proceso de Depuracin
Instrucciones de Imprimir
El Depurador

El Proceso de Depuracin
Depuracin (debugging) es el proceso de identificar un error y corregirlo. Una depuracin
efectiva no se realiza de manera natural. Para muchos desarrolladores, la depuracin
consume muchas horas. El tiempo necesario para encontrar un error y corregirlo depender
de tu competencia en depuracin. El uso de estrategias ad hoc, como tratar de adivinar por
ejemplo, puede hacer que desperdicies grandes cantidades de tiempo sin obtener ningn
resultado. El proceso de identificar un error debe ser metdico y no debe comenzar hasta
que el desarrollador ha entendido bien el cdigo del programa. En esta pgina,
describiremos una tcnica de depuracin y presentaremos algunas herramientas para
depuracin. En la pgina Depurando con Eclipse, utilizaremos la tcnica descrita aqu para
depurar un programa.
La siguiente figura muestra un resumen de una efectiva tcnica para depurar un programa:

Figura 1 Proceso de Depuracin

1. Crea un caso de prueba: para diagnosticar y corregir un error, debes ser capaz de
reproducirlo. Para ahorrar tiempo en las pruebas, crea un caso de prueba pequeo
que reproduzca el error. Implementa este caso de prueba en una clase separada o en
el mtodo main del programa que ser depurado.
2. Ubica el cdigo que causa el error. Un buen lugar para comenzar la bsqueda es el
caso de prueba mismo: encuentra la lnea de cdigo en el caso de prueba donde
aparece el error. Esta lnea te dirigir al cdigo que contiene el error. Una vez que
hayas ubicado el cdigo, estudia sus estructuras de control y sus variables.
Determina cmo se espera que se comporte el cdigo y qu valores se espera que
contengan las variables.
3. Repasa el cdigo lnea por lnea. Presta particular atencin a las instrucciones que
asignen un nuevo valor a una variable relevante. Identifica el cdigo que causa el
error.
4. No asumas que el error es causado por un problema de lgica en esta parte del
cdigo. Puede ser causado por datos errneos originados en otras reas del cdigo.
Si es as, localiza el cdigo donde se originaron los datos errneos y repite la
operacin a partir del paso 2.
5. Repara el cdigo:
o La correccin no debe "esconder", "maquillar" o "reprimir" el error.
o La correccin no debe introducir nuevos errores. El desarrollador debe
entender cmo la correccin afecta otras partes del cdigo porque una
correccin puede tener efectos colaterales inesperados.
o Resulta prudente revisar el cdigo circundante. En muchos casos, hay ms
de un error en la misma parte del cdigo.

Instrucciones de Imprimir
El uso de instrucciones de imprimir es una tcnica comn. Est disponible en muchos
idiomas y es fcil de implementar. Las instrucciones de imprimir se utilizan para desplegar
informacin importante mientras se ejecuta el cdigo. La informacin puede incluir:

Los mtodos llamados


El valor de los parmetros
El valor del las variables de control de un bucle
El valor de las variables locales
El valor de las variables de instancia

El siguiente ejemplo ilustra el uso de instrucciones de imprimir para rastrear la ejecucin de


una aplicacin. En esta aplicacin, la clase SumCalculator solicita un rango al usuario y
despus despliega la suma de los enteros que se encuentran en dicho rango. El mtodo
sumRange contiene las instrucciones de imprimir que rastrean la ejecucin del cdigo del
mtodo. La primera instruccin de imprimir despliega el nombre del mtodo y el valor de

sus argumentos. La segunda instruccin de imprimir despliega los valores de las variables
locales.
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:

import java.io.*;
/**
* Esta aplicacin despliega la suma de enteros en el rango
* especificado.
*
* @author
* @version 1.0.0
*/
public class SumCalculator {
private static BufferedReader stdIn =
new BufferedReader(new InputStreamReader(System.in));
private static PrintWriter stdOut =
new PrintWriter(System.out, true);
private static PrintWriter stdErr =
new PrintWriter(System.err, true);
/**
* Regresa la suma de enteros en el rango
* especificado [inferior,superior].
*
* @param lower el lmite inferior.
* @param upper el lmite superior.
* @return regresa la suma de enteros en el rango
*
especificado [inferior,superior].
*/
public static int sumRange(int lower, int upper) {
stdErr.println(" sumRange called. lower:" + lower
+ " upper:" + upper);
int

total = 0;

for (int i = lower ; i <= upper; i++) {


total += i;
stdErr.println("
for loop, i:" + i + "
+ total);
}

total:"

return total;
}
/**
* Despliega la suma de enteros en el rango especificado.
*
* @param args no usado.
*/
public static void main(String[] args) {
int lower;

54:
int upper;
55:
56:
try {
57:
stdErr.print("lower limit: ");
58:
stdErr.flush();
59:
lower = Integer.parseInt(stdIn.readLine());
60:
stdErr.print("upper limit: ");
61:
stdErr.flush();
62:
upper = Integer.parseInt(stdIn.readLine());
63:
stdOut.println("The result is: " + sumRange(lower,
64: upper));
65:
} catch (NumberFormatException nfe) {
66:
stdErr.println(nfe);
67:
} catch (IOException ioe) {
68:
stdErr.println(ioe);
69:
}
70:
71:
}
}

Listado 1 SumCalculator
Cuando la aplicacin es ejecutada, despliega el nombre del mtodo, los argumentos del
mtodo y los valores de la variable de control del bucle y de la variable local total en cada
iteracin del bucle. Toma en cuenta que este cdigo no tiene ningn error. Slo estamos
demostrando cmo pueden ser utilizadas las instrucciones de imprimir para rastrear la
ejecucin de un programa.

Figura 2 Ejecucin de SumNumbers

El Depurador
Un depurador (debugger) es una herramienta conveniente para localizar la fuente de los
errores. Un depurador te permite ejecutar una lnea a la vez y observar su efecto en las
variables del programa. Existen muchos depuradores de Java disponibles:

Ambientes integrados de desarrollo (Integrated Development Environments o IDE),


tales como Eclipse, Sun ONE Studio, Borland JBuilder y BlueJ, contienen sus
propios depuradores.

Depuradores grficos autnomos, tales como JSwat y DDD

Depuradores basados en texto, tales como Sun jdb

Casi todos los depuradores tienen las siguientes capacidades:


1. Establecer puntos de ruptura. Un punto de ruptura (breakpoint) es un marcador en el
cdigo que indica que el depurador puede detener la ejecucin del programa antes
de ejecutar una cierta instruccin.
2. Recorrer un programa paso a paso. Una vez que un punto de ruptura detienen la
ejecucin de un programa, el depurador provee el siguiente conjunto de comandos
para continuar la ejecucin.
o resume. Continuar con la ejecucin, no solamente paso a paso.
o step into. Ejecutar la lnea actual. Si la lnea actual llama a un mtodo, el
depurador "pasa adentro de" el mtodo, es decir, la ejecucin se mueve al
mtodo llamado y se detiene antes de la primera lnea del mtodo llamado.
o step over. Ejecuta la lnea actual. Si la lnea actual llama a un mtodo, el
depurador "pasa sobre" el mtodo, es decir, el mtodo es ejecutado y la
ejecucin se detiene antes de que la siguiente lnea del mtodo actual.
o step return. Se ejecuta hasta que el mtodo actual es completado y regresa al
mtodo que hace la llamada. La ejecucin se detiene antes de la siguiente
lnea del mtodo que hace la llamada.
3. Examinar los datos. El depurador puede desplegar los valores de las variables del
mtodo y la clase actuales. Si una variable es un objeto compuesto que contiene
mltiples elementos, el usuario puede "abrir" el objeto e inspeccionar el valor de
cada elemento.
4. Rastreo de la pila. Cuando un punto de ruptura es alcanzado y la ejecucin
suspendida, el depurador puede desplegar la secuencia de los mtodos llamados. El
usuario puede examinar los valores de las variables locales que se encuentran en los
mtodos llamados.
Como puedes ver, un depurador es una herramienta poderosa para monitorear la ejecucin
de un programa e identificar la fuente de errores. Sin embargo, un depurador es solamente
una herramienta. La habilidad para identificar y eliminar errores depende, en ltima
instancia, de la competencia del programador.

1.1.9 Depurando con Eclipse

Introduccin
El Ejemplo
Crear el Proyecto
Importar la Clase Employee
Ejecutar la Aplicacin
Mostrar los Nmeros de Lnea
Depurar la Clase
Colocar un Punto de Ruptura
Monitorear la Ejecucin
Diagnosticar y Corregir el Error

Introduccin
En esta seccin, realizaremos una demostracin del proceso de depuracin utilizando un
depurador. Utilizaremos el depurador incluido en Eclipse. Las funciones bsicas provistas
por este depurador son similares a las que ofrecen otros depuradores. Por lo tanto, tambin
puedes avanzar en este tutorial utilizando otro depurador.

El Ejemplo
La clase Employee representa a un empleado en un sistema de nminas. Los objetos de la
clase Employee contienen el nombre y el salario del empleado. El salario de un empleado
es una funcin del salario por hora, el nmero de horas trabajadas y las comisiones de
ventas. La informacin de cada empleado es almacenada en una cadena con el siguiente
formato:
name_hourlyWage_hoursWorked_sale1,sale2,...,salen

Donde,

name es el nombre del empleado


wagePerHour es el salario por hora del empleado
hoursWorked es el nmero de horas que el empleado trabaj
sale1,sale2,...,salen son las ventas del empleado

El sueldo ganado por un empleado se calcula utilizando la siguiente ecuacin.


earning = hourlyWage * hoursWorked + (sale1 + sale2 + ... + salen) * 0.02

Donde, el valor 0.02 corresponde al 2% por comisin de ventas.


A continuacin se presenta el cdigo de la clase Employee:
1: import java.io.*;

2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:

import java.util.*;
/**
* Modela la informacin de un empleado.
*
* @author
* @version 1.0.0
*/
public class Employee {
private static PrintWriter stdErr =
new PrintWriter(System.err, true);
private final static double

SALE_COMMISSION = 0.02;

private final static String

DATA_DELIM = "_";

private final static String

SALES_DELIM = ",";

private String

name;

private double

earnings;

/**
* Caso de prueba para la clase <code>Employee</code>
*
* @param args no utilizado.
*/
public static void main(String[] args) {
String
Employee

data = "John Smith_10.00_20_1000.0,100.0,0.0";


employee = new Employee(data);

try {
if (employee.getEarnings() == 222.0) {
stdErr.println("Test 1 passed");
} else {
stdErr.println("Test 1 failed");
}
} catch (NumberFormatException iae) {
stdErr.println("Test 1 failed, " + iae);
}
data = "John Smith_10.00_20_1000.0,100.0";
employee = new Employee(data);
try {
if (employee.getEarnings() == 222.0) {
stdErr.println("Test 2 passed");
} else {
stdErr.println("Test 2 failed");
}
} catch (NumberFormatException iae) {
stdErr.println("Test 2 failed, " + iae);
}

59:
}
60:
61:
/**
62:
* Construye un objeto <code>Employee</code> con la
63:
* informacin especificada en el parmetro <code>data</code>.
64:
* <p>
65:
* Los datos de entrada tienen el siguiente formato:
66:
* </p>
67:
* <p>
68:
* nombre_salarioHora_horasTrabajadas_venta1,venta2,...,ventan
69:
* </p>
70:
* <p>
71:
* Los campos de venta almacenan la cantidad de cada venta
72: realizada por el
73:
* empleado.
74:
* </p>
75:
*
76:
* @param data una cadena con la informacin del empleado.
77:
* @throws NumberFormatException si los datos contienen nmeros
78:
*
invlidos
79:
*/
80:
public Employee(String data) throws NumberFormatException {
81:
82:
StringTokenizer tokenizer =
83:
new StringTokenizer(data, DATA_DELIM);
84:
85:
try {
86:
this.name = tokenizer.nextToken();
87:
88:
double hourlyWage =
89:
Double.parseDouble(tokenizer.nextToken());
90:
int hoursWorked =
91:
Integer.parseInt(tokenizer.nextToken());
92:
93:
double commission = (tokenizer.hasMoreTokens()) ?
94:
95: computeCommission(tokenizer.nextToken()) : 0;
96:
97:
this.earnings = hourlyWage * hoursWorked + commission;
98:
99:
} catch (NumberFormatException nfe) {
100:
throw new NumberFormatException(
101:
"bad employee data: " + data);
102:
}
103:
}
104:
105:
/**
106:
* Obtiene el nombre del empleado.
107:
*
108:
* @return regresa una cadena con el nombre del empleado.
109:
*/
110:
public String getName() {
111:
112:
return this.name;
113:
}
114:
115:
/**

116:
* Obtiene los ingresos del empleado.
117:
*
118:
* @return los ingresos del empleado.
119:
*/
120:
public double getEarnings() {
121:
122:
return this.earnings;
123:
}
124:
125:
/*
126:
* Calcula la comisin del empleado con los datos
127:
* especificados en el parmetro.
128:
*
129:
* @param data una cadena con los datos de las ventas del
130: empleado.
131:
* @return regresa la comisin ganada por el empleado.
132:
* @throws NumberFormatException si los datos contienen nmeros
133:
*
invlidos
134:
*/
135:
private double computeCommission(String data)
136:
throws NumberFormatException {
137:
138:
StringTokenizer tokenizer =
139:
new StringTokenizer(data, SALES_DELIM);
140:
141:
double total = 0.0;
142:
143:
try {
144:
145:
String token = tokenizer.nextToken();
146:
147:
while (tokenizer.hasMoreTokens()) {
148:
token = tokenizer.nextToken();
149:
total += Double.parseDouble(token);
150:
}
151:
152:
} catch (NumberFormatException nfe) {
153:
throw new NumberFormatException(
154:
"bad sales data: " + data);
155:
}
156:
return total * SALE_COMMISSION;
}
}

Listado 1 Employee.java
En la lnea 92, el operador condicional ( ? : ) utiliza el valor booleano de una expresin
para decidir cul de dos otras expresiones debe ser evaluada. La siguiente asignacin:
variable = condicin ? expresin1 : expresin2;

es equivalente al siguiente cdigo:


if (condicin) {

variable = expresin1;
} else {
variable = expresin2;
}

El constructor utiliza un objeto StringTokenizer para extraer cada parte de la informacin


del empleado. Entonces, asigna valores a las variables name y earning. El mtodo
computeCommission regresa la comisin del empleado a partir de la informacin de ventas.
Esta implementacin de la clase Employee es incorrecta. En el resto de esta pgina,
utilizaremos el depurador Eclipse para encontrar el error y corregirlo.

Crear el Proyecto
El primer paso es crear el proyecto de Java.
1. Abre Eclipse y despus abre la perspectiva de Java.
2. En el men File (archivo), apunta a New (nuevo) y despus selecciona Project
(proyecto).
3. En el asistente de New Project, selecciona Java en el panel izquierdo, da un clic en
Java Project (proyecto de Java) en el panel derecho y despus elige Next
(siguiente).

Figura 1 Ventana de nuevo proyecto


4. En el cuadro de Project name (nombre de proyecto) escribe Employee. Selecciona
el recuadro de Use default (utilizar predeterminado) y presiona Finish (terminar).

Figura 2 Asistente del proyecto de Java


5. Eclipse aade el nuevo proyecto a la lista que se encuentra en la vista Projects
(proyectos).

Figura 3 Proyecto Employee

Importar la Clase Employee


1. En el men File, selecciona Import (importar).
2. En el asistente de importacin, selecciona File System (sistema de archivo) y
selecciona Next.

Figura 4 Asistente de importacin


3. En el cuadro de dilogo del sistema de archivo, File system, selecciona Browse
(explorar). En el cuadro de dilogo Import from directory (importar desde
directorio), localiza el directorio que contiene el archivo Employee.java, da un clic
en el nombre del directorio y despus presiona OK.

Figura 5 Seleccionar el directorio


4. Este asistente desplegar en el panel derecho de la ventana todos los archivos que se
encuentran en el directorio seleccionado. Selecciona el cuadro que est a un lado de
Employee.java y escribe Employee en el cuadro Into folder. Da un clic en Create
selected folders only (crear slo las carpetas seleccionadas) y despus presiona
Finish.

Figura 6 Seleccionar el archivo Employee.java


5. En la vista Package Explorer (explorador de paquetes) que se encuentra en la parte
izquierda de la ventana, da un doble clic en Employee y despus da otro doble clic
en default-package (paquete predeterminado). Esto desplegar los archivos de la
aplicacin Employee. Da un doble clic en Employee.java. El cdigo aparecer en
el editor con resaltamiento de sintaxis.

Figura 7 Cdigo de la clase Employee

Ejecutar la Aplicacin
1. Presiona la flecha que se encuentra a la derecha del botn Run en la barra de
herramientas, apunta a Run As y selecciona Java Application.

Figura 8 Correr la aplicacin


2. Eclipse desplegar la salida de la aplicacin en la vista Console. Esta salida indica
que la clase Employee tiene un error. En las secciones siguientes, te mostraremos
cmo encontrar y corregir el error utilizando el depurador Eclipse.

Figura 9 La salida en la vista Console

Mostrar los Nmeros de Lnea


Antes de buscar los errores, modifica las preferencias del editor de Java de modo que el
editor incluya nmeros de lnea.
1. En el men Window (ventana), da un clic en Preferences (preferencias).
2. En el panel izquierdo del cuadro de dilogo Preferences, da un doble clic en Java y
despus da un clic en Editor.
3. Selecciona el cuadro Show line numbers (mostrar nmeros de lnea) y presiona
OK.

Figura 10 Mostrar nmeros de lnea


4. El editor de Java desplegar el nmero de cada lnea a la izquierda.

Figura 11 Cdigo con nmeros

Depurar la Clase
1. Para depurar la clase, presiona la flecha que se encuentra a la derecha del botn
Debug (depurar) en la barra de herramientas. Apunta a Debug As y despus
selecciona Java Application.

Figura 12 Depurar una aplicacin de Java


2. Eclipse mostrar la perspectiva Debug del proyecto.

Figura 13 Perspectiva Debug


3. La perspectiva Debug contiene un editor y cuatro vistas:
1. Vista Debug: Despliega los mtodos que han sido llamados
2. Vista Variables: Despliega los valores de las variables
3. Navegador de Clases (class browser): Despliega las variables y los
mtodos de las clases
4. Vista Console: Despliega la salida en System.err y System.out
La vista Debug tiene una barra de herramientas con botones que pueden controlar la
ejecucin del cdigo.

Colocar un Punto de Ruptura


La clase Employee contiene un caso de prueba que genera un mensaje como salida cuando
detecta un error. Como puedes ver en este ejemplo, es una buena idea definir casos de
prueba que verifiquen que el programa est funcionando como se espera que lo haga.
El siguiente paso es localizar el error; para realizar esta tarea, el depurador es una excelente
herramienta. Tpicamente, los puntos de ruptura son colocados en la parte del cdigo donde
queremos suspender la ejecucin y examinar los valores de las variables.

Un buen punto para comenzar es la lnea que reporta el error. (Ver la tcnica de depuracin
descrita en la pgina Depurando.) En este ejemplo, la lnea 40 del mtodo main reporta el
error.
1. En el editor, ve a la lnea 40. Da un clic derecho al nmero de lnea y selecciona
Add Breakpoint (aadir punto de ruptura).

Figura 14 Aadir un Punto de Ruptura


2. Aparecer un crculo azul a la izquierda del nmero de lnea; este crculo representa
el punto de ruptura.

Figura 15 Marca de un punto de ruptura

Monitorear la Ejecucin

1. En la barra de herramientas, presiona debug


Employee en modo de depuracin.

para "lanzar" la aplicacin

Figura 16 Depurar la aplicacin


2. La vista Debug muestra mucha informacin que podemos ignorar por el momento.
Enfocaremos nuestra atencin en la seccin "Thread[main]". Esta seccin muestra
los mtodos que fueron llamados antes de que la ejecucin alcanzara el punto de
ruptura. Tambin muestra que la ejecucin fue suspendida en la lnea 40 del mtodo
main de la clase Employee.

Figura 17 Vista view


3. La vista Variables muestra el valor de las variables en este punto. Da un clic en el
signo de ms ( + ) que se encuentra junto a la variable employee. Esto desplegar
los contenidos del objeto.

Figura 18 Vista Variables

4. El valor de la variable earnings es incorrecto: es 202.0 y debera se 222.0. El


siguiente paso es mirar el cdigo justo donde se modifica el valor de la variable
earnings. La lnea 95 asigna un valor a earnings.
5. En la barra de herramientas de depuracin, en la vista Debug, presiona terminate
para abortar la ejecucin de la aplicacin.
6. Da un doble clic en la marca azul que se encuentra en la lnea 40 para quitar de
punto de ruptura.
7. Ve a la lnea 95. Da un clic derecho al nmero de lnea y selecciona Add
Breakpoint.

Figura 19 Punto de Ruptura en la lnea 95


8. En la barra de herramientas, presiona bug
depuracin una vez ms.

para lanzar la aplicacin en modo de

Figura 20 Depurar la aplicacin


9. La ejecucin se detiene en la lnea 95. La vista Variables muestra el valor de las
variables en este punto.

Figura 21 Vista Variables en la lnea 95


10. Los valores de las variables hourlyWage y hoursWorked son correctos, pero el
valor de commission es 2.0 y debera ser 22.0. El siguiente paso es mirar el cdigo
justo donde se modifica el valor de la variable commission. La lnea 93 llama al
mtodo computeCommission y asigna el valor regresado por el mtodo
computeCommission a la variable commission.
11. En la barra de herramientas de depuracin, presiona terminate
para abortar la
ejecucin de la aplicacin.
12. Da un doble clic en la marca azul de la lnea 95 para quitar el punto de ruptura.
13. El mtodo computeCommission utiliza un objeto StringTokenizer y un bucle
while para sumar las ventas. Ve a la lnea 144 para monitorear el comportamiento
del bucle while. Da un clic derecho en la lnea 144 y selecciona Add Breakpoint.

Figura 22 Punto de ruptura en la lnea 144


14. En la barra de herramientas, selecciona bug para "lanzar" la aplicacin en modo
de depuracin de nuevo
15. La ejecucin se detiene en la lnea 144, antes del bucle while.

Figura 23 Ejecucin suspendida en la lnea 144


16. La vista Variables muestra el valor de las variables en este punto.

Figura 24 Vista Variables en la lnea 144


17. Antes de que comience la ejecucin del bucle while, la variable total contiene
0.0, la variable token contiene el primer token ("1000.0") y la variable tokenizer
indica la posicin del siguiente token en data.
18. Utilizaremos los controles de pasos para monitorear el comportamiento del bucle
while. La barra de herramientas de depuracin que se encuentra en la vista Debug
contiene los siguientes controles:

resume

Contina la ejecucin hasta el siguiente punto de


ruptura.

step
into

Ejecuta la lnea actual. Si la lnea actual llama a un


mtodo, el depurador "pasa adentro de" el mtodo, es
decir, la ejecucin se mueve al mtodo llamado y se
detiene antes de la primera lnea del mtodo llamado.

step
over.

Ejecuta la lnea actual. Si la lnea actual llama a un


mtodo, el depurador "pasa sobre" el mtodo, es decir, el
mtodo es ejecutado y la ejecucin se detiene antes de la
siguiente lnea del mtodo actual. Si no hay ms lneas
en el mtodo, la ejecucin regresa al mtodo que hace la
llamada y se detiene antes de la siguiente lnea del
mtodo que hace la llamada.

step
return

Ejecuta hasta que el mtodo actual se completa y regresa


al mtodo que hace la llamada. La ejecucin se detiene
antes de la siguiente lnea del mtodo que hace la
llamada.

terminate

Aborta la ejecucin.

19. En la barra de herramientas de depuracin, selecciona step over para ejecutar la


lnea actual. La ejecucin se detiene antes de la lnea 145.

Figura 25 La ejecucin se detuvo en la lnea 145


20. La variable tokenizer indica la ubicacin del siguiente token en data.
21. Presiona step over para ejecutar la lnea actual. La ejecucin se detiene antes de
la lnea 146.

Figura 26 La ejecucin se suspendi en la lnea 146


22. La variable token ahora contiene el segundo token ("100.0"), pero la variable
total es an 0.0. La informacin del primer token se ha perdido.

Figura 27 La vista Variables en la lnea 146


23. Este comportamiento no es lo que esperbamos. Hemos encontrado el error. El
siguiente paso es analizar el cdigo y corregir el error.
24. Presiona terminate para abortar la ejecucin.
25. Da un doble clic en la marca azul que se encuentra en la lnea 144 para quitar el
punto de ruptura.

Diagnosticar y Corregir el Error

Hemos descubierto que el valor del primer token no es aadido a la variable total. Un
error comn es disfrazar el error en vez de repararlo. Por ejemplo, podemos pensar que el
orden de las lnea 145 y 146 est incorrecto e intercambiarlas:

Figura 28 Primer intento de corregir el error


1. Intercambia las lneas y guarda el archivo.
2. Corre la aplicacin para probar la correccin. Presiona la flecha que est a la
derecha del botn Run en la barra de herramientas, apunta a Run As y despus
selecciona Java Application.

Figura 29 Correr la aplicacin


3. La vista Console muestra que el segundo caso de prueba fall.

Figura 30 Salida de la primera correccin


4. Antes de intentar corregir el cdigo, es importante analizar el cdigo para entender
mejor el error. Revisando el cdigo, observamos que la estructura del bucle while
es incorrecta. El mtodo hasMoreTokens debe ser llamado antes de leer cada token
y el valor de la venta debe ser aadido a la variable total inmediatamente despus
de que el token es ledo.
5. Corrige el cdigo del mtodo computeCommission como se indica a continuacin:

Figura 31 Correccin del mtodo computeCommission()


6. Corre la aplicacin para probar la correccin. Da un clic en la flecha que se
encuentra a la derecha del botn Run en la barra de herramientas, apunta a Run As
y despus selecciona Java Application.

Figura 32 Correr la aplicacin


7. La vista Console muestra la salida:

Figura 33 Salida de la segunda correccin


8. La salida indica que la aplicacin pas ambos casos de prueba.

1.2 Diseando Clases

1.2.1 Diagramas UML de Clases


1.2.2 Relaciones entre Clases
1.2.3 Estructuras Comunes de Clases
1.2.4 UML con Eclipse
1.2.5 Modelando Clases
1.2.6 Modelando el Sistema de Biblioteca

1.2.1 Diagramas UML de Clases

Introduccin
Notacin de Clase
Lecturas:

Requerida:
o Barker, primera edicin, captulo 10 (pginas 2303).
o Barker, segunda edicin, captulo 10 (pginas 372
6).

Secuencia: Lee el libro de texto antes de leer esta pgina.

Introduccin
El Lenguaje de Modelacin Unificado (Unified Modeling Language o UML por sus siglas
en ingls) es un lenguaje grfico para modelar los aspectos estticos y dinmicos de un
sistema. UML es una unificacin de las metodologas desarrolladas por Grady Booch,
James Rumbaugh e Ivar Jacobsen. El Grupo de Administracin de Objetos (Object
Management Group u OMG), una organizacin sin fines de lucro que promueve el uso de
la tecnologa orientada a objetos, ha asumido la responsabilidad del futuro desarrollo del
estndar UML.
UML es un lenguaje que unifica las mejores prcticas de la ingeniera para modelar
sistemas. Define diferentes diagramas grficos que proveen mltiples perspectivas de un
sistema en desarrollo. UML define los siguientes diagramas:

Diagrama de caso de uso

Diagrama de clase

Diagramas de comportamiento:
o Diagrama de estado
o Diagrama de actividad
o Diagramas de interaccin:
Diagrama de secuencia
Diagrama de colaboracin

Diagramas de implementacin:
o Diagrama de componentes
o Diagrama de despliegue

A lo largo de este curso, utilizaremos diagramas de clase para discutir los diferentes
elementos del diseo orientado a objetos. Los diagramas de clase muestran la estructura
interna de las clases y sus relaciones con otros elementos del sistema.

Notacin de Clase
El elemento fundamental de un diagrama de clase es la notacin de una clase. Como se
muestra en la Figura 1, una clase est representada por un rectngulo con tres secciones. La
primera seccin contiene el nombre de la clase; la segunda seccin describe los atributos de
la clase y la tercera seccin describe los mtodos de la clase.

Figura 1 Notacin de Clase


El tipo de una variable y el tipo de retorno de un mtodo estn especificados por dos puntos
( : ) seguidos por el nombre de un tipo. La especificacin de un atributo o mtodo comienza
con un smbolo que indica la visibilidad de dicho atributo o mtodo:

- indica visibilidad privada


+ indica visibilidad pblica

La visibilidad privada no permite que otras clases tengan acceso a este atributo o mtodo,
mientras que la visibilidad pblica permite que otras clases tengan acceso a este atributo o
mtodo.
Comnmente, los atributos se definen como privados; de esta manera el objeto puede
esconder su informacin para mantener el control de su estado. Un mtodo se define como
pblico si se espera que sea llamado por otras clases y se define como privado si no se
pretende que sea llamado por clases externas.
Cuando una clase necesita brindar acceso a sus atributos privados, la convencin indica
definir los mtodos pblicos para acceder el valor de un atributo o modificar un atributo.
Estos mtodos son conocidos como selectores (accessors) o modificadores (mutators),
respectivamente.
A continuacin se muestra la representacin UML de la clase Employee (empleado). Esta
clase contiene tres atributos privados: name (nombre), hourlyWage (salario por hora) y
hoursWorked (horas trabajadas). Tambin contiene los siguientes mtodos pblicos:

Mtodos para obtener los valores de los atributos (accessors): getName,


getHourlyWage, y getHoursWorked
Mtodos para modificar los valores de los atributos (mutators): setName,
setHourlyWage, y setHoursWorked
Un mtodo para obtener los ingresos del empleado: getEarnings

Figura 2 Representacin de la clase Employee


La notacin de clase puede ser abreviada para resaltar otras partes del sistema que se est
modelando. Por ejemplo, la seccin de mtodos nicamente debe especificar los nombres
de los mtodos:

Figura 3 Representacin abreviada de la clase Employee


La forma ms pequea de una clase consiste en un rectngulo con un nombre de clase:

Figura 4 La forma ms pequea de la clase Employee


Un diagrama de clase contiene muchas clases, atributos y mtodos que pueden ser difciles
de leer. En tal caso, pueden omitirse algunos atributos y mtodos de forma segura. El
siguiente diagrama de clase incluye solamente los atributos y mtodos que son ms
importantes para describir la funcionalidad de la clase:

Figura 5 Representacin esencial de la clase Employee

1.2.2 Relaciones Entre Clases

Asociaciones
Asociaciones de Una Va (One-Way) y Dos Vas (Two-Way)
Multiplicidad
Agregacin
Especializacin/Generalizacin

Lecturas:

Requeridas:
o Barker, first edition, chapter 5 (pages 113 20); chapter
10 (pages 233 40).
o Barker, second edition, chapter 5 (pages 16774);
chapter 10 (pages 37686).

Secuencia: Lee el libro de texto antes de leer esta pgina.

Asociaciones
Una asociacin representa la relacin entre dos o ms clases. Una asociacin binaria es
una relacin entre dos clases. Existe una asociacin binaria si un objeto de una clase
requiere un objeto de otra clase para hacer su trabajo. En UML, una asociacin binaria est
representada por una lnea slida que conecta dos clases.
Por ejemplo, en un saln de clases, un profesor (Professor) ensea a los estudiantes
(Student). Esta asociacin est expresada en el siguiente diagrama de clase:

Figura 1 Asociacin entre las clases que representan estudiantes y


profesores

En un sistema bancario, los clientes (Client) tienen cuentas de banco (BankAccount). Esta
asociacin se encuentra expresada en el siguiente diagrama de clase:

Figura 2 Asociacin entre las clases que representan clientes y cuentas


bancarias

Asociaciones de Una Va (One-Way) y Dos Vas (Two-Way)


Una asociacin puede ser una relacin de una va (one-way) o de dos vas (two-way). Una
asociacin de una va indica la direccin en la que se puede navegar de un objeto de una
clase a un objeto de otra clase. Una asociacin de dos vas indica una navegacin
bidireccional entre objetos de dos clases.
En una asociacin de una va, la primera clase tiene una referencia a un objeto de la
segunda clase, pero la segunda clase no tiene una referencia a un objeto de la primera clase.
En una asociacin de dos vas, cada clase contiene una referencia a un objeto de la otra
clase.
UML indica una asociacin de una va con una flecha al final de la lnea de asociacin. El
atributo de la primera clase que contiene una referencia a un objeto de la segunda clase
tambin est escrito al final de la lnea.
Por ejemplo, la siguiente asociacin indica que un motor (Engine) es parte de un carro
(Car):

Figura 3 Asociacin de una va entre las clases que representan carros y motores

Observa el atributo engine al final de la lnea. La clase Car tiene un atributo engine que
contiene una referencia a un objeto de la clase Engine.
El siguiente ejemplo muestra la relacin entre las clases Country (pas), Government
(gobierno) y Capital. Cada pas tiene un gobierno y una capital. Los atributos al final de
las lneas indican que la clase Country tiene una referencia a un objeto de la clase
Government as como una referencia a un objeto de la clase Capital:

Figura 4 Asociaciones de una va entre las clases que representan pases, gobiernos y capitales

Una clase puede contener una o ms asociaciones con otra clase. Por ejemplo, el siguiente
diagrama de clase muestra dos asociaciones entre las clases Flight (vuelo) y Pilot

(piloto), una asociacin con el atributo pilot (piloto) y otra con el atributo coPilot
(copiloto):

Figura 5 Dos asociaciones entre las clases que representan vuelos y


pilotos

Multiplicidad
La multiplicidad indica el nmero de instancias de una clase que pueden ser asociadas a
una sola instancia de otra clase. Por ejemplo, un carro tiene cuatro llantas y un motor,
tambin un cliente tiene una o ms cuentas de banco. La multiplicidad puede especificarse
con un solo entero o como un rango n..m, donde n es el lmite inferior y m es el lmite
superior. Podemos utilizar un asterisco ( * ) para denotar que no existe un lmite superior. A
continuacin se presentan las multiplicidades ms comunes:
0..1

Cero o una instancia

0..* *

Cero o ms instancias

Exactamente una instancia

1..*

Una o ms instancias

Tabla 1 Multiplicidades comunes

Las asociaciones pueden clasificarse de acuerdo a su multiplicidad. En este curso,


discutiremos tres tipos: uno a uno, uno a muchos y muchos a muchos.
Asociacin uno a uno

En una asociacin uno a uno, exactamente una instancia de cada clase est relacionada
solamente con una instancia de otra clase. Por ejemplo, la asociacin entre las clases Car
(carro) y Engine (motor) puede definirse como una asociacin uno a uno, indicando que
cada carro contiene solo un motor y que cada motor est instalado solamente en un carro:

Figura 6 Asociacin uno a uno entre las clases que


representan carros y motores

El siguiente diagrama de clase muestra las asociaciones uno a uno entre las clases Country
(pas), Government (gobierno) y Capital. Cada pas contiene slo un gobierno y una
capital. Cada gobierno est asociado con un solo pas y cada capital est asociada con solo
un pas:

Figura 7 Asociaciones uno a uno entre las clases que


representan pases, gobiernos y capitales
Asociacin uno a muchos

En una asociacin uno a muchos entre las clases A y B, una instancia de la clase A puede
estar relacionada con muchas instancias de la clase B, pero una instancia de la clase B est
relacionada solamente con una instancia de la clase A. Por ejemplo, en la asociacin entre
las clases Client (cliente) y BankAccount (cuenta bancaria), cada cliente puede tener
muchas cuentas de banco, pero cada cuenta de banco tiene solamente un propietario:

Figura 8 Asociacin uno a muchos entre las clases que


representan clientes y cuentas bancarias

El siguiente diagrama muestra la relacin entre las clases que representan un calendario:

Figura 9 Asociacin entre las clases de un calendario

En este diagrama, un ao (Year) contiene doce meses (Month) y cada mes est asociado con
solo un ao. (Toma en cuenta que los meses Enero1962 y Enero2029 son instancias
diferentes de la clase Month.) De la misma forma, un mes contiene cuatro o cinco semanas
(Week) y cada semana est asociada con solo un mes. Finalmente, una semana contiene
siete das (Day) y cada da est asociado con una sola semana.
Asociacin muchos a muchos

En una asociacin muchos a muchos entre las clases A y B, una instancia de la clase A puede
estar relacionada con muchas instancias de la clase B y una instancia de la clase B puede
estar relacionada con muchas instancias de la clase A. Por ejemplo, en la asociacin entre
las clases Student (estudiante) y Course (curso), cada estudiante toma muchos cursos y
cada curso est siendo impartido para muchos estudiantes:

Figura 10 Asociacin entre las clases que representan


estudiantes y cursos

El siguiente diagrama representa una compaa donde un empleado (Employee) puede


trabajar en muchos departamentos (Department) y puede estar involucrado en muchos
proyectos (Project); cada departamento puede tener muchos empleados y a su vez, cada
proyecto puede involucrar muchos empleados:

Figura 11 Asociacin entre las clases que representan


empleados, departamentos y proyectos

Agregacin
La agregacin es una forma especial de asociacin. Una agregacin es una asociacin entre
las clases A y B, donde cada instancia de la clase A contiene, o est compuesta por,
instancias de la clase B. En este sentido, una instancia de la clase B es parte de una instancia
de la clase A. A la instancia de la clase A se le conoce como agregada (aggregate) y a la
instancia de la clase B se le conoce como componente (component). Por ejemplo, un libro
(Book) est compuesto por una tabla de contenidos (TableOfContents), ningn o un
prefacio (Preface), uno o ms captulos (Chapter) y un ndice (Index). En un libro, cada
captulo est compuesto por una o ms secciones (Section) y cada seccin est compuesta
por uno o ms prrafos (Paragraph) y ninguna o algunas figuras (Figure).
Una relacin de agregacin se representa en UML mediante una lnea con un diamante
junto a la clase agregada:

Figura 12 Notacin de agregacin

El siguiente diagrama de clase muestra la estructura de componentes de un libro:

Figura 13 Agregacin jerrquica de un libro

En este curso, no utilizaremos asociaciones de agregacin. Los ejemplos y ejercicios


utilizarn nicamente asociaciones de una va y de dos vas.

Especializacin/Generalizacin
La Especializacin/Generalizacin representa a la relacin es un. Por ejemplo, una ballena
es un mamfero y un cliente es una persona. La especializacin/generalizacin permite que
la clase A sea definida como especializacin de otra clase B, ms general. La clase A es
llamada clase de especializacin (specialization class) y la clase B es llamada clase de
generalizacin (generalization class). La especializacin/generalizacin se representa en
UML mediante una lnea con un tringulo junto a la clase de generalizacin:

Figura 14 Notacin de Especializacin/Generalizacin

Si existe una relacin de especializacin/generalizacin entre las clases A y B, es decir, si A


es un B, entonces todas las instancias de la clase A son tambin instancias de la clase B. Una
consecuencia importante de esta relacin es que la clase A hereda todas las caractersticas
de la clase B. Esto significa que todos los atributos y mtodos de la clase B son tambin
atributos y mtodos de la clase A. El siguiente diagrama de clase representa las relaciones
cliente es una persona (Client is a Person) y un empleado es una persona (Employee is a
Person):

Figura 15 Relacin de especializacin/generalizacin entre clases que representan clientes, empleados y personas

Debido a las relaciones de especializacin/generalizacin, los atributos de la clase Person


son tambin atributos de las clases Client y Employee. Cada instancia de la clase Client
contiene los atributos name (nombre), age (edad), address (direccin) y accounts
(cuentas); y cada instancia de la clase Employee contiene los atributos name (nombre), age
(edad), address (direccin), salary (salario) y departament (departamento).
Veamos otro ejemplo. Considera un sistema de archivos multimedia que incluye archivos
de imagen, de audio y de texto. Las clases se definen a continuacin:

La clase MediaFile (archivo de multimedia) contiene informacin general sobre los


archivos multimedia: name (nombre), extension (extensin) y size (tamao) en bytes.
La clase ImageFile (archivo de imagen) especializa la clase MediaFile, aadiendo los
atributos width (ancho de la imagen) y height (altura de la imagen).
La clase AudioFile (archivo de audio) especializa la clase MediaFile, aadiendo el
atributolength (longitud en minutos).
La clase TextFile especializa la clase MediaFile, aadiendo el atributo summary
(sumario) que contiene todo el texto.
Las clases MidiFile y Mp3File especializan la clase AudioFile, aadiendo
informacin especfica a cada formato.
Las clases JpgFile y GifFile especializan la clase ImageFile, aadiendo informacin
especfica a cada formato.

El siguiente diagrama de clase muestra las relaciones de especializacin/generalizacin


entre las clases:

Figura 16 Jerarqua de especializacin/generalizacin de los archivos multimedia

En este ejemplo:

Una instancia de la clase JpgFile contiene los atributos especficos de la clase JpgFile,
as como los atributos width, height, name, extension y size.
Una instancia de la clase TextFile contiene los atributos summary, name, extension y
size.
Una instancia de la clase Mp3File contiene los atributos especficos de la clase Mp3File,
as como los atributos length, name, extension y size.

1.2.3 Estructuras de Clase Comunes

Introduccin
Colecciones
Clases Autocontenidas
Bucles de Relacin

Introduccin
Aunque la definicin de clases y sus relaciones depende de la aplicacin que se est
utilizando en particular, algunas estructuras de clase son comunes para muchos diseos.
Estas estructuras de clase, las cuales pueden concebirse como bloques de construccin
bsicos, pueden ser combinadas para la creacin de sistemas complejos. Esta pgina te
mostrar algunas de ellas.

Colecciones
Una coleccin modela una relacin uno a muchos. Las colecciones almacenan muchas
instancias de una clase. El siguiente diagrama de clase utiliza una conexin para representar
la relacin "un cliente tiene una o ms cuentas bancarias" y define los mtodos para
manejar la coleccin de instancias de la clase BankAccount (cuenta bancaria). En dicha
coleccin, cada instancia de BankAccount tiene un ndice que indica su ubicacin en la
coleccin.

Figura 1 Coleccin de instancias de BankAccount


En este ejemplo:

La coleccin es almacenada en el atributo accounts de la clase Client.


addBankAccount(account:BankAccount) almacena una instancia de la clase
BankAccount en la coleccin.
getBankAccount(index:int): BankAccount obtiene la instancia ubicada en la
posicin especificada por index.
getNumberOfBankAccounts():int obtiene el nmero de cuentas de banco que
hay en la coleccin.

Los ndices son una manera simple de trabajar con colecciones, pero no siempre son
apropiados para todos los tipos de colecciones. En la siguiente unidad de este curso, te
presentaremos una solucin ms general que no utiliza ndices.

Clases Autocontenidas
Una clase puede tener una asociacin con ella misma. En tales casos, la clase contiene
atributos con referencias a los objetos de la misma clase. Por ejemplo, el siguiente diagrama
de clase muestra la definicin de la clase Person en un sistema de rbol genealgico. Las
relaciones "cada persona tiene una madre" y "cada persona tiene un padre" estn
indicadas en los atributos mother y father. Los atributos mother y father son referencias
a objetos de la clase Person.

Figura 2 Relaciones padre y madre


En otro ejemplo, el siguiente diagrama muestra la relacin "cada empleado tiene un jefe".
El diagrama indica que el jefe de un empleado es otro empleado.

Figura 3 Clase autocontenida Employee

Bucles de Relacin
La autocontencin puede ser encontrada en relaciones que incluyen dos o ms clases. Un
ejemplo de un ciclo de autocontencin es un sistema de archivos. Un sistema de archivos
tiene carpetas y las carpetas contienen archivos o ms carpetas, o ambas. Podemos definir
una clase Folder, que contenga una coleccin de objetos FolderItem:

Figura 4 Diagrama de clase de un sistema de archivos


En este ejemplo, las clases Folder y File estn definidas como especializaciones de la
clase FolderItem. La clase File tiene atributos para la extensin y el tamao del archivo.
La clase Folder tiene una coleccin y algunos mtodos:

folderItems atributo que contiene la coleccin de instancias de la clase


FolderItem.
addFolderItem(item:FolderItem) aade a la carpeta una instancia de la clase
FolderItem.
removeFolderItem(item:FolderItem) elimina de la carpeta una instancia de la
clase FolderItem.
getFolderItem(index:int):FolderItem obtiene la instancia ubicada en la
posicin especificada por index.
getNumberOfFileItem(index:int):int obtiene el nmero de elementos de la
clase FolderItem que hay en la carpeta.

Observa que el diagrama de clase de un sistema de archivos es una combinacin de


herencia y de relacin de asociacin.
Referencias
Lau, Y. The Art of Objects: Object-Oriented Design and Architecture (El Arte de los
Objetos: Diseo y Arquitectura Orientados a Objetos). Addison-Wesley, 2001.

1.2.4 UML con Eclipse

Introduccin
Crear el Proyecto
Crear la Carpeta
Crear el Nuevo Diagrama de Clase
Crear la Clase BankAccount
Crear la Clase Person
Crear la Clase Client
Crear una Relacin de Especializacin/Generalizacin
Crear una Relacin de Asociacin
Exportar una Imagen

Introduccin
EclipseUML es un plug-in de Eclipse para dibujar diagramas de UML. EclipseUML provee
una vista grfica para definir clases y sus relaciones. En esta pgina, mostraremos cmo
dibujar un diagrama de clase utilizando EclipseUML. Crearemos un diagrama de clase para
la siguiente abstraccin:
"En un sistema bancario, un cliente es una persona que tiene una o ms cuentas de banco"

Figura 1 Diagrama de Clase de un Sistema Bancario

Crear el Proyecto
El primer paso es crear un proyecto de Java:
1. En el men File, apunta a New y despus selecciona Project.
2. En el asistente de Nuevo Proyecto, selecciona Java en el panel izquierdo, da un clic
en Java Project que se encuentra a la derecha y despus presiona Next.

Figura 2 Asistente para la creacin de un nuevo proyecto


3. En el cuadro Project name, escribe BankSystem. Selecciona el cuadro Use default
y despus presiona Finish.

Figura 3 Cuadro de dilogo de un nuevo proyecto de Java

4. Eclipse crear un nuevo proyecto de Java y desplegar la perspectiva de Java.

Figura 4 Perspectiva de Java


La vista de Explorador de Paquetes (Package Explorer) muestra todos los proyectos
en el espacio de trabajo de Eclipse.

Crear la Carpeta
1. En el men File, apunta a New y despus da un clic en Folder. Aparecer el cuadro
de dilogo New Folder.
2. Escribe uml en el cuadro Folder name y despus presiona Finish.

Figura 5 Cuadro de Dilogo New Folder


3. La vista Package Explorer mostrar la nueva carpeta dentro del proyecto
BankSystem.

Figura 6 Vista de Explorador de Paquetes

Crear el Nuevo Diagrama de Clase


1. Da un clic derecho en la nueva carpeta, apunta a UML y despus selecciona Class
diagram editor (editor de diagramas de clase).

Figura 7 Abrir el editor de Diagramas de Clase


2. Eclipse abrir el editor de Diagramas de Clase.

Figura 8 Editor de Diagramas de Clase


3. La barra de herramientas en el editor de Diagramas de Clase contiene los siguientes
botones.
Seleccin (Selection)
Zoom
Crear un paquete (Create a package)
Crear una clase (Create a class)
Crear una interfase (Create an interface)
Crear una asociacin (Create an association)
Crear una generalizacin (Create a generalization)
Crear una dependencia (Create a dependency)
Crear una indicacin (Create an indication)
Crear una nota (Create a note)

Crear la Clase BankAccount

1. En la barra de herramientas del editor, presiona Create a Class y despus da un


clic en el diagrama. Aparecer el cuadro de dilogo de New Java Class.
2. Escribe BankAccount en el cuadro Name y despus presiona Finish.

Figura 9 Crear la clase BankAccount


3. La clase BankAccount aparecer en el diagrama donde hicimos clic con el ratn.

Figura 10 Clase BankAccount


4. A continuacin, crea un atributo para la clase BankAccount. Haz clic con el botn
derecho en la clase BankAccount, apunta a New y selecciona Attribute (atributo).
Aparecer el cuadro de dilogo New Attribute (nuevo atributo).

Figura 11 Aadir un atributo


5. Escribe balance en el cuadro Name. Selecciona double en el cuadro Type. Da un
clic para eliminar la seleccin del cuadro Use accessors (utilizar mtodos de
acceso) y despus presiona OK.

Figura 12 Cuadro de dilogo de Nuevo Atributo


6. Ahora despliega los atributos de la clase en el diagrama. Da un clic derecho en
BankAccount y selecciona Maximize.

Figura 13 Desplegar atributos de clase


7. El atributo balance aparecer en el diagrama.

Figura 14 Clase BankAccount con el atributo balance


8. Despus, crea un mtodo para la clase BankAccount. Da un clic derecho en
BankAccount, apunta a New y elige Method. Aparecer el cuadro de dilogo New
Operation (nueva operacin).

Figura 15 Aadir un mtodo


9. Escribe getBalance en el cuadro Name. Selecciona double en el cuadro Return
type. En el grupoVisibility, selecciona public. Por ltimo, presiona OK.

Figura 16 Cuadro de dilogo Nueva Operacin


10. El mtodo getBalance aparecer en el diagrama.

Figura 17 Clase BankAccount con el mtodo getBalance


11. Ahora crea un mtodo con un parmetro de entrada. Da un clic derecho en
BankAccount, apunta a New y despus selecciona Method. Aparecer el cuadro de
dilogo New Operation.
12. Escribe deposit en el cuadro Name. Selecciona void en el cuadro Return type. En
el grupo Visibility, selecciona public. En el rea de parmetros, Parameters,
selecciona Add.

Figura 18 Crear el mtodo deposit


13. Aparecer el cuadro de dilogo Parameter Properties (propiedades del parmetro).
Escribe amount en el cuadro Name. Selecciona double en el cuadro Type. Por
ltimo, selecciona OK.

Figura 19 Cuadro de dilogo de Propiedades del


Parmetro

14. Presiona OK en el cuadro de dilogo New Operation.


15. El mtodo deposit aparecer en el diagrama.

Figura 20 La clase BankAccount con el mtodo deposit


16. Crea otro mtodo con un parmetro de entrada. Da un clic derecho en
BankAccount, apunta a New y despus selecciona Method. Aparecer el cuadro de
dilogo New Operation.
17. Escribe withdraw en el cuadro Name. Selecciona void en el cuadro Return type.
En el grupo Visibility selecciona public. En el rea Parameters, selecciona Add.
18. Aparecer el cuadro de dilogo Parameter Properties. Escribe amount en el
cuadro Name. Selecciona double en el cuadro Type. Por ltimo, presiona OK.
19. Presiona OK en el cuadro de dilogo New Operation.
20. El mtodo withdraw aparecer en el diagrama.

Figura 21 Clase BankAccount con el mtodo withdraw


21. Ahora despliega la firma completa de cada mtodo del diagrama. Da un clic derecho
en BankAccount y elige View selector.... Aparecer el cuadro de dilogo View
Selector (ver selector).

Figura 22 Abrir cuadro de dilogo Ver


Selector
22. Elige la pestaa Methods del cuadro de dilogo View Selector. En el rea de firma,
Signature, selecciona Display arguments (desplegar argumentos), With
variable name (con nombre de variable) y Display return type (desplegar tipo de
retorno). Por ltimo, presiona OK.

Figura 23 Despliega las firmas de los mtodos


completas
23. Aparecer en el diagrama la firma completa de cada mtodo de BankAccount.

Figura 24 Clase BankAccount con firmas completas

Crear la Clase Person


1. En la barra de herramientas del editor, selecciona Create a Class y despus da
un clic en el diagrama. Aparecer el cuadro de dilogo New Java Class (nueva
clase de Java).
2. Escribe Person en el cuadro Name y despus presiona Finish.
3. La clase Person aparecer en el diagrama donde hicimos clic con el ratn.

Figura 25 Diagrama con la clase Person

Crear la Clase Client


1. En la barra de herramientas del editor, presiona Create a Class y despus da un
clic en el diagrama. Aparecer el cuadro de dilogo New Java Class.
2. Escribe Client en el cuadro Name y despus presiona Finish.
3. La clase Client aparecer en el diagrama donde hicimos clic con el ratn.

Figura 26 Diagrama con la clase Client

Crear la Relacin de Especializacin/Generalizacin


1. En la barra de herramientas del editor, presiona Generalization
Client y despus Person.

. Presiona

Figura 27 Diagrama con una relacin de


generalizacin/especializacin
2. Aparecer una relacin de especializacin/generalizacin entre las clases Client y
Person.

Crear la Relacin de Asociacin


1. En la barra de herramientas del editor, presiona Association . Selecciona Client
y despus da un clic en BankAccount. Aparecer el cuadro de dilogo Properties
(propiedades).
2. Selecciona la pestaa Connection y borra el texto que se encuentra en el cuadro
Label.

Figura 28 Cuadro de dilogo de Propiedades


3. Presiona la pestaa 1st Association End. Da un clic en el cuadro Navigable para
quitar la seleccin. Borra el texto del cuadro Name. Selecciona 1 en el cuadro
Multiplicity.

Figura 29 Propiedades de 1st Association End


4. Presiona la pestaa 2nd Association End. Selecciona el cuadro Navigable. Escribe
accounts en el cuadro Name. Selecciona 1..* en el cuadro Multiplicity. En el rea
de visibilidad, Visibility, elige private.

Figura 30 Propiedades de 2nd Association End


5. Presiona OK. Aparecer en el diagrama una asociacin entre las clases Client y
BankAccount.

Figura 31 Diagrama con la relacin de asociacin


6. Ahora est completo el modelo de la abstraccin del sistema bancario.

Exportar una Imagen


1. Da un clic derecho en el diagrama, apunta a Export y despus selecciona JPEG.
Aparecer el cuadro de dilogo Save As (guardar como).

Figura 32 Exportar una imagen


2. Selecciona la carpeta, escribe el nombre del archivo y despus presiona Save. El
diagrama de clase ser guardado como un archivo JPEG.

1.2.5 Modelando Clases

El Proceso de Modelar Clases


Identificando Clases
Identificando Relaciones
Identificando Atributos
Identificando Mtodos
Modelacin Utilizando UML
Lecturas:

Requerida:
o Barker, primera edicin, captulo 10 (pginas 213
30).
o Barker, segunda edicin, captulo 10 (pginas 355
72).
Secuencia: Leer el libro de texto antes de leer esta pgina.

El Proceso de Modelar Clases


El diseo orientado a objetos es el proceso de construir un modelo de objetos para un
sistema que ser desarrollado. Un modelo de objetos especifica las clases, sus atributos y
mtodos y sus relaciones con otras clases. En esta pgina, describiremos una tcnica para
crear un modelo de objetos a partir de la especificacin de un sistema. En la pgina
Modelando el Sistema de Biblioteca utilizaremos esta tcnica para modelar el sistema de
una biblioteca.
Los pasos para crear un modelo de objetos a partir de la especificacin de un sistema son
los siguientes:
1.
2.
3.
4.
5.

Identificar clases de objetos a partir de la especificacin del sistema.


Identificar relaciones entre clases.
Identificar los atributos de cada clase.
Identificar los mtodos de cada clase.
Modelar el sistema utilizando UML.

Identificando Clases
Una manera sencilla de identificar las clases es analizar la descripcin textual en la
especificacin del sistema. En este anlisis textual, los sustantivos y las frases de
sustantivos indican con frecuencia los objetos y sus clases. Los sustantivos en singular
("libro", "catlogo de biblioteca" y "cliente") y los sustantivos en plural ("usuarios",
"libros" y "cuentas") indican clases. Los sustantivos propios ("el banco ACME") y los
sustantivos de referencia directa ("la persona que posea la cuenta") indican objetos.

Los pasos para identificar las clases utilizando el anlisis del texto son los siguientes:

Hacer una lista con los sustantivos de la especificacin.

Reducir la lista:
o Convertir los sustantivos en plural a su forma singular. En un modelo de
objetos, los nombres de clases estn en singular.
o Eliminar los sustantivos que representen objetos. Reemplazar con
sustantivos genricos. Por ejemplo, utiliza "cliente" en vez de "John Smith."
o Eliminar los sustantivos vagos.
o Eliminar los sustantivos que son atributos de clases. Si no puedes identificar
los atributos del sustantivo, es posible que el sustantivo haga referencia a un
atributo de la clase.

Agrupa los sinnimos y elige el mejor nombre para la clase a partir de este grupo.
Por ejemplo, "usuario" y "cliente" son sinnimos. En un sistema bancario, el mejor
nombre es "cliente" porque el sistema puede tener dos tipos de usuarios: los clientes
y los empleados del banco.

Seleccionar las clases que son relevantes para el sistema.

Busca ms clases relevantes. Analiza el dominio de la aplicacin para encontrar:


o Cosas fsicas. Por ejemplo, "persona", "libro" y "computadora".
o Roles jugados por personas u organizaciones. Por ejemplo, "jefe" y
"proveedor."
o Objetos que representan una ocurrencia o evento. Por ejemplo, "cada del
sistema", "vuelo" y "clic del ratn."
o Objetos que representan una relacin entre otros objetos del modelo. Por
ejemplo, "compra" (relacionada con "comprador", "vendedor" y
"mercanca") y "matrimonio" (relacionado con "hombre" y "mujer").
o Personas que desempean alguna funcin. Por ejemplo, "estudiante" y
"oficinista".
o Lugares. Por ejemplo, "biblioteca", "saln de clases" y "banco".
o Colecciones de objetos, personas, recursos o facilidades. Por ejemplo,
"catlogo" y "grupo".
o Conceptos o ideas que son intangibles. Por ejemplo, "dinero" y "cuenta de
banco".

Identificando Relaciones
Los pasos para identificar las relaciones de asociacin y de especializacin/generalizacin
son los siguientes:

Crear una tabla n x n donde n es el nmero de clases. Nombra las filas y columnas
con los nombres de las clases.

Para identificar las relaciones de especializacin/generalizacin, realiza las


siguientes preguntas para cada celda de la fila A y la columna B:
o Es una instancia de la clase A, una instancia de la clase B?
o Es una instancia de la clase B, una instancia de la clase A?
Si la respuesta a las dos preguntas es s, entonces los nombres de clases pueden ser
sinnimos.
Si la respuesta a la primera pregunta es s, entonces la clase A es una especializacin
de la clase B. Marca con una S la celda de la fila A y la columna B.
Si la respuesta a la segunda pregunta es s, entonces la clase A es una generalizacin
de la clase B. Marca con una G la celda de la fila A y la columna B.

Para identificar las relaciones de asociacin, evala cada celda de la fila A y B:


o Si no hay asociacin entre la clase A y la clase B, marca la celda con una X.
o Si hay una o ms asociaciones entre la clase A y la clase B, entonces inserta
los atributos de la asociacin. Por ejemplo, "piloto", "esposa", "cuentas" y
"clientes."

La siguiente tabla muestra las relaciones del enunciado "un cliente es una persona que tiene
una o ms cuentas".
Persona

Cliente

Cuenta

Persona

Cliente

cuentas

Cuenta

Esta tabla indica que la clase Cliente es una especializacin de la clase Persona y la clase
Persona tiene una relacin de asociacin con la clase Cuenta.

Identificando Atributos
Los atributos son los datos que un objeto es responsable de conocer y administrar. Los
pasos para identificar los atributos de las clases son los siguientes:

Buscar los adjetivos y las frases posesivas como "X de Y" en la especificacin del
sistema. Por ejemplo, "nmero de la cuenta" y "nombre del cliente".

Utiliza tu conocimiento del dominio de la aplicacin para definir el conjunto de


atributos necesarios para que el sistema sea desarrollado.

Identificando Mtodos

Los mtodos describen las acciones que un objeto es responsable de proveer. Los pasos
para identificar los mtodos de las clases son los siguientes:

Para identificar comportamientos, busca verbos. Por ejemplo, el enunciado


"el cliente deposita dinero en la cuenta"
Indica que la clase Cuenta debe definir un mtodo depsito.

Utiliza tu conocimiento del dominio de la aplicacin para definir el conjunto de


mtodos necesarios para desarrollar el sistema. Busca en el dominio de la aplicacin
las acciones que:
o Creen e inicialicen nuevas instancias.
o Establezcan y obtengan los valores de los atributos.
o Carguen y guarden desde un almacenamiento persistente.
o Destruyan instancias.
o Realicen clculos utilizando los valores de un objeto.
o Generen como salida o desplieguen un resultado.

Si el objeto tiene alguna coleccin, incluye los mtodos necesarios para aadir,
eliminar y acceder los elementos de estas colecciones.

Modelacin Utilizando UML


Los pasos para producir un diagrama de clase UML son los siguientes:

Utilizar la notacin de clases para representar clases. Incluir los atributos y mtodos.

Utilizar la notacin de ligas para describir las relaciones de asociacin y de


especializacin/generalizacin entre las clases. Para las asociaciones, especifica la
multiplicidad y el nombre del atributo asociado con la relacin.

Referencias:
Lee, Richard, y William M. Tepfenhart. Practical Object-Oriented Development with UML
and Java (Desarrollo Orientado a Objetos Prctico con UML y Java). Upper Saddle River,
NJ: Prentice-Hall, 2002.

1.2.6 Modelando el Sistema de Biblioteca

Especificacin del Sistema de Biblioteca


Identificando Clases
Identificando Relaciones
Identificando Atributos
Identificando Mtodos
Modelacin Utilizando UML

Especificacin del Sistema de Biblioteca


El sistema de biblioteca mantiene la informacin de los artculos que los usuarios tienen
prestados.
El sistema contiene un catlogo de los artculos que posee la biblioteca. Hay dos tipos de
artculos en el catlogo: libros y grabaciones. Todos los artculos del catlogo estn
identificados por un cdigo nico. (Si la biblioteca posee varias copias del mismo libro o
grabacin, cada copia tiene un cdigo nico). La informacin de cada artculo incluye
ttulo, ao y disponibilidad. Un artculo est disponible si no ha sido prestado.
Adems:

La informacin de un libro incluye el autor y el nmero de pginas.


La informacin de una grabacin incluye el intrprete y el formato (CD o cinta).

El sistema contiene una base de datos de los usuarios. Cada usuario tiene un cdigo de
identificacin nico, adems de un nombre. El sistema mantiene una lista, para cada
usuario, del catlogo de artculos que ste tiene prestados.
El sistema de biblioteca debe ser capaz de:

Desplegar el catlogo, enlistando el cdigo, el ttulo y la disponibilidad de cada


artculo.
Desplegar un artculo del catlogo.
Desplegar los usuarios enlistando el cdigo de identificacin y el nombre de cada
usuario.
Desplegar los artculos del catlogo prestados a un usuario.
Prestar (check out) un artculo del catlogo, aadiendo el artculo a la lista de
artculos prestados del usuario.
Regresar (check in) un artculo del catlogo, eliminando el artculo de la lista de
artculos prestados del usuario.

Identificando Clases
Primero, hacemos una lista de los sustantivos en la especificacin del sistema:

sistema de biblioteca libro

CD

artculos

grabacin

cinta

usuarios

copia

base de datos de los


usuarios

sistema

informacin

usuario

catlogo

artculo

cdigo de
identificacin

biblioteca

ttulo

nombre

tipos

ao

lista

artculos del catlogo disponibilidad

usuario

libros

autor

cdigo (usuario)

grabaciones

nmeros de pgina

lista de artculos
prestados

cdigo (artculo)

intrprete

copias

formato
Entonces, reducimos la lista eliminando los siguientes nombres:
cdigo (artculo), ttulo, ao,
disponibilidad

Estos nombres son atributos de un


artculo del catlogo.

autor, nmero de pginas

Estos nombres son atributos de un


libro.

intrprete, formato

Estos nombres son atributos de un


artculo de grabacin.

CD, cinta

Estos nombres son valores del atributo


formato.

nombre, cdigo de
Estos nombres son atributos de un
identificacin, cdigo (usuario) usuario.
informacin

Este nombre es un trmino genrico


para los atributos de la clase.

tipos

Este nombre no es relevante para el


sistema.

A continuacin, agrupamos los sinnimos y elegimos el mejor nombre para la clase de cada
grupo:

CatalogItem

artculos, artculos del


catlogo, copias, copia,
artculo

LibrarySystem

sistema de biblioteca, sistema,


biblioteca

Borrower

usuarios, usuario

Book

libros, libro

Recording

grabaciones, grabacin

BorrowedItems

lista, lista de artculos


prestados

BorrowerDatabase

base de datos de los usuarios

Finalmente, seleccionamos las clases que son relevantes para el sistema:


LibrarySystem
Catalog
CatalogItem
Book
Recording
Borrower
BorrowedItems
BorrowerDatabase

Identificando Relaciones
La siguiente tabla identifica las relaciones de especializacin/generalizacin:

Figura 1 Tabla de relaciones

Identificando Atributos
A continuacin se presenta la lista de atributos para cada clase:

Clase

Atributos

LibrarySystem

catalog, borrowerDB

Catalog

items

CatalogItem

code, title, year, available

Book

author, numberOfPages

Recording

performer, format

Borrower

name, id, borrowedItems

BorrowedItems

items

BorrowerDatabase

borrowers

Identificando Mtodos
A continuacin se presenta la lista de mtodos de cada clase:
Clase

Mtodos

LibrarySystem

displayCatalog()
displayCatalogItem()
displayBorrowerDatabase()
displayBorrower()
checkIn()
checkOut()

Catalog

addItem(item:CatalogItem)
getItem(index:int):CatalogItem
getNumberOfItems():int
getItem(code:String):CatalogItem

CatalogItem

getCode():String
getTitle():String
getYear():int
isAvailable():boolean
setAvailable(value:boolean)

Book

getAuthor():String
getNumberOfPages():int

Recording

getPerformer():String
getFormat():String

Borrower

getId():String
getName():String
getBorrowedItems():BorrowedItems

BorrowedItems

addItem(item:CatalogItem)
removeItem(item:CatalogItem)
getItem(index:int):CatalogItem
getItem(code:String):CatalogItem
getNumberOfItems():int

BorrowerDatabase addBorrower(borrower:Borrower)
getBorrower(index:int):Borrower

getNumberOfBorrowers():int
getBorrower(id:String):Borrower

Modelacin Utilizando UML


El siguiente es un diagrama de clase del sistema de biblioteca:

Figura 2 Diagrama de clase del sistema de biblioteca

Unidad 2. Implementacin de Clases

2.1 Implementando Clases


2.2 Colecciones
2.3 Diseo Avanzado de Clases

2.1 Implementando Clases

2.1.1 Definiendo Clases


2.1.2 Herencia
2.1.3 Mtodo equals y Mtodo toString
2.1.4 Prueba de Unidades
2.1.5 Implementando el Sistema de Biblioteca

2.1.1 Definiendo Clases

Variables y Mtodos Estticos


Mtodos Selectores (Accesors) y Modificadores (Mutators)
Lecturas:

Requeridas:
o Barker, primera edicin, captulo 3 (pginas 5962),
captulo 4 (pginas 83109), captulo 7 (pginas 17985), captulo 13 (pginas 326-33).
o Barker, segunda edicin, captulo 3 (pginas 6871),
captulo 4 (pginas 97161), captulo 7 (pginas 31320).

Secuencia: Lee el libro de texto antes de leer esta pgina.

Variables y Mtodos Estticos


Considera una clase que contiene una variable de instancia. Cada vez que se crea una
instancia de esa clase, se asigna memoria para la variable de instancia; por consiguiente,
cada instancia de la clase tendr su propia copia de la variable de instancia. Esto no es
verdadero para las variables de clase. Slo existir una copia de una variable de clase.
Dicha copia es compartida por todas las instancias de la clase. Una variable de clase se
declara utilizando la palabra clave static, motivo por el cual se conoce frecuentemente
como variable esttica.
Un mtodo de clase es un mtodo que puede acceder nicamente a variables de clase. Por
el contrario, un mtodo de instancia puede acceder tanto a variables e instancias de clase.
Un mtodo de clase se declara tambin utilizando la palabra clave static, por lo que se
utiliza con frecuencia el trmino mtodo esttico.
Considera la clase Point, la cual modela un punto del plano Cartesiano (ver listado 1). La
variable de clase numberOfInstances mantiene el nmero de instancias de Point que han
sido creadas. Cada vez que se crea un objeto Point, numberOfInstances es incrementado.
El mtodo de clase getNumberOfInstances regresa la variable de clase
numberOfInstances.
1:
2:
3:
4:
5:
6:
7:
8:
9:

/**
* Esta clase modela un punto en el plano Cartesiano.
*
* @author
* @version 1.0.0
*/
public class Point {
/* Nmero de instancias creadas */

10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:

private static int numberOfInstances = 0;


/* coordenada x de este punto*/
private int x;
/* coordenada y de este punto*/
private int y;
/**
* Programa de prueba para la clase <code>Point</code>.
*
* @param args no utilizado
*/
public static void main(String[] args) {
Point pointOne = new Point(10, 100);
System.out.println("x: " + pointOne.getX());
System.out.println("y: " + pointOne.getY());
pointOne.setX(20);
pointOne.setY(200);
System.out.println("new x: " + pointOne.getX());
System.out.println("new y: " + pointOne.getY());
System.out.println("Instances before PointTwo is created: " +
Point.getNumberOfInstances());
Point pointTwo = new Point(20, 200);
System.out.println("Instances after PointTwo is created: " +
Point.getNumberOfInstances());
}
/**
* Crea un objeto <code>Point</code> e incrementa el
* nmero de instancias.
*
* @param initialX la coordenada x
* @param initialY la coordenada y
*/
public Point(int initialX, int initialY) {
this.x = initialX;
this.y = initialY;
Point.numberOfInstances++;
}
/**
* Regresa el nmero de instancias de <code>Point</code> que
* han sido creadas.
*
* @return el nmero de instancias de <code>Point</code> que
*
han sido creadas.
*/

67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:
80:
81:
82:
83:
84:
85:
86:
87:
88:
89:
90:
91:
92:
93:
94:
95:
96:
97:
98:
99:
100:
101:
102:
103:
104:
105:
106:
107:
108:
109:
110:
111: }

public static int

getNumberOfInstances()

return Point.numberOfInstances;
}
/**
* Regresa la coordenada x de este punto.
*
* @return la coordenada x de este punto.
*/
public int getX() {
return this.x;
}
/**
* Regresa la coordenada y de este punto.
*
* @return Regresa la coordenada y de este punto.
*/
public int getY() {
return this.y;
}
/**
* Modifica la coordenada x de este punto.
*
* @param newX la nueva coordenada x
*/
public void setX(int newX) {
this.x = newX;
}
/**
* Modifica la coordenada y de este punto.
*
* @param newY la nueva coordenada y
*/
public void setY(int newY) {
this.y = newY;
}

Listado 1 Point.java
La siguiente figura muestra la salida de la consola cuando el mtodo principal de la clase
Point es ejecutado:

Figura 1 Ejecucin de Point


Para llamar a un mtodo de instancia, el nombre del mtodo debe estar precedido por una
referencia de objeto:
pointOne.setX(20);

Por convencin, para llamar a un mtodo de clase, el nombre del mtodo debe estar
precedido por el nombre de la clase:
Point.getNumberOfInstances()

Esto tiene sentido porque las variables de clase no son parte de ningn objeto, por lo que
los mtodos que operan en ellos no estn asociados a ningn objeto en particular. Si las
variables de clase son pblicas, tambin son accedidas utilizando el nombre de la clase. Si
numberOfInstances fuera declarada como public, podramos escribir:
Point.numberOfInstances

Debido a que las variables de clase y los mtodos de clase no estn asociados a ningn
objeto en particular, pueden ser utilizados an y cuando no existan objetos de la clase! Por
ejemplo, podemos llamar a getNumberOfInstances antes de que se cree ningn objeto
Point.

Mtodos Selectores (Accesors) y Modificadores (Mutators)


Un mtodo selector o selector de lectura, es utilizado para recuperar el valor de una
variable de instancia. Por convencin, el nombre de un selector es getVariableName donde
VariableName es el nombre de la variable de instancia. Un mtodo modificador o selector
de escritura, es utilizado para cambiar, o mutar, el valor de una variable de instancia. Por
convencin, el nombre de un modificador es setVariableName.
Por ejemplo, la clase Point provee los selectores getX y getY y los modificadores setX y
setY.

En este material, utilizaremos el prefijo "initial" (inicial) para nombrar los parmetros de
los constructores y el prefijo "new" (nuevo) para nombrar los parmetros de los
modificadores. Esta convencin evita el error lgico que ocurre cuando un programador
utiliza el mismo nombre para un parmetro y para una variable de instancia y olvida utilizar
la palabra clave this.

2.1.2 Herencia

Implementando Relaciones de Especializacin/Generalizacin


Convirtiendo el Tipo de Objetos (Casting)
El Operador instanceof
Lecturas:

Requerida:
o Barker, primera edicin, captulo 5 (pginas 12039);
captulo 13 (pginas 305-11 and 33543).
o Barker, segunda edicin, captulo 5 (pginas 174
208).
Secuencia: Lee el libro de texto antes de leer esta pgina.

Implementando Relaciones de Especializacin/Generalizacin


Una relacin de especializacin/generalizacin es implementada en Java utilizando
herencia. La herencia es un mecanismo que crea una nueva clase "extendiendo" o
"especializando" una clase existente. La nueva clase (la subclase o clase hija) hereda las
variables y mtodos de la clase existente (la superclase o clase padre). Para declarar una
subclase, utiliza la palabra clave extends seguida por el nombre de la superclase:
public class DerivedClass extends BaseClass {
}

Por ejemplo, considera la relacin de especializacin/generalizacin presentada en el


siguiente diagrama de clase:

Figura 1 Relacin entre Person y Employee


A continuacin se presenta una implementacin de la clase Person:
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:

/**
* Esta clase modela una persona.
*
* @author
* @version 1.0.0
*/
public class Person {
/* Nombre de la persona */
private String name;
/* Direccin de la persona */
private String address;
/**
* Construye un objeto <code>Person</code>.
*
* @param initialName el nombre de la persona.
* @param initialAddress la direccin de la persona.
*/
public Person (String initialName, String initialAddress) {
this.name = initialName;
this.address = initialAddress;
}
/**
* Regresa el nombre de la persona.
*
* @return el nombre de la persona.
*/
public String getName() {
return this.name;

35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46: }

}
/**
* Regresa la direccin de esta persona.
*
* @return la direccin de esta persona.
*/
public String getAddress() {
return this.address;
}

Listado 1 Person.java
A continuacin se presenta una implementacin de la clase Employee:
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:

/**
* Esta clase modela un Empleado (Employee).
*
* @author
* @version 1.0.0
*/
public class Employee extends Person {
/* Salario del empleado */
private double salary;
/**
* Construye un objeto <code>Employee</code>.
*
* @param initialName el nombre del empleado.
* @param initialAddress la direccin del empleado.
* @param initialSalary el salario del empleado.
*/
public Employee (String initialName, String initialAddress,
double initialSalary) {
super(initialName, initialAddress);
this.salary = initialSalary;
}
/**
* Regresa el salario de este empleado.
*
* @return el salario de este empleado.
*/
public double getSalary() {
return this.salary;
}
/**
* Modifica el salario de este empleado.
*
* @param newSalary el nuevo salario.

40:
41:
42:
43:
44:
45: }

*/
public void setSalary(double newSalary) {
this.salary = newSalary;
}

Listado 2 Employee.java
En la lnea 7 de Employee.java, la clase Employee extiende la clase Person. En la lnea
22, el constructor de Employee utiliza la palabra clave super para llamar al constructor de
Person, la clase padre. Las variables de instancia name y address son declaradas en la
clase Person, de modo que el constructor de Person las inicializar. En Java, dentro de un
constructor la llamada a super debe ser siempre la primera instruccin.
Observa que una instancia de la clase Employee contiene una copia de las variables name y
address, pero los mtodos de Employee no pueden acceder estas variables. Estas variables
son declaradas como privadas en la clase Person, de modo que slo pueden ser obtenidas
por los mtodos de la clase Person. Un objeto Employee debe utilizar los mtodos getName
y getAddress, ambos heredados de Person, para acceder a los valores de name y address,
respectivamente.

Convirtiendo el Tipo de Objetos (Casting)


Un empleado es una persona, tal que todo objeto Employee es tambin un objeto Person.
Por esta razn, una variable de referencia de Employee puede ser asignada a una variable de
referencia de Person. El siguiente cdigo crea un objeto Employee y asigna la referencia de
Employee a person, una referencia de Person:
Person person = new Employee("Joe Smith", "100 Main Ave", 3000.0);

Las implicaciones de esto son inesperadas y un tanto ms confusas. La referencia person,


la cual apunta a un objeto Employee, no puede ser utilizada para llamar a los mtodos de
Employee! Si escribimos
double salary = person.getSalary();

// ilegal

el compilador protestar porque no puede encontrar un mtodo llamado getSalary en la


clase Personhasta este punto del cdigo, el compilador slo sabe que person es un
Person. Podemos utilizar la referencia person para llamar a los mtodos de Person como
getName y getAddress:
String name = person.getName();
String address = person.getAddress();

// legal
// legal

Java provee una facilidad para el problema de getSalary. Podemos cambiar la referencia
person en una referencia de Employee con el trmino de conversin de tipo (cast). Una
vez que tenemos una referencia de Employee, podemos llamar al mtodo getSalary como
se indica a continuacin:

Employee employee = (Employee) person;


double salary = employee.getSalary();
// o
double salary = ((Employee) person).getSalary();

Podemos convertir la referencia person en una referencia Employee porque person apunta
en realidad a un objeto Employee. Si no se hiciera y ejecutramos el cdigo, la conversin
sera ilegal y la mquina virtual de Java (Java Virtual Machine o JVM) lanzara una
excepcin ClassCastException.
Aunque siempre resulta legal convertir una referencia de subclase en una referencia de
superclase, hacerlo al revs no siempre es legal. Considera el siguiente cdigo:
Person person = new Person ("Joe Smith", "100 Main Ave");
double salary = ((Employee) person).getSalary();

// ilegal

Este cdigo compilar, pero cuando sea ejecutado, la JVM lanzar una excepcin
ClassCastException porque, en este ejemplo, la referencia person no apunta a un objeto
Employee.

El Operador instanceof
El operador instanceof toma dos operandos: una referencia de un objeto y un nombre de
clase. Una expresin instanceof se evaluar como verdadera si el objeto especificado es
una instancia de la clase especificada:
object instanceof ClassX

La expresin tambin resultar verdadera si object es una instancia de una subclase de


ClassX. De hecho, si object es una instancia de cualquier clase que tenga a la ClassX como
ancestro, entonces la expresin resultar verdadera. Si el operador del lado izquierdo tiene
un valor de null, la expresin instanceof resultar falsa. Observa que el operador
instanceof no puede ser utilizado para determinar el tipo de una expresin primitiva.
El operador instanceof es utilizado con frecuencia para evitar una conversin ilegal:
Person person = new Person ("Joe Smith", "100 Main Ave");
if (person instanceof Employee) {
salary = ((Employee) person).getSalary();
}

En este ejemplo, la conversin no se realiza porque la referencia person no apunta a un


objeto Employee.

2.1.3 Mtodo equals y Mtodo toString

Mtodo equals
Mtodo toString
Lecturas:

Requeridas:
o Barker, primera edicin, captulo 13 (pginas 3625).
o Barker, segunda edicin, captulo 13 (pginas 523
32).

Secuencia: Lee el libro de texto antes de leer esta pgina.

Mtodo equals
En Java, todas las clases descienden, directa o indirectamente, de la clase Object, de modo
que todas las clases heredan los mtodos definidos en la clase Object. En este curso,
utilizaremos fuertemente dos de estos mtodos, equals y toString.
El mtodo equals compara dos objetos y regresa verdadero s y solo si son iguales. La
versin de este mtodo definida en la clase Object regresa true si los objetos que estn
siendo comparados son el mismo objeto. Esta implementacin predeterminada es
exactamente lo mismo que obj1 == obj2.
El mtodo equals toma un parmetro de entrada, una referencia de Object. En Java, esto
significa que una referencia a un objeto de cualquier tipo puede ser pasada a equals. Por lo
mismo, equals puede utilizarse para comparar dos instancias de cualquier clase.
Recuerda la clase Point que estudiamos en la seccin Definiendo Clases. El siguiente
cdigo compara objetos Point utilizando el mtodo equals definido en la clase Object:
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:

Point pointOne = new Point(10, 100);


Point pointTwo = new Point(10, 100);
Point pointThree = pointOne;
if (pointOne.equals(pointTwo)) {
System.out.println("pointOne and pointTwo are equal");
} else {
System.out.println("pointOne and pointTwo are different");
}
if (pointOne.equals(pointThree)) {
System.out.println("pointOne and pointThree are equal");
} else {
System.out.println("pointOne and pointThree are different");
}

Listado 1 Comparacin de objetos Point


En la lnea 1, se crea un objeto Point y la referencia regresada por el operador new es
asignada a pointOne. En la lnea 2, se crea otro objeto Point y su referencia es asignada a
pointTwo. En la lnea 4, pointOne es asignada a pointThree de modo que ambas
referencias hacen referencia al mismo objeto. La referencia pointTwo hace referencia a un
objeto diferente:

Figura 1 Variables de referencia Point


La siguiente figura muestra la salida cuando se ejecuta el cdigo del Listado 1:

Figura 2 Ejecucin del cdigo del Listado 1


En la lnea 6, pointOne y pointTwo son comparados utilizando la implementacin
predeterminada del mtodo equals definido en la clase Object. Debido a que estas
referencias hacen referencia a diferentes objetos, se genera como salida el mensaje
"PointOne and pointTwo are different". En la lnea 12, pointOne y pointThree son
comparados. Estas referencias apuntan al mismo objeto, por lo que se genera como salida el
mensaje "PointOne and pointThree are equal".
El mtodo equals, tal y como est definido en Object, no resulta apropiado para la
mayora de las clases, por lo que muchas de ellas lo sobrescriben. La versin de equals en
la mayora de las clases regresa true cuando los objetos que se estn comparando tienen el
mismo estado, esto es, contienen los mismos datos. Por ejemplo, la clase Point podra
definir la siguiente versin de equals:
1: /**

2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:

* Sobrescribe {@link Object#equals(Object)}.


* <p>
* Dos objetos <code>Point</code> son iguales si sus coordenadas
* x y y son las mismas.
* </p>
*
* @param object objeto con el cual este punto <code>Point</code> es
*
comparado.
* @return <code>verdadero</code> si las coordenadas x y y
*
de este punto <code>Point</code> son iguales a las
coordenadas
*
x y y del argumento; <code>falso</code>
*
de otra forma.
*/
public boolean equals(Object object) {
if (object instanceof Point) {
Point point = (Point) object;
return point.getX() == getX() && point.getY() == getY();
} else {
return false;
}
}

Listado 2 Mtodos equals en la clase Point


En la lnea 17, el operador instanceof revisa si la referencia object apunta a un objeto
Point. En la lnea 19, la referencia object es convertida a una referencia Point. La
referencia point, a diferencia de la referencia object, puede ser utilizada para invocar los
mtodos de Point getX y getY. En la lnea 21, las coordenadas x y y de dos objetos Point
son comparadas. Observa que esta implementacin aplica a las comparaciones entre objetos
Point y los objetos de sus subclases.
El siguiente cdigo compara objetos Point utilizando el mtodo equals definido en la
clase Point. En este ejemplo, las tres referencias Point hacen referencia a tres diferentes
objetos.
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:

Point pointOne = new Point(10, 100);


Point pointTwo = new Point(10, 100);
Point pointThree = new Point(50, 500);
if (pointOne.equals(pointTwo)) {
System.out.println("pointOne and pointTwo are equal");
} else {
System.out.println("pointOne and pointTwo are different");
}
if (pointOne.equals(pointThree)) {
System.out.println("pointOne and pointThree are equal");

14: } else {
15:
System.out.println("pointOne and pointThree are different");
16: }

Listado 3 Comparacin de objetos Point


La siguiente figura muestra la salida cuando se ejecuta el cdigo del Listado 3:

Figura 3 Ejecucin del cdigo del Listado 3


Las referencias pointOne y pointTwo apuntan a objetos Point diferentes, pero estos
objetos contienen los mismos datos, por lo que son considerados iguales.

Mtodo toString
La clase Object define un mtodo llamado toString que regresa la representacin string
del objeto que hace la llamada. La versin de este mtodo definida en la clase Object
regresa un String con el siguiente formato:
NombreClase@numero

Donde NombreClase es el nombre de la clase del objeto y nmero es un nmero


hexadecimal que identifica al objeto.
Es recomendable que todas las subclases sobrescriban el mtodo toString. Las clases
comnmente redefinen el mtodo toString de modo que el String regresado contenga la
representacin textual del objeto. Por ejemplo, considera la siguiente versin de toString
en la clase Point:
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:

/**
* Sobrescribe {@link Object#toString()}.
* <p>
* Regresa una representacin string de este objeto
* <code>Point</code>.
* </p>
*
* @return una representacin string de este objeto
*
<code>Point</code>.
*/
public String toString() {
return

"(" + getX() + "," + getY() + ")";

Listado 4 Mtodo toString en la clase Point

En la lnea 13, los selectores getX y getY son utilizados para construir un String con el
siguiente formato:
(x,y)

El siguiente cdigo utiliza el mtodo toString definido en la clase Point. Cuando al


mtodo println se le pasa una referencia a un objeto, encuentra la cadena equivalente del
objeto especificado llamando a la versin de toString asociada con dicho objeto.
1:
2:
3:
4:
5:
6:
7:
8:

Point pointOne = new Point(10, 100);


Point pointTwo = new Point(-20, 200);
Point pointThree = new Point(50, -500);
System.out.println(pointOne);
System.out.println(pointTwo);
System.out.println(pointThree);
System.out.println();

Listado 5 Mostrando los objetos Point


La siguiente figura muestra la salida cuando se ejecuta el cdigo del Listado 5:

Figura 4 Ejecucin del cdigo del Listado 5


La salida contiene la representacin string de pointOne, pointTwo y pointThree.

2.1.4 Prueba de Unidades


Lecturas:

Opcional:
o IPL Information Processing Ltd, Why Bother to Unit
Test? (Por qu preocuparse por la Prueba de
Unidades?) Este documento introduce el concepto de
prueba de unidades y discute sus ventajas.

Opcional:
o IPL Information Processing Ltd, Designing Unit Test
Cases (Diseando Casos de Prueba de Unidades).
Este documento describe diversas tcnicas para
disear casos de prueba de unidades.

La prueba de unidades es un importante aspecto en el diseo de software. La prueba de


unidades es una tcnica que verifica si una clase, o un grupo de clases, se comportan como
es esperado. Se puede agregar una prueba de cdigo a la clase que est siendo probada en el
mtodo main o puede crearse una nueva clase dedicada a las pruebas.
Considera la siguiente clase que modela una cuenta de banco:
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:

/**
* Esta clase modela una cuenta de banco.
*
* @author
* @version 1.0.0
*/
public class BankAccount {
/* Saldo de la cuenta*/
private double balance;
/**
* Crea un nuevo objeto <code>BankAccount</code> con un saldo
* inicial de cero.
*/
public BankAccount() {
this.balance = 0.0;
}
/**
* Regresa el saldo de esta cuenta.
*
* @return el saldo de esta cuenta
*/
public double getBalance() {

27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73: }

return this.balance;
}
/**
* Deposita dinero en la cuenta. Si la cantidad especificada es
* positiva, se actualiza el saldo de la cuenta.
*
* @param amount cantidad de dinero que se aadir al saldo.
* @return <code>verdadero</code> si el dinero es depositado;
*
<code>falso</code> de otro modo.
*/
public boolean deposit(double amount) {
if (amount > 0) {
this.balance += amount;
return true;
} else {
return false;
}
}
/**
* Retira dinero de esta cuenta. Si la cantidad especificada es
* positiva y la cuenta tiene suficientes fondos, el
* saldo de la cuenta es actualizado.
*
* @param amount cantidad de dinero que se sustraer del saldo.
* @return <code>verdadero</code> si el dinero es retirado;
*
<code>falso</code> de otro modo.
*/
public boolean withdraw(double amount) {
if (amount > 0 && this.balance >= amount) {
this.balance -= amount;
return true;
} else {
return false;
}
}

Listado 1 BankAccount.java
La clase BankAccount contiene tres mtodos: uno para acceder el saldo de la cuenta; uno
para depositar dinero y otro para retirar dinero. Los mtodos deposit y withdraw tienen
cdigo defensivo: deposit no actualizar el saldo si la cantidad especificada es negativa (o
cero), mientras que withdraw no actualizar el saldo si la cuenta no tiene fondos
insuficientes. La siguiente clase es una clase manejadora de prueba para BankAccount:

1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:

import

java.io.*;

/**
* Programa de prueba para la clase <code>BankAccount</code>.
*
* @author
* @version 1.0.0
*/
public class TestBankAccount {
/* Flujo de salida estndar */
private static PrintWriter stdOut =
new PrintWriter(System.out, true);
/* Flujo de error estndar */
private static PrintWriter stdErr =
new PrintWriter(System.err, true);
/**
* Programa de prueba para la clase <code>BankAccount</code>.
*
* @param args no utilizado.
*/
public static void main(String[] args) {
boolean result;
// Probando el constructor y el accesor
BankAccount accountOne = new BankAccount();
assertTrue("1: testing method getBalance()",
accountOne.getBalance() == 0);
//Probando el mtodo deposit
BankAccount accountTwo = new BankAccount();
result = accountTwo.deposit(100);
assertTrue("2: testing method deposit", result);
assertTrue("3: testing method deposit",
accountTwo.getBalance() == 100);
result = accountTwo.deposit(50);
assertTrue("4: testing method deposit", result);
assertTrue("5: testing method deposit",
accountTwo.getBalance() == 150);
result = accountTwo.deposit(0);
assertTrue("6: testing method deposit", ! result);
assertTrue("7: testing method deposit",
accountTwo.getBalance() == 150);
result = accountTwo.deposit(-25);
assertTrue("8: testing method deposit", ! result);
assertTrue("9: testing method deposit",
accountTwo.getBalance() == 150);
//Probando el mtodo withdraw

58:
BankAccount accountThree = new BankAccount();
59:
60:
accountThree.deposit(100);
61:
result = accountThree.withdraw(60);
62:
assertTrue("10: testing method withdraw", result);
63:
assertTrue("11: testing method withdraw",
64:
accountThree.getBalance() == 40);
65:
66:
result = accountThree.withdraw(50);
67:
assertTrue("12: testing method withdraw", ! result);
68:
assertTrue("13: testing method withdraw",
69:
accountThree.getBalance() == 40);
70:
71:
result = accountThree.withdraw(0);
72:
assertTrue("14: testing method withdraw", ! result);
73:
assertTrue("15: testing method withdraw",
74:
accountThree.getBalance() == 40);
75:
76:
result = accountThree.withdraw(-10);
77:
assertTrue("16: testing method withdraw", ! result);
78:
assertTrue("17: testing method withdraw",
79:
accountThree.getBalance() == 40);
80:
81:
stdOut.println("done");
82:
}
83:
84:
/**
85:
* Despliega un mensaje en el flujo de salida estndar si el
86: valor
87:
* especificado por el argumento <code>condition<code> es
88:
* <code>falso</code>.
89:
*
90:
* @param message el mensaje de error.
91:
* @param condition la condicin de prueba.
92:
*/
93:
public static void assertTrue(String message,
94:
boolean condition) {
95:
96:
if (! condition) {
97:
stdErr.print("** Test failure ");
98:
stdErr.println(message);
99:
}
100:
}
}

Listado 2 TestBankAccount.java
Observa que el operador -! est separado de su operando por un espacio para enfatizar la
negacin de la expresin.
El mtodo assertTrue facilita la escritura de casos de prueba. Tiene dos parmetros de
entrada: un String y un boolean. El primer argumento debe ser un mensaje de error. El
mensaje ser desplegado si el segundo argumento indica algn problema. El segundo
argumento debe ser el resultado de una prueba o una expresin de prueba, tal como:

accountTwo.getBalance() == 100

El mtodo main de la clase de prueba comienza con un caso de prueba para el constructor
de BankAccount y el selector getBalance. Contina con diversos casos de prueba para el
mtodo deposit; los casos de prueba aseguran que deposit trabaja correctamente tanto
con argumentos vlidos como invlidos. Concluye con casos de prueba para withdraw que
consideran varios escenarios posibles.

2.1.5 Implementando el Sistema de Biblioteca

Clases del Sistema de Biblioteca


La Clase CatalogItem
La Clase Book
La Clase Recording
La Clase Borrower

Clases del Sistema de Biblioteca


El Sistema de Biblioteca lleva un registro de los elementos que los usuarios han pedido
prestados. Esta pgina describe la implementacin de los constructores, selectores
(accessors), modificadores (mutators), el mtodo equals y el mtodo toString de algunas
de las clases del Sistema de Biblioteca.
El siguiente diagrama de clase muestra una porcin del Sistema de Biblioteca:

Figura 1 Porcin del diagrama de clase del Sistema de Biblioteca

La Clase CatalogItem
La Clase CatalogItem modela un elemento del catlogo de la biblioteca.
Variables de instancia:

code. El cdigo nico que identifica el elemento del catlogo.


title. El ttulo del elemento del catlogo
year. El ao en que fue publicado el elemento del catlogo.
available. Indica si el elemento del catlogo est disponible.

Constructor y mtodos:

public CatalogItem(String initialCode,


String initialTitle,
int initialYear)

Constructor que inicializa las variables de instancia code, title, year y


available.

public String getCode().

public String getTitle().

public int getYear().

public void setAvailable(boolean value).


instancia available.

public boolean isAvailable().


available.

boolean equals(Object object). Sobrescribe el mtodo equals de


Object. Dos objetos CatalogItem son iguales si sus cdigos son iguales.

String

Regresa el valor de la variable de instancia code.


Regresa el valor de la variable de instancia title.

Regresa el valor de la variable de instancia year.


Modifica el valor de la variable de

Regresa el valor de la variable de instancia

la clase

toString(). Sobrescribe el mtodo toString de la clase Object.


Regresa la representacin String del objeto CatalogItem. La cadena regresada
tiene el siguiente formato:
code_title_year_available

Los campos estn separados por un guin bajo ( _ ). Suponemos que los campos en
s no contienen guiones bajos.
Implementacin:
1:
2:
3:
4:
5:
6:
7:

/**
* Esta clase modela un artculo del catlogo. Contiene la siguiente
* informacin:
* </p>
* <ol>
* <li>el cdigo del artculo, un <code>String</code></li>
* <li>el ttulo del artculo, un <code>String</code></li>

8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:

* <li>el ao en que fue publicado el artculo, un


<code>int</code></li>
* <li>un valor <code>booleano</code> si el artculo est
*
disponible</li>
* </ol>
*
* @author
* @version 1.0.0
*/
public class CatalogItem {
/* Cdigo de este artculo. */
private String code;
/* Ttulo de este artculo. */
private String title;
/* El ao en que el artculo fue publicado. */
private int year;
/* Indica si el artculo est disponible */
private boolean available;
/**
* Construye un objeto <code>CatalogItem</code>.
* <p>
* Establece la variable de instancia <code>available</code>
* como <code>verdadero</code>.
* <p>
*
* @param initialCode el cdigo del artculo.
* @param initialTitle el ttulo del artculo.
* @param initialyear el ao en que el artculo fue publicado.
*/
public CatalogItem(String initialCode, String initialTitle,
int initialyear) {
this.code = initialCode;
this.title = initialTitle;
this.year = initialyear;
this.available = true;
}
/**
* Regresa el cdigo de este artculo.
*
* @return el cdigo de este artculo.
*/
public String getCode() {
return

this.code;

}
/**
* Regresa el ttulo de este artculo.
*
* @return el ttulo de este artculo.

65:
*/
66:
public String getTitle() {
67:
68:
return this.title;
69:
}
70:
71:
/**
72:
* Regresa el ao en que el artculo fue publicado.
73:
*
74:
* @return el ao en que el artculo fue publicado.
75:
*/
76:
public int getYear() {
77:
78:
return this.year;
79:
}
80:
81:
/**
82:
* Establece la variable de instancia <code>available</code>.
83:
*
84:
* @param value el nuevo valor.
85:
*/
86:
public void setAvailable(boolean value) {
87:
88:
this.available = value;
89:
}
90:
91:
/**
92:
* Regresa <code>true</code> si el artculo est disponible.
93:
*
94:
* @return <code>true</code> si el artculo est disponible;
95:
*
<code>false</code> de otra forma.
96:
*/
97:
public boolean isAvailable() {
98:
99:
return this.available;
100:
}
101:
102:
/**
103:
* Regresa <code>true</code> si el cdigo de este artculo del
104: catlogo es
105:
* igual al cdigo del argumento
106:
* </p>
107:
*
108:
* @param object objeto contra el cual se compara este artculo
109: del catlogo.
110:
* @return <code>true</code> si el cdigo de este artculo del
111: catlogo es
112:
*
igual al cdigo del argumento; <code>false</code>
113:
*
de otro modo.
114:
*/
115:
public boolean equals(Object object) {
116:
117:
return object instanceof CatalogItem
118:
&& getCode().equals(((CatalogItem) object).getCode());
119:
}
120:
121:
/**

122:
* Regresa la representacin string de este artculo del
123: catlogo.
124:
*
125:
* @return la representacin string de este artculo del
126: catlogo.
127:
*/
public String toString() {
return

getCode() + "_" + getTitle() + "_" + getYear()


+ "_" + isAvailable();

}
}

Listado 1 CatalogItem.java

La Clase Book
La clase Book modela un libro. Extiende la clase CatalogItem.
Variables de instancia:

author. El autor del libro


numberOfPages. El nmero

de pginas del libro

Constructor y mtodos:

public Book(String initialCode,


String initialTitle,
int initialYear,
String initialAuthor,
int initialNumberOfPages)

Constructor que inicializa las variables de instancia code, title, year, available,
author y numberOfPages.

public String getAuthor().

public int getNumberOfPages().


numberOfPages.

String toString(). Sobrescribe el mtodo toString de la clase Object. Regresa


la representacin String del objeto Book. La cadena regresada tiene el siguiente

Regresa el valor de la variable de instancia author.


Regresa el valor de la variable de instancia

formato:
code_title_year_available_author_numberOfPages

Los campos estn separados por un guin bajo ( _ ). Suponemos que los campos no
contienen ningn guin bajo.

Implementacin:
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:

/**
* Esta clase modela un libro. Extiende {@link CatalogItem} y
* aade la siguiente informacin:
* <ol>
* <li>el autor del libro, un <code>String</code></li>
* <li>el nmero de pginas del libro, un <code>int</code></li>
* </ol>
*
* @author
* @version 1.0.0
* @see CatalogItem
*/
public class Book extends CatalogItem {
/* Autor del libro.*/
private String author;
/* Nmero de pginas del libro.*/
private int numberOfPages;
/**
* Construye un objeto <code>Book</code>.
*
* @param initialCode el cdigo del libro.
* @param initialTitle el ttulo del libro.
* @param initialYear el ao en que fue publicado el libro.
* @param initialAuthor el autor del libro.
* @param initialNumberOfPages el nmero de pginas del libro.
*/
public Book(String initialCode, String initialTitle,
int initialYear, String initialAuthor,
int initialNumberOfPages) {
super(initialCode, initialTitle, initialYear);
this.author = initialAuthor;
this.numberOfPages = initialNumberOfPages;
}
/**
* Regresa el autor de este libro.
*
* @return el autor de este libro.
*/
public String getAuthor() {
return

this.author;

}
/**
* Regresa el nmero de pginas de este libro.
*
* @return el nmero de pginas de este libro.
*/

55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70: }

public int
return

getNumberOfPages()

this.numberOfPages;

}
/**
* Regresa la representacin string de este libro.
*
* @return la representacin string de este libro.
*/
public String toString() {
return

super.toString() + "_" + getAuthor() + "_"


+ getNumberOfPages();

Listado 2 Book.java

La Clase Recording
La clase Recording modela una grabacin, ya sea un CD o una cinta. Extiende la clase
CatalogItem.
Variables de instancia:

performer. El intrprete
format. El formato de la

de la grabacin
grabacin

Constructor y mtodos:

public Recording(String initialCode,


String initialTitle,
int initialYear,
String initialPerformer,
String initialFormat)

Constructor que inicializa las variables de instancia code, title, year, available,
performer y format.

public String getPerformer().


performer.

public String getFormat().

String toString(). Sobrescribe el mtodo toString de la clase Object.


la representacin String del objeto Recording. La cadena regresada

Regresa el valor de la variable de instancia

Regresa el valor de la variable de instancia format.

siguiente formato:
code_year_available_title_performer_format

Regresa
tiene el

Los campos estn separados por un guin bajo ( _ ). Suponemos que los campos no
contienen guiones bajos.
Implementacin:
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:

/**
* Esta clase modela una grabacin. Extiende {@link CatalogItem} y
* aade la siguiente informacin:
* <ol>
* <li>el intrprete de la grabacin, un <code>String</code></li>
* <li>el formato de la grabacin, un <code>String</code></li>
* </ol>
*
* @author
* @version 1.0.0
* @see CatalogItem
*/
public class Recording extends CatalogItem {
/* Intrprete de la grabacin. */
private String performer;
/* Formato de la grabacin. */
private String format;
/**
* Construye un objeto <code>Recording</code>.
*
* @param initialCode el cdigo del catlogo de artculos.
* @param initialTitle el ttulo del catlogo de artculos.
* @param initialYear el ao del catlogo de artculos.
* @param initialPerformer el intrprete de la grabacin.
* @param initialFormat el formato de la grabacin.
*/
public Recording(String initialCode, String initialTitle,
int initialYear, String initialPerformer,
String initialFormat) {
super(initialCode, initialTitle, initialYear);
this.performer = initialPerformer;
this.format = initialFormat;
}
/**
* Regresa el intrprete de esta grabacin.
*
* @return el intrprete de esta grabacin.
*/
public String getPerformer() {
return
}
/**

this.performer;

51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70: }

* Regresa el formato de esta grabacin.


*
* @return el formato de esta grabacin.
*/
public String getFormat() {
return

this.format;

}
/**
* Regresa la representacin string de esta grabacin.
*
* @return la representacin string de esta grabacin.
*/
public String toString() {
return

super.toString() + "_" + getPerformer() + "_"


+ getFormat();

Listado 3 Recording.java

La Clase Borrower
La clase Borrower modela un usuario de la biblioteca.
Variables de instancia:

id. El nmero de identificacin


name . El nombre de un usuario

del usuario

Constructor y mtodos:

public Borrower(String initialId,


String initialName)

Constructor que inicializa las variables de instancia id y name.

public String getId().

public String getName().

boolean equals(Object object). Sobrescribe el mtodo equals de la clase


Object. Dos objetos Borrower son iguales si sus nmeros de identificacin son

Regresa el valor de la variable de instancia id.


Regresa el valor de la variable de instancia name.

iguales.

String toString(). Sobrescribe el mtodo toString de la clase Object. Regresa


la representacin String del objeto Borrower. La representacin String tiene el

siguiente formato:

id_name

Los campos estn separados por un guin bajo ( _ ). Suponemos que los campos no
contienen guiones bajos.
Implementacin:
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:

/**
* Esta clase modela un usuario de una biblioteca. Contiene la
siguiente
* informacin:
* <ol>
* <li>El id del usuario, un <code>String</code></li>
* <li>El nombre del usuario, un <code>String</code></li>
* <li>Los artculos que han sido prestados al usuario,
*
un objeto <code>BorrowedItems</code></li>
* </ol>
*
* @author
* @version 1.0.0
* @see BorrowedItems
* @see CatalogItem
*/
public class Borrower {
/* Nmero de identificacin del usuario.*/
private String id;
/* Nombre del usuario.*/
private String name;
/* Artculos prestados al usuario.*/
private BorrowedItems borrowedItems;
/**
* Construye un objeto <code>Borrower</code>.
* <p>
* La coleccin de artculos prestados inicialmente est vaca.
* </p>
*
* @param initialId el id del usuario.
* @param initialName el nombre del usuario.
*/
public Borrower(String initialId, String initialName) {
this.id = initialId;
this.name = initialName;
this.borrowedItems = new BorrowedItems();
}
/**
* Regresa el nmero de identificacin de este usuario.
*
* @return el nmero de identificacin de este usuario.
*/

49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:
80:
81:
82:
83:
84:
85:
86:
87:
88:
89:
90:
91:
92:
93:
94:
95:
96:
97:

public String
return

getId()

this.id;

}
/**
* Regresa el nombre de este usuario.
*
* @return el nombre de este usuario.
*/
public String getName () {
return

this.name;

}
/**
* Regresa la coleccin de artculos prestados.
*
* @return un objeto {@link BorrowedItems}.
*/
public BorrowedItems getBorrowedItems () {
return

this.borrowedItems;

}
/**
* Regresa <code>true</code> si el id de este usuario es
* igual al id del argumento.
*
* @param object objeto contra el cual se compara este usuario.
* @return <code>true</code> si el id de este usuario es
*
igual al id del argumento; <code>false</code>
*
de otro modo.
*/
public boolean equals(Object object) {
return object instanceof Borrower
&& getId().equals(((Borrower) object).getId());
}
/**
* Regresa la representacin string de este usuario.
*
* @return la representacin string de este usuario.
*/
public String toString() {
return

getId() + "_" + getName();

}
}

Listado 4 Borrower.java

2.2 Colecciones

2.2.1 Arreglos
2.2.2 ArrayList e Iteradores
2.2.3 Implementando las Colecciones del Sistema de Biblioteca

2.2.1 Arreglos

Arreglos
Declaracin y Utilizacin de Arreglos
Un Ejemplo del Uso de Arreglos
Lecturas:

Requeridas:
o Barker, primera edicin, captulo 6 (pginas 1438);
captulo 13 (pginas 3168).
o Barker, segunda edicin, captulo 6 (pginas 219
27).

Secuencia: Lee el libro de texto antes de leer esta pgina.

Arreglos
Un arreglo es un agregado homogneo, es decir, una coleccin de datos (cada uno de los
cuales es del mismo tipo). En Java, un arreglo puede contener un conjunto de datos
primitivos o un conjunto de referencias de objetos. Cada pieza del arreglo se llama
elemento. Para acceder a un elemento de un arreglo, utiliza el operador de corchetes ( [] ) y
un ndice entero que indica la ubicacin del elemento en el arreglo. El primer elemento en
un arreglo tiene un ndice 0, el segundo tiene un ndice 1 y as sucesivamente. Por lo tanto,
los ndices en un arreglo de n elementos estarn en el rango de 0 a n - 1. Los elementos
del arreglo son almacenados contiguamente en memoria.

Declaracin y Utilizacin de Arreglos


Un arreglo es declarado especificando el tipo de sus elementos, seguido por corchetes.
Considera la siguiente declaracin:
int[]

ages;

El tipo de los elementos del arreglo es int, mientras que el tipo del arreglo en s es int[].
El nombre del arreglo es el identificador ages. Considera otra declaracin:
String[]

names;

Esta instruccin declara un arreglo de tipo String, una coleccin de referencias String.
Las variables ages y names son variables de referencia y sus valores son null inicialmente.
Cada una de ellas permanecer siendo null hasta que se cree un objeto arreglo. (En Java,
los arreglos son implementados como objetos).
Para crear un objeto arreglo, utiliza el operador new, seguido por el tipo de los elementos y
el tamao del arreglo deseado. El tamao del arreglo no debe ser negativo.

ages = new int[5];


names = new String[3];

Cuando se crea un nuevo objeto arreglo, sus elementos son inicializados a sus valores
predeterminados. Por ejemplo, los elementos del arreglo ages son inicializados en cero y
los elementos del arreglo names son inicializados en null. Un objeto arreglo contiene una
variable de instancia public llamada length, la cual indica el nmero de elementos del
arreglo. La longitud de un objeto arreglo no puede cambiar nunca. Sin embargo, una
referencia de un arreglo puede ser cambiada de modo que haga referencia a otro objeto
arreglo, con una longitud diferente. Considera lo siguiente:
int[] values = new int[5];
int[] biggerArray = new int[10];
int nextIndex = 0;
...
if (nextIndex >= values.length) {
values = biggerArray;
}

Al inicio de este fragmento de cdigo, la referencia values hace referencia a un arreglo de


5 elementos; al final, hace referencia a un arreglo de 10 elementos.
Existe otra forma de crear un objeto arreglo: la declaracin del arreglo puede incluir un
inicializador, el cual es una lista separada por comas de los elementos iniciales entre
corchetes. Un inicializador puede ser utilizado solamente en la instruccin de declaracin.
int[] ages = {21, 19, 35, 27, 55};
String[] names = {"Bob", "Achebe", null};

La longitud del arreglo se deduce del nmero de elementos del inicializador. En el arreglo
ages, el primer elemento (el elemento que se encuentra en la posicin 0) se establece como
21; el segundo elemento como 19 y as sucesivamente. En el arreglo names, los primeros
dos elementos hacen referencia a objetos String, mientras que la ltima referencia es
null.
Recuerda que un elemento del arreglo es accedido utilizando el operador de corchetes y un
ndice. Considera la siguiente expresin. El primer elemento tienen un ndice 0, por lo que
el ndice 2 indica el tercer elemento del arreglo:
ages[2]

La

// el tercer elemento

Mquina

Virtual

de

Java
(JVM)
lanzar
una
excepcin
ArrayIndexOutOfBoundsException si un programa trata de utilizar un ndice invlido. Un
ndice negativo siempre es invlido. Si un arreglo contiene n elementos, entonces un ndice
n o mayor es invlido.
Debido a que ages es un arreglo de enteros (int), la expresin ages[2] es un int. De
forma similar, names es un arreglo de referencias String de modo que la expresin

es una referencia a un objeto String y puede ser utilizado cada vez que se
requiera una referencia String. De este modo, si:
names[1]

String[] names = {"Bob", "Achebe"}

entonces, la siguiente expresin resultar false porque el primer y el segundo elemento del
arreglo hacen referencia a objetos String que no son iguales.
names[0].equals(names[1])

Tpicamente, los arreglos son recorridos en orden secuencial utilizando bucles for. El
siguiente cdigo utiliza un bucle for para inicializar cada elemento en un arreglo en el
cuadrado de su ndice. Despus de que el bucle termina, el elemento cuyo ndice es 0 tiene
un valor de 0, el elemento cuyo ndice es 1 tiene un valor de 1, el elemento cuyo ndice es 2
tiene un valor de 4 y as sucesivamente.
int[]

values = new

int[5];

for (int i = 0; i < values.length; ++i)


values[i] = i * i;
}

La variable de control del bucle, i, tiene dos propsitos en el cuerpo del bucle: 1) es
utilizada como el ndice del arreglo y 2) es utilizada para calcular el valor de cada elemento
del arreglo. Observa que values.length es parte de la condicin de terminacin del bucle.
El bucle for-each provee una manera sencilla para iterar sobre los elementos de un arreglo.
En el bucle for-each se debe especificar el arreglo sobre el cual se realizar la iteracin, y
una variable para acceder a cada uno de los elementos. Por ejemplo, el siguiente cdigo
utiliza el bucle for-each para concatenar las cadenas que se encuentran en un arreglo y
despus despliega el resultado: "Arrays and for-each".
String[] words = {"Arrays", " and ", "for-each"}
String result = "";
for (String element : words) {
result += element;
}
stdout.println(result);

Un Ejemplo del Uso de Arreglos


Considera el siguiente ejemplo, una implementacin sencilla de un diccionario:
1:
2:
3:
4:
5:

import java.io.*;
/**
* Esta clase modela un diccionario
*

6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:

* @author nombre del autor


* @version 1.0.0
*/
public class Dictionary {
/* Flujo de salida estndar */
private static PrintWriter stdOut =
new PrintWriter(System.out, true);
/* Flujo de error estndar */
private static PrintWriter stdErr =
new PrintWriter(System.err, true);
/* Tamao inicial del arreglo */
private static final int INITIAL_SIZE = 5;
/* Palabras en el diccionario */
private String[] words;
/* Indica la siguiente ubicacin disponible en el arreglo */
private int nextIndex;
/**
* Prueba la implementacin de la clase <code>Dictionary</code>.
*
* @param args no utilizado.
*/
public static void main(String[] args) {
Dictionary dictionary = new Dictionary();
String[] knownWords = {"desk", "computer", "house", "dog",
"cat",
"world", "book", "money", "river",
"paper", "coffee"};
String[] unknownWords = {"maison", "haus", "casa"};
for (String word : knownWords) {
dictionary.addWord(word);
}
for (String word : knownWords) {
if (! dictionary.hasWord(word)) {
stdErr.println(
"** Test failure, word not found in the
dictionary: " +
word);
}
}
for (String word : unknownWords) {
if (dictionary.hasWord(word)) {
stdErr.println(
"** Test failure, non dictionary word found in
dictionary: "
+ word);
}

63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:
80:
81:
82:
83:
84:
85:
86:
87:
88:
89:
90:
91:
92:
93:
94:
95:
96:
97:
98:
99:
100:
101:
102:
103: de
104:
105:
106:
107:
108: de
109:
110:
111:
112:
113:
114:

}
stdOut.println("done");
}
/**
* Crea un diccionario vaco.
*/
public Dictionary() {
this.words = new String[INITIAL_SIZE];
this.nextIndex = 0;
}
/**
* Aade una nueva palabra a este diccionario.
*
* @param word la palabra que ser aadida.
*/
public void addWord(String word) {
if (this.nextIndex >= this.words.length) {
// crea un nuevo arreglo, que tiene el doble del tamao
// del arreglo actual
String[] biggerWords = new String[2 * this.words.length];
// copia los contenidos del arreglo actual
// al nuevo arreglo
for (int i = 0; i < this.words.length; i++) {
biggerWords[i] = this.words[i];
}
this.words = biggerWords;
}
this.words[this.nextIndex] = word;
this.nextIndex++;
}
/**
* Regresa <code>true</code> si la palabra especificada es parte
* este diccionario.
*
* @param word la palabra que ser buscada.
* @return <code>true</code> si la palabra especificada es parte
*
este diccionario; <code>false</code> de otra forma.
*/
public boolean hasWord(String word) {
for (int i = 0; i < this.nextIndex; i++) {
if (this.words[i].equals(word)) {
return true;
}
}
return false;
}

Listado 1 Dictionary.java
Las palabras del diccionario son almacenadas en un arreglo String. En la lnea 78, el
mtodo addWord aade una palabra al arreglo. Inicialmente, el arreglo puede almacenar
cinco cadenas. Si addWord es llamada y el arreglo est lleno, addWord crea un nuevo
arreglo (el cual tiene el doble del tamao del arreglo actual), copia los contenidos del
arreglo actual al nuevo arreglo y entonces actualiza la referencia del arreglo de modo que
apunte al nuevo arreglo.
En la lnea 105, el mtodo hasWord determina si la palabra especificada es parte del
diccionario. Busca en el arreglo secuencialmente, comenzando con el elemento 0 (es decir,
el primer elemento que se encuentra en el ndice 0).
En la lnea 33, el mtodo main prueba la implementacin de la clase Dictionary utilizando
dos arreglos: knownWords y unknownWords. En la lnea 41, el bucle for-each aade al
diccionario las cadenas de caracteres del arreglo knownWords. En la lnea 45, el bucle foreach verifica que las cadenas de caracteres hayan sido aadidas al diccionario. Por ltimo,
en la lnea 53, el bucle for-each verifica que las cadenas de caracteres del arreglo
unknownWords no sean parte del diccionario.

2.2.2 ArrayList e Iteradores

La clase ArrayList
Iteradores
Utilizando Bucles For-Each en Colecciones
Implementando Clases Colecciones
Lecturas:

Requerida:
o Barker, primera edicin, captulo 13 (pginas 3436).
o Barker, segunda edicin, captulo 6 (pginas 227-40,
pginas 249-59); captulo 13 (pginas 3168).
Nota: La primera edicin no cubre el uso de la clase
ArrayList y genricos.

Secuencia: Lee el libro de texto antes de leer esta pgina.

La Clase ArrayList
La clase java.util.ArrayList<E> implementa una coleccin de objetos que puede crecer
para alojar nuevos elementos cuando la coleccin est llena. Los objetos contenidos en el
ArrayList pueden ser accedidos utilizando un ndice entero. A continuacin se presenta
una lista de algunos de los mtodos definidos en la clase ArrayList:

ArrayList().

int size().

boolean isEmpty().

boolean contains(Object elem).

boolean add(E o).

void add(int index, E element).

E get(int index).

Construye una coleccin vaca.

Regresa el nmero de objetos en la coleccin.


Determina si no hay objetos en la coleccin.

Determina si el objeto especificado es un


elemento de la coleccin (tal como lo determina el mtodo equals).
Aade el objeto especificado al final de la coleccin.

Inserta el objeto especificado en la posicin


especificada por el ndice, moviendo cualquier elemento subsiguiente a la derecha
(incrementa sus ndices en uno).
Regresa el objeto encontrado en la posicin especificada.

public E set(int index, E element).

especificada por el ndice.

Reemplaza el elemento de la posicin

Elimina la primera ocurrencia del objeto


especificado (utilizando el mtodo equals), recorriendo los elementos
subsiguientes a la izquierda (resta uno a sus ndices).

E remove(int index).

public boolean remove(Object o).

Regresa el objeto de la posicin especificada, despus de


eliminarlo de la coleccin y de mover cualquier elemento subsiguiente a la
izquierda (resta uno a sus ndices).

La clase ArrayList almacena referencias a objetos de un tipo de datos particular.


Considera el siguiente segmento de cdigo que crea una lista de empleados y aade tres
empleados a la lista:
ArrayList<Employee> employees = new ArrayList<Employee>();
employees.add(new Employee("John Smith"));
employees.add(new Employee("Mary Williams"));
employees.add(new Employee("Peter Jefferson"));
Employee firstEmployee = employees.get(0);

Debido a que las colecciones solamente contienen referencias a objetos en lugar de tipos
primitivos, los elementos de tipos primitivos deben ser colocados en un objeto envoltorio
(wrapper) antes de ser colocados en una coleccin (por ejemplo, Integer en el caso de
elementos de tipo int). Java tiene la habilidad de automticamente envolver (box) y
desenvolver (unbox) tipos primitivos, reduciendo de esta manera la complejidad para aadir
y acceder elementos de tipos primitivos en las colecciones. El siguiente cdigo ilustra cmo
utilizar un ArrayList de enteros:
ArrayList<Integer> numbers = new ArrayList<Integer>();
numbers.add(1);
int num = numbers.get(0);

Iteradores
El mtodo iterator de la clase ArrayList regresa un objeto java.util.Iterator<E>
sobre los elementos de la coleccin. Un iterador es un objeto que se utiliza para recorrer
una coleccin de principio a fin. Adems, el uso de iteradores permite eliminar elementos
de la coleccin de forma segura durante el recorrido.
La clase java.util.Iterator<E> provee los siguientes mtodos:

boolean hasNext()

E next().

Regresa true si la iteracin tiene ms elementos.

Regresa el siguiente elemento de la iteracin.

void remove().

Elimina de la coleccin el ltimo elemento regresado por el


iterador. Este mtodo lanza la excepcin IllegalStateException si el mtodo
next no ha sido llamado o si el mtodo remove ya ha sido llamado despus de la
ltima llamada al mtodo next.

Por ejemplo, el siguiente cdigo concatena las cadenas que se encuentran en una coleccin
y despus despliega el resultado: "ArrayList and Iterators".
ArrayList<String> list = new ArrayList<String>();
list.add("ArrayList");
list.add(" and ");
list.add("Iterators");
String result = "";
for (Iterator<String> listIterator = list.iterator();
listIterator.hasNext(); ) {
result += listIterator.next();
}
stdout.println(result);

Considera el siguiente ejemplo, la implementacin sencilla de un diccionario:


1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:

import java.util.*;
import java.io.*;
/**
* Esta clase modela un diccionario
*
* @author
* @version 1.0.0
*/
public class Dictionary {
/* Flujo de salida estndar */
private static PrintWriter stdOut =
new PrintWriter(System.out, true);
/* Flujo de error estndar */
private static PrintWriter stdErr =
new PrintWriter(System.err, true);
/* Palabras en el diccionario */
private ArrayList<String> words;
/**
* Prueba la implementacin de la clase <code>Dictionary</code>.
*
* @param args no utilizado.
*/
public static void main(String[] args) {

29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:
80:
81:
82:
83:
84:
85:

Dictionary dictionary = new Dictionary();


String[] knownWords = {"host", "computer", "house", "dog",
"cat", "world", "book", "money",
"river",
"paper", "coffee"};
String[] unknownWords = {"maison", "haus", "casa"};
for (String word : knownWords) {
dictionary.addWord(word);
}
for (String word : knownWords) {
if (! dictionary.hasWord(word)) {
stdErr.println(
"** Test failure, word not found in the
dictionary: " +
word);
}
}
for (String word : unknownWords) {
if (dictionary.hasWord(word)) {
stdErr.println(
"** Test failure, non dictionary word found in
dictionary: "
+ word);
}
}
ArrayList<String> result = dictionary.getStartsWith("ho");
if (! (result.size() == 2
&& result.contains("host")
&& result.contains("house"))) {
stdErr.println("** Test failure in getStartsWith()");
}
dictionary.removeStartsWith("ho");
if (dictionary.hasWord("host") ||
dictionary.hasWord("house")) {
stdErr.println("** Test failure in removeStartsWith()");
}
stdOut.println("done");
}
/**
* Crea un diccionario vaco.
*/
public Dictionary() {
this.words = new ArrayList<String>();
}
/**
* Aade una nueva palabra a este diccionario.

86:
*
87:
* @param word la palabra que ser aadida.
88:
*/
89:
public void addWord(String word) {
90:
91:
this.words.add(word);
92:
}
93:
94:
/**
95:
* Regresa <code>true</code> si la palabra especificada
96:
* se encuentra en este diccionario.
97:
*
98:
* @param word la palabra que ser buscada.
99:
* @return <code>true</code> si la palabra especificada es parte
100:
*
de este diccionario; <code>false</code> de otro modo.
101:
*/
102:
public boolean hasWord(String word) {
103:
104:
return this.words.contains(word);
105:
}
106:
107:
/**
108:
* Regresa una coleccin con todas las palabras en este
109: diccionario que
110:
* empiezan con el prefijo especificado.
111:
*
112:
* @param prefix el prefijo.
113:
* @return un <code>ArrayList</code> de todas las palabras en
114: este
115:
*
diccionario que empiezan con el prefijo especificado.
116:
*/
117:
public ArrayList<String> getStartsWith(String prefix) {
118:
119:
ArrayList<String> result = new ArrayList<String>();
120:
121:
for (Iterator<String> wordsIterator = this.words.iterator();
122:
wordsIterator.hasNext(); ) {
123:
124:
String word = wordsIterator.next();
125:
126:
if (word.startsWith(prefix)) {
127:
result.add(word);
128:
}
129:
}
130:
131:
return result;
132:
}
133:
134:
/**
135:
* Elimina todas las palabras de este diccionario que
136:
* empiezan con el prefijo especificado.
137:
*
138:
* @param prefix el prefijo.
139:
*/
140:
public void removeStartsWith(String prefix) {
141:
142:
for (Iterator<String> wordsIterator = this.words.iterator();

143:
144:
145:
146:

wordsIterator.hasNext(); ) {
String word = wordsIterator.next();
if (word.startsWith(prefix)) {
wordsIterator.remove();
}
}
}
}

Listado 1 Dictionary.java
Las palabras del diccionario son almacenadas en una coleccin ArrayList. En la lnea 87,
el mtodo addWord llama al mtodo add de la clase ArrayList para aadir una palabra al
diccionario.
En la lnea 100, el mtodo hasWord llama al mtodo contains de la clase ArrayList para
determinar si la palabra especificada se encuentra en el diccionario.
En la lnea 115, el mtodo getStartsWith utiliza un iterador para recorrer el diccionario y
regresa un ArrayList con todas las palabras del diccionario que empiezan con el prefijo
especificado.
En la lnea 142, el mtodo removeStartsWith llama al mtodo remove de la clase
Iterator para eliminar una palabra del diccionario.

Utilizando Bucles For-Each en Colecciones


El bucle for-each provee una manera sencilla para iterar sobre los elementos de una
coleccin. En el bucle for-each se debe especificar la coleccin en donde se realizar la
iteracin, y una variable para acceder a cada uno de los elementos. El siguiente cdigo
utiliza el bucle for-each para concatenar las cadenas que se encuentran en una coleccin y
despus despliega el resultado: "ArrayList and for-each".
ArrayList<String> list = new ArrayList<String>();
list.add("ArrayList");
list.add(" and ");
list.add("for-each");
String result = "";
for (String element : list) {
result += element;
}
stdout.println(result);

El bucle for-each solamente puede ser utilizado en aquellas clases que implementan la
interfaz java.util.Iterable<T>. Una interfaz es una construccin en el lenguaje de

programacin Java que define un grupo de mtodos que se estn implementados por una
clase. Aprender ms sobre interfaces en la seccin Interfaces.
Para implementar la interfaz Iterable<T>, la clase debe incluir en la declaracin una
clusula implements y declarar el mtodo iterator.
1: public class MyCollection implements Iterable<T>
2:
3:
...
4:
5:
public Iterator<T> iterator() {
6:
...
7:
}
8: }
9:

Listado 2 Implementando la interfaz Iterable


El mtodo iterator debe regresar un objeto Iterator el cual es utilizado para obtener los
elementos almacenados en la coleccin en un orden secuencial.

Implementando Clases Colecciones


Como se mencion anteriormente, una clase coleccin modela una relacin uno-a-muchos.
La relacin uno-a-muchos puede ser implementada utilizando un ArrayList para
almacenar las instancias de la coleccin. Adems, la clase provee un grupo de mtodos para
manejar la coleccin. Por ejemplo, considere el siguiente diagrama de clase que representa
una coleccin de instancias de BankAccount.

Figura 1 Coleccin de instancias de BankAccount


En este diagrama:

La coleccin es almacenada en el atributo accounts de la clase Client .


El mtodo addAccount almacena una instancia de la clase BankAccount en la
coleccin.
El mtodo getAccountsIterator regresa un iterador sobre las cuentas de banco de
la coleccin.
El mtodo getNumberOfBankAccounts regresa el nmero de cuentas de banco en la
coleccin.

El siguiente cdigo es una implementacin de la clase Client:


1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:

import

java.util.*;

/**
* Esta clase modela un cliente de un banco. Se mantiene la siguiente
* informacin:
* <ol>
* <li>El nombre del cliente, un <code>String</code></li>
* <li>Las cuentas de banco del cliente, un
<code>ArrayList</code></li>
* </ol>
*
* @author
* @version 1.0.0
*/
public class Client implements Iterable<BankAccount> {
/* Nombre del cliente */
private String name;
/* Coleccin de objetos <code>BankAccounts</code>.*/
private ArrayList<BankAccount> accounts;
/**
* Construye un objeto <code>Client</code>.
* <p>
* Crea una coleccin vaca de cuentas de banco.
* </p>
*
* @param initialName el nombre del cliente.
*/
public Client(String initialName) {
this.name = initialName;
this.accounts = new ArrayList<BankAccount>();
}
/**
* Regresa el nombre de este cliente.
*
* @return el nombre de este cliente.
*/
public String getName() {
return this.name;
}
/**
* Aade una cuenta de banco a este cliente.
*
* @param bankAccount el objeto {@link BankAccount}.
*/
public void addAccount(BankAccount bankAccount) {
this.accounts.add(bankAccount);

55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77: }

}
/**
* Regresa un iterador sobre las cuentas de banco de este cliente.
*
* regresa un {@link Iterator} sobre las cuentas de banco de este
*
cliente.
*/
public Iterator<BankAccount> iterator() {
return this.accounts.iterator();
}
/**
* Regresa el nmero de cuentas de banco de este cliente.
*
* @return el nmero de cuentas de banco de este cliente.
*/
public int getNumberOfAccounts() {
return this.accounts.size();
}

Listado 3 Client.java
La clase Client utiliza un ArrayList para implementar la coleccin de objetos
BankAccount. La clase implemente la interfaz Iterable<BankAccount>, provee el mtodo
addAccount para aadir un objeto BankAccount a la coleccin, y provee el mtodo
iterator para acceder a los objetos BankAccount almacenados en la coleccin.
El siguiente cdigo muestra cmo utilizar la clase Client:
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:

import
import

java.util.*;
java.io.*;

/**
* Programa de prueba para la clase <code>Client</code>.
*
* @author
* @version 1.0.0
*/
public class TestClient {
/* Standard output stream */
private static PrintWriter stdOut =
new PrintWriter(System.out, true);
/* Standard error stream */
private static PrintWriter stdErr =
new PrintWriter(System.err, true);
/**
* Prueba la implementacin de la clase <code>Client</code>.

22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53: }
54:

*
* @param args no utilizado.
*/
public static void main(String[] args) {
BankAccount accountOne = new BankAccount();
BankAccount accountTwo = new BankAccount();
BankAccount accountThree = new BankAccount();
accountOne.deposit(1000.0);
accountTwo.deposit(2000.0);
accountThree.deposit(3000.0);
Client client= new Client("John Smith");
client.addAccount(accountOne);
client.addAccount(accountTwo);
client.addAccount(accountThree);
double totalBalance = 0.0;
for (BankAccount account : client) {
totalBalance += account.getBalance();
}
if (totalBalance != 6000.0) {
stdErr.println("** Test failure");
}
stdOut.println("done");
}

Listado 4 TestClient.java
La clase TestClient crea una instancia Client con tres cuentas bancarias. En la lnea 43,
la clase utiliza un bucle for-each para iterar sobre las cuentas del cliente y obtener su
balance.

2.2.3 Implementando las Colecciones del Sistema de


Biblioteca

Clases Coleccin del Sistema de Biblioteca


La Clase Catalog
La Clase BorrowedItems
La Clase BorrowerDatabase
El Sistema de Biblioteca Completo

Clases Coleccin del Sistema de Biblioteca


Esta pgina explica el uso de colecciones en el sistema de biblioteca. El siguiente diagrama
de clase resalta las clases que contienen colecciones:

Figura 1 Diagrama de clase del sistema de la biblioteca

Las siguientes clases utilizan colecciones:

Catalog
BorrowedItems
BorrowerDatabase

La Clase

Catalog

La clase Catalog utiliza una coleccin de instancias de CatalogItem e implementa la


interfaz Iterable<CatalogItem> para permitir la iteracin sobre los artculos del catalogo
utilizando bucles for-each.
Variables de instancia:

items. Una coleccin ArrayList


CatalogItem.

que contiene referencias a instancias de la clase

Constructor y mtodos:

public Catalog().

public

void

Crea la coleccin items, que inicialmente est vaco.

addItem(CatalogItem

catalogItem).

Aade el

artculo

especificado al catlogo.

public

public Iterator<CatalogItem> iterator().

CatalogItem getItem(String code). Regresa una referencia a la


instancia de CatalogItem con el cdigo especificado. Regresa null si no hay
artculos con el cdigo especificado.

Regresa un iterador sobre los

artculos del catlogo.

public int getNumberOfItems().

Regresa el nmero de artculos en el catlogo.

Implementacin:
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:

import java.util.*;
import java.io.*;
/**
* Mantiene la informacin sobre un catlogo de una biblioteca.
* Contiene una coleccin de objetos {@link CatalogItem}.
*
* @author
* @version 1.0.0
* @see CatalogItem
*/
public class Catalog implements Iterable<CatalogItem> {

14:
/* Coleccin de objetos <code>CatalogItem</code>.*/
15:
private ArrayList<CatalogItem> items;
16:
17:
/**
18:
* Construye un string vaco.
19:
*/
20:
public Catalog() {
21:
22:
this.items = new ArrayList<CatalogItem>();
23:
}
24:
25:
/**
26:
* Aade un objeto {@link CatalogItem} a este catlogo.
27:
*
28:
* @param catalogItem el objeto {@link CatalogItem}.
29:
*/
30:
public void addItem(CatalogItem catalogItem) {
31:
32:
this.items.add(catalogItem);
33:
}
34:
35:
/**
36:
* Regresa un iterador sobre los artculos de este catlogo.
37:
*
38:
* @return un {@link Iterator} de objetos {@link CatalogItem}.
39:
*/
40:
public Iterator<CatalogItem> iterator() {
41:
42:
return this.items.iterator();
43:
}
44:
45:
/**
46:
* Regresa un objeto {@link CatalogItem} con el <code>code</code>
47:
* especificado.
48:
*
49:
* @param code el cdigo de un artculo.
50:
* @return El objeto {@link CatalogItem} con el cdigo
51:
*
especificado. Regresa <code>null</code> si el objeto
52: con
53:
*
el cdigo no es encontrado.
54:
*/
55:
public CatalogItem getItem(String code) {
56:
57:
for (CatalogItem catalogItem : items) {
58:
if (catalogItem.getCode().equals(code)) {
59:
60:
return catalogItem;
61:
}
62:
}
63:
64:
return null;
65:
}
66:
67:
/**
68:
* Regresa el nmero de artculos del catlogo.
69:
*
70:
* @return el nmero de objetos {@link CatalogItem} en este

71:
72:
73:
74:
75:
76:

*
catlogo
*/
public int getNumberOfItems()

return this.items.size();
}
}

Listado 1 Catalog.java

La Clase BorrowedItems
La clase BorrowedItems modela la lista de artculos que han sido prestados a un usuario.
Utiliza una coleccin de instancias de CatalogItem e implementa la interfaz
Iterable<CatalogItem> para permitir la iteracin sobre los artculos prestados utilizando
bucles for-each.
Variables de instancia:

items. Una coleccin ArrayList


CatalogItem.

que contiene referencias a instancias de la clase

Constructor y mtodos:

public BorrowedItems().

public

void

Crea la coleccin items, que inicialmente est vaco.

addItem(CatalogItem

catalogItem).

Aade el

artculo

especificado a la lista de elementos solicitados por el usuario.

public

public Iterator<CatalogItem> iterator().

CatalogItem getItem(String code). Regresa una referencia a la


instancia CatalogItem con el cdigo especificado. Regresa null si no hay artculos
con el cdigo especificado.

Regresa un iterador sobre los

artculos prestados.

public int getNumberOfItems().

Regresa el nmero de artculos prestados.

Implementacin:
1:
2:
3:
4:
5:
6:
7:
8:
9:

import java.util.*;
import java.text.*;
/**
* Mantiene una coleccin de {@link CatalogItems}
* prestados a un usuario.
*
* @author
* @version 1.0.0

10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:

* @see CatalogItem
*/
public class BorrowedItems implements Iterable<CatalogItem>

/* Artculos del catlogo prestados a un usuario.*/


private ArrayList<CatalogItem> items;
/**
* Establece la coleccin de {@link CatalogItems} como vaca.
*/
public BorrowedItems() {
this.items = new ArrayList<CatalogItem>();
}
/**
* Aade un objeto {@link CatalogItem} a esta coleccin y
* establece el objeto {@link CatalogItem} como no disponible.
*
* @param item the {@link CatalogItem} object.
*/
public void addItem(CatalogItem catalogItem) {
this.items.add(catalogItem);
catalogItem.setAvailable(false);
}
/**
* Elimina un objeto {@link CatalogItem} de esta coleccin
* y establece el objeto {@link CatalogItem} como disponible.
*
* @param catalogItem el objeto {@link CatalogItem}.
*/
public void removeItem(CatalogItem catalogItem) {
this.items.remove(catalogItem);
catalogItem.setAvailable(true);
}
/**
* Regresa un iterador sobre los artculos prestados de esta
* coleccin.
*
* @return un {@link Iterator} de objetos {@link CatalogItem}
*/
public Iterator<CatalogItem> iterator() {
return this.items.iterator();
}
/**
* Regresa un objeto {@link CatalogItem} con el
<code>cdigo</code>
* especificado.
*
* @param code el cdigo de un artculo.
* @return El objeto {@link CatalogItem} con el cdigo

67:
*
especificado. Regresa <code>null</code> no se
68: encuentra
69:
*
el objeto con el cdigo.
70:
*/
71:
public CatalogItem getItem(String code) {
72:
73:
for (CatalogItem catalogItem : this.items) {
74:
if (catalogItem.getCode().equals(code)) {
75:
76:
return catalogItem;
77:
}
78:
}
79:
80:
return null;
81:
}
82:
83:
/**
84:
* Regresa el nmero de artculos prestados.
85:
*
86:
* @return el nmero de artculos prestados.
87:
*/
88:
public int getNumberOfItems() {
89:
90:
return this.items.size();
}
}

Listado 2 BorrowedItems.java

La Clase BorrowerDatabase
La clase BorrowerDatabase modela una base de datos de usuarios. Utiliza una coleccin
de instancias de Borrower e implementa la interfaz Iterable<Borrower> para permitir la
iteracin sobre los elementos de la base de datos utilizando bucles for-each.
Variables de instancia:

borrowers. Una
clase Borrower.

coleccin ArrayList que contiene referencias a instancias de la

Constructor y mtodos:

public BorrowerDatabase().

Crea la coleccin borrowers, que inicialmente est

vaco.

public

String

addBorrower(Borrower

borrower).

Aade

el

usuario

especificado a la base de datos.

Borrower getBorrower(String id). Regresa una referencia a la


instancia Borrower con el nmero de identificacin especificado. Regresa null si
no hay usuarios en la base de datos con el nmero de identificacin especificado.

public

public Iterator<Borrower> iterator().

Regresa un iterador sobre la base de

datos de usuarios.

public int getNumberOfItems().

Regresa el nmero de usuarios en la base de

datos.
Implementacin:
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:

import java.util.*;
import java.text.*;
/**
* Mantiene una coleccin de objetos {@link Borrower}.
*
* @author
* @version 1.0.0
* @see Borrower
*/
public class BorrowerDatabase implements Iterable<Borrower>

/* Coleccin de objetos <code>Borrower</code>.*/


private ArrayList<Borrower> borrowers;
/**
* Construye una coleccin vaca de objetos
* {@link Borrower}.
*/
public BorrowerDatabase() {
this.borrowers = new ArrayList<Borrower>();
}
/**
* Aade un usuario {@link Borrower} a la base de datos.
*
* @param borrower el objeto {@link Borrower}.
*/
public void addBorrower(Borrower borrower) {
this.borrowers.add(borrower);
}
/**
* Regresa un iterador sobre los usuarios de esta base de datos.
*
* @return un {@link Iterator} de objetos {@link Borrower}
*/
public Iterator<Borrower> iterator() {
return this.borrowers.iterator();
}
/**
* Regresa el usuario con el <code>id</code>
* especificado.

48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77: }

*
* @param id el id del usuario.
* @return El objeto {@link Borrower} con el id especificado.
*
Regresa <code>null</code> si el objeto con el id
*
especificado no es encontrado.
*/
public Borrower getBorrower(String id) {
for (Borrower borrower : this.borrowers) {
if (borrower.getId().equals(id)) {
return borrower;
}
}
return null;
}
/**
* Regresa el nmero de usuarios en esta
* base de datos.
*
* @return el nmero de usuarios en esta
*
base de datos.
*/
public int getNumberOfBorrowers() {
return this.borrowers.size();
}

Listado 3 BorrowerDatabase.java
.

2.3 Diseo Avanzado de Clases

2.3.1 Clases Abstractas


2.3.2 Polimorfismo
2.3.3 Interfaces
2.3.4 Patrones de Diseo
2.3.5 Patrn de Diseo Singular (Singleton)
2.3.6 Patrn de Diseo Estrategia (Strategy)

2.3.1 Clases Abstractas


Lecturas:

Requeridas:
o Barker, primera edicin, captulo 7 (pginas 16975).
o Barker, segunda edicin, captulo 7 (pginas 282
90).

Secuencia: Lee el libro de texto antes de leer esta pgina.


Un mtodo abstracto consiste en una firma de un mtodo sin el cuerpo del mtodo. Un
mtodo es declarado abstracto aadiendo la palabra clave abstract a la firma del mtodo.
A continuacin se presentan ejemplos de declaraciones de mtodos abstractos:
public abstract void
public abstract void

eat(int amount);
sleep(int hours);

Un mtodo abstracto debe ser declarado en una clase abstracta. Una clase abstracta se
denota utilizando el modificador abstract:
public abstract class className {
. . .
}

No se puede crear ninguna instancia de una clase abstracta. Si una subclase de una clase
abstracta no implementa todos los mtodos abstractos heredados de su padre, la subclase
debe ser definida tambin como abstracta. Una clase abstracta tiene un propsito: actuar
como la superclase de una jerarqua de clases.
Considera una compaa qumica que transporta sus productos en dos tipos de
contenedores: vagones (wagon) y tanques (tank):

Figura 1 Contenedor vagn

Figura 2 Contenedor tanque

El siguiente diagrama representa la jerarqua de la clase Container (contenedor):

Figura 3 Jerarqua de la clase Container


En un diagrama de clase UML, los nombres de las clases y mtodos abstractos se escriben
con letra itlica. Container es una clase abstracta que define el mtodo abstracto
computeVolume. A continuacin se presenta una implementacin de la clase Container:
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:

/**
* Esta clase modela un contenedor
*
* @author
* @version 1.0.0
*/
public abstract class Container {
/**
* Calcula el volumen de este contenedor.
*
* @return el volumen de este contenedor.
*/
public abstract double computeVolume();
}

Listado 1 Container.java
En la lnea 7, la clase Container es declarada utilizando el modificador abstract. En la
lnea 14, el mtodo computeVolume se declara utilizando el modificador abstract.
La clase Wagon extiende la clase Container, aadiendo los atributos width(ancho),
height(altura) y length(longitud) y proporcionando una implementacin del mtodo
computeVolume:
1: /**
2: * Esta clase modela un contenedor tipo vagn.
3: *

4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:

* @author
* @version 1.0.0
* @see Container
*/
public class Wagon

extends

Container

/* El ancho del vagn */


private double width;
/* La altura del vagn */
private double height;
/* La longitud del vagn */
private double length;
/**
* Construye un objeto <code>Wagon</code>.
*
* @param initialWidth el ancho de este vagn.
* @param initialHeight la altura de este vagn.
* @param initialLength la longitud de este vagn.
*/
public Wagon(double initialWidth,
double initialHeight,
double initialLength) {
this.width = initialWidth;
this.height = initialHeight;
this.length = initialLength;
}
/**
* Sobrescribe {@link Container#computeVolume()}.
* <p>
* Calcula el volumen de este vagn.
* </p>
*
* @return el volumen de este vagn.
*/
public double computeVolume() {
return this.width * this.height * this.length;
}
}

Listado 2 Wagon.java
La clase Tank hereda de la clase Container, aadiendo los atributos length(longitud) y
radius(radio) y proporcionando una implementacin del mtodo computeVolume:
1:
2:
3:
4:
5:
6:

/**
* Esta clase modela un contenedor de tipo tanque.
*
* @author
* @version 1.0.0
* @see Container

7: */
8: public class Tank extends Container {
9:
10:
/* El radio del tanque */
11:
private double radius;
12:
13:
/* La longitud del tanque */
14:
private double length;
15:
16:
/**
17:
* Construye un objeto <code>Tank</code>
18:
*
19:
* @param initialRadius el radio de este tanque.
20:
* @param initialLength la longitud de este tanque.
21:
*/
22:
public Tank(double initialRadius,
23:
double initialLength) {
24:
25:
this.radius = initialRadius;
26:
this.length = initialLength;
27:
}
28:
29:
/**
30:
* Sobrescribe {@link Container#computeVolume()}.
31:
* <p>
32:
* Calcula el volumen de este tanque.
33:
* </p>
34:
*
35:
* @return el volumen de este tanque.
36:
*/
37:
public double computeVolume() {
38:
39:
return Math.PI * this.radius * this.radius * this.length;
40:
}
41: }

Listado 3 Tank.java
Las clases que no son abstractas son llamadas clases concretas. Wagon y Tank son clases
concretas.
Una clase abstracta no tiene que tener mtodos abstractos. Sin embargo, dicha clase no
puede ser instanciada porque est definida como abstracta. En el diseo de algunas
jerarquas de clases, slo las subclases pueden ser instanciadas; la superclase se define
como abstracta por lo que no puede ser instanciada.
Por ejemplo, considera la siguiente jerarqua de clase en un sistema de negocios:

Figura 4 Jerarqua de la clase Person


La clase Person se define como abstracta y no contiene ningn mtodo abstracto. La clase
Person contiene el atributo name y el mtodo getName. La clase Employee extiende la
clase Person, aadiendo el atributo age y el mtodo getAge. La clase Client hereda de la
clase Person, aadiendo el atributo credit y el mtodo getCredit.
A continuacin se presenta una implementacin de la clase Person:
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:

/**
* Esta clase modela una persona.
*
* @author
* @version 1.0.0
*/
public abstract class Person {
/* El nombre de la persona */
private String name;
/**
* Construye un objeto <code>Person</code>.
*
* @param initialName el nombre de esta persona.
*/
public Person(String initialName) {
this.name = initialName;
}
/**
* Obtiene el nombre de esta persona.
*
* @return el nombre de esta persona.
*/
public String getName() {
return this.name;
}

31: }

Listado 4 Person.java
A continuacin se presenta una implementacin de la clase Employee:
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:

/**
* Esta clase modela un empleado.
*
* @author
* @version 1.0.0
* @see Person
*/
public class Employee extends Person

/* La edad del empleado */


private int age;
/**
* Construye un objeto <code>Employee</code>.
*
* @param initialName el nombre de este empleado.
* @param initialAge la edad de este empleado.
*/
public Employee(String initialName,
int initialAge) {
super(initialName);
this.age = initialAge;
}
/**
* Obtiene la edad de este empleado.
*
* @return la edad de este empleado.
*/
public int getAge() {
return this.age;
}
}

Listado 5 Employee.java
A continuacin se presenta una implementacin de la clase Client:
1:
2:
3:
4:
5:
6:
7:
8:

/**
* Esta clase modela un cliente.
*
* @author
* @version 1.0.0
* @see Person
*/
public class Client extends Person

9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36: }

/* El crdito del cliente */


private double credit;
/**
* Construye un objeto <code>Client</code>.
*
* @param initialName el nombre de este cliente.
* @param initialCredit el crdito de este cliente.
*/
public Client(String initialName,
double initialCredit) {
super(initialName);
this.credit = initialCredit;
}
/**
* Obtiene el crdito de este cliente.
*
* @return el crdito de este cliente
*/
public double getCredit() {
return this.credit;
}

Listado 6 Client.java
No se pueden crear instancias de la clase Person porque la clase Person es abstracta. Por
consecuencia, la siguiente declaracin es ilegal:
Person person = new Person("John");

// ilegal

Sin embargo, pueden crearse instancias de las clases Employee y Client porque son clases
concretas:
Employee employee = new Employee("John", 21);
Client client = new Client("Mary", 6000.0);

2.3.2 Polimorfismo
Lecturas:

Requerida:
o Barker, primera edicin, captulo 7 (pginas 1648).
o Barker, segunda edicin, captulo 7 (pginas 274
80).
Secuencia: Lee el libro de texto antes de leer esta pgina.

En Java, una variable de referencia puede guardar una referencia a un objeto del tipo
declarado o de cualquier subtipo del tipo declarado. Recuerda la clase Container
introducida en la pgina Clases Abstractas:

Figura 1 Jerarqua de la clase Container


Una variable de referencia de tipo Container puede almacenar una referencia a una
instancia de la clase Wagon o de la clase Tank:
Container container;
container = new Wagon(1, 1, 3);
container = new Tank(1, 3);

Esta caracterstica de una variable de referencia ser capaz de hacer referencia a objetos
de diferentes claseshace posible el polimorfismo. El polimorfismo permite asociar el
nombre de un mtodo con muchas implementaciones. Cuando un mtodo polimrfico es
llamado, la Mquina Virtual de Java (JVM) determina qu versin del mtodo ejecutar
examinando la variable de referencia utilizada en el mtodo que hace la llamada. Por
ejemplo, la instruccin

double volume = container.computeVolume();

llamar al mtodo computeVolume de Wagon cuando la referencia container apunte a un


objeto de la clase Wagon y al mtodo computeVolume de Tank cuando la referencia
container apunte a un objeto de la clase Tank.
La siguiente clase demuestra el uso polimrfico del mtodo computeVolume:
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:

import

java.io.*;

/**
* Esta clase demuestra el uso de las clases contenedor.
*
* @author
* @version 1.0.0
* @see Container
* @see Wagon
* @see Tank
*/
public class ContainerDemo {
private static PrintWriter stdOut =
new PrintWriter(System.out, true);
/**
* Demuestra el uso de polimorfismo en las clases
* contenedor.
*
* @param args no utilizado.
*/
public static void main(String[] args) {
Container container;
container = new Wagon(1, 1, 3);
stdOut.println("Volume: " + container.computeVolume());
container = new Tank(1, 3);
stdOut.println("Volume: " + container.computeVolume());
}
}

Listado1 ContainerDemo.java
La siguiente figura muestra la salida de la clase ContainerDemo:

Figura 2 Ejecucin de ContainerDemo

En este ejemplo, la misma instruccin


stdOut.println("Volume: " + container.computeVolume());

genera como salida diferentes valores. La instruccin de la lnea 28 llama al mtodo


Wagon.computeVolume porque container contiene una referencia a un objeto de la clase
Wagon. La instruccin de la lnea 31 llama al mtodo Tank.computeVolume porque
container contiene una referencia a un objeto de la clase Tank.

2.3.3 Interfaces

Interfaces
Representacin UML de Interfaces
Usando Interfaces
Comparando Clases Abstractas e Interfases
Lecturas:

Requerida:
o Barker, primera edicin, captulo 7 (pginas 1758).
o Barker, segunda edicin, captulo 7 (pginas 290
304).

Secuencia: Lee el libro de texto antes de leer esta pgina.

Interfaces
En Java, una interfaz define un conjunto de mtodos abstractos; algunas interfaces incluyen
tambin declaraciones de constantes. Una interfaz se declara casi igual que una clase,
utilizando la palabra clave interface en vez de la palabra clave class:
1: public interface MyInterface {
2:
3:
int CONSTANT = 10;
4:
5:
void methodOne();
6:
7:
double methodTwo();
8:
9:
void methodThree(double value);
10: }

Listado 1 Declaracin y cuerpo de una interfaz


En las interfaces de Java:

Todos los mtodos que se encuentran en una interfaz son implcitamente pblicos y
abstractos. Como una cuestin de estilo, no se utilizan los modificadores public y
abstract en la definicin de una interfaz.
Todos los campos de datos de una interfaz son implcitamente pblicos, estticos y
finales. Como un aspecto de estilo, no se utilizan los modificadores public, static
y final en la definicin de una interfaz.

Para que una clase haga uso de una interfaz, se utiliza la palabra clave implements, seguida
por el nombre de la interfaz:

1: public class ClassA implements MyInterface {


2:
3:
public void methodOne() {
4:
...
5:
}
6:
7:
public double methodTwo() {
8:
...
9:
}
10:
11:
public void methodThree(double value) {
12:
...
13:
}
14:
15:
...
16:
17: }

Listado 2 Una clase que implementa una interfaz


Cuando una clase implementa una interfaz, accede a implementar todos los mtodos de la
interfaz. Si la clase no implementa todos los mtodos, la clase debe ser definida como
abstracta.
Una interfaz puede heredar de otra interfaz. En este caso, la interfaz padre es llamada
superinterfaz, de forma similar al trmino superclase para las clases padre. La interfaz hija
es llamada subinterfaz, de manera similar al trmino subclase para las clases hijas.
1: public interface MyInterface extends InterfaceOne {
2:
3:
void aMethod();
4: }

Listado 3 Una interfaz que hereda de otra interfaz


Una clase solo puede heredar de una clase. En contraste, una interfaz puede heredar de
cualquier nmero de interfaces:
1: public interface MyInterface extends Interface1, Interface2 {
2:
3:
void aMethod();
4: }

Listado 4 Una interfaz que hereda de varias interfaces


Una clase puede implementar muchas interfaces:
1: public class ClassA implements
2:
Interface1, Interface2, Interface3 {
3:
4:
...
5:
6: }

Listado 5 Una clase que implementa varias interfaces

Representacin UML de Interfaces


Como se muestra en la Figura 1, una interfaz se representa en UML por un rectngulo con
dos compartimientos. El primer compartimiento contiene el encabezado <<interface>> y
el nombre de la interfaz; el segundo compartimiento describe los mtodos de la interfaz. En
UML, las interfaces carecen de atributos; slo tienen operaciones. En UML, las clases que
implementan una interfaz estn indicadas por una lnea punteada entre la clase y la interfaz,
con un tringulo junto a la interfaz:

Figura 1 Representacin UML de una interfaz


En este ejemplo, las clases ClassA y ClassB implementan los mtodos declarados en la
interfaz MyInterface.
En la siguiente figura, InterfaceTwo hereda de InterfaceOne y ClassA implementa
InterfaceTwo e InterfaceThree:

Figura 2 Una clase que implementa varias interfaces


ClassA debe implementar
e InterfaceThree.

todos los mtodos declarados en InterfaceOne, InterfaceTwo

Usando Interfaces
La interfaz Device especifica dos comportamientos, turn-off (apagado) y turn-on
(encendido), que son comunes para dispositivos elctricos como focos y televisiones:

Figura 3 Interfaz Device

La interfaz Device declara, pero no implementa, los mtodos turnOff y turnOn:


1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:

/**
* Esta interfaz especifica dos comportamientos, encendido y apagado,
* que son comunes para muchos dispositivos elctricos.
*
* @author
* @version 1.0.0
*/
public interface Device {
/**
* Apaga el dispositivo.
*/
void turnOff();
/**
* Enciende el dispositivo.
*/
void turnOn();
}

Listado 6 Device.java
Todas las clases que implementan la interfaz Device deben implementar los mtodos
turnOff y turnOn. La siguiente clase, DeviceDemo, implementa la interfaz Device. La
clase DeviceDemo tiene un atributo, el nombre del dispositivo. Los mtodos turnOff y
turnOn de la clase DeviceDemo despliegan un mensaje en la salida estndar.
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:

import java.io.*;
/**
* Esta clase demuestra el uso de la interfaz {@link Device}.
*
* @author
* @version 1.0.0
* @see Device
*/
public class DeviceDemo implements Device {
/* Flujo de salida estndar */
private static PrintWriter stdOut =
new PrintWriter(System.out, true);
/* El nombre del dispositivo */
private String name;
/**
* Prueba la clase <code>DeviceDemo</code>.
*/
public static void main (String[] args) {
Device device = new DeviceDemo("demo");
device.turnOn();

27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55: }

device.turnOff();
}
/**
* Construye un objeto <code>DeviceDemo</code>.
*
* @param name el nombre de este dispositivo.
*/
public DeviceDemo (String initialName) {
name = initialName;
}
/**
* Apaga el dispositivo.
*/
public void turnOff() {
stdOut.println("Turn off device " + name);
}
/**
* Enciende el dispositivo.
*/
public void turnOn() {
stdOut.println("Turn on device " + name);
}

Listado 7 DeviceDemo.java
La siguiente figura muestra la salida de la clase DeviceDemo:

Figura 4 Ejecucin de DeviceDemo


La clase Stopwatch implementa tambin la interfaz Device. Al encender el cronmetro
(stopwatch), el mtodo turnOn asigna el tiempo actual, en milisegundos, a la variable de
instancia startTime. Al apagar el cronmetro, el mtodo turnOff genera como salida el
tiempo en milisegundos en el que estuvo encendido el cronmetro.
1:
2:
3:
4:
5:
6:

import java.io.*;
/**
* Esta clase modela un cronmetro que puede ser iniciado y detenido a
voluntad
* durante un tiempo exacto.

7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:

*
* @author
* @version 1.0.0
* @see Device
* @see System
*/
public class Stopwatch

implements Device {

/** Representa el estado de apagado*/


public static final int OFF = 0;
/** Representa el estado de encendido */
public static final int ON = 1;
/* Flujo de salida estndar */
private static PrintWriter stdOut =
new PrintWriter(System.out, true);
/* Estado de este dispositivo */
private int state;
/* Almacena el tiempo cuando se prende el dispositivo */
private long startTime;
/**
* Prueba la clase <code>Stopwatch</code>.
*/
public static void main (String[] args) {
Device device = new Stopwatch();
device.turnOn();
/* retraso */
for (int i = 0; i < 50000000; i++);
device.turnOff();
}
/**
* Construye un objeto <code>Stopwatch</code>.
* <p>
* El estado inicial del cronmetro es apagado.
* </p>
*/
public Stopwatch () {
state = Stopwatch.OFF;
startTime = 0;
}
/**
* Apaga el cronmetro y genera como salida el tiempo que el
cronmetro
* estuvo encendido.
*/
public void turnOff() {

64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:
80:
81:
82:
83:

if (state == Stopwatch.OFF) {
stdOut.println("The device is off");
} else {
long rightNow

= System.currentTimeMillis();

stdOut.println("Time: " + (rightNow - startTime));


startTime = 0;
state = Stopwatch.OFF;
}
}
/**
* Enciende el cronmetro y toma nota del tiempo actual.
*/
public void turnOn() {
startTime = System.currentTimeMillis();
state = Stopwatch.ON;
}
}

Listado 8 Stopwatch.java
La siguiente figura muestra la salida de la clase Stopwatch.

Figura 5 Ejecucin de Stopwatch

Comparando Clases Abstractas e Interfaces


Existen diferencias significativas entre clases abstractas e interfaces:

Una clase abstracta puede definir variables de instancia, mientras que una interfaz
no puede hacerlo.
Una clase abstracta puede implementar mtodos, mientras que una interfaz no puede
hacerlo.
Las interfaces no contienen constructores.
Si una clase hereda de una clase abstracta, sta no puede heredar de otra clase; si
una clase implementa una interfaz, tiene la libertad de heredar de otra clase e
implementar muchas otras interfaces.

Una clase abstracta debe ser utilizada cuando algunos detalles en la implementacin, como
las variables y definiciones de mtodos, son comunes para todas las clases en una jerarqua.
En tal caso, la clase abstracta sera la raz de la jerarqua de clase.

Una interfaz debe ser utilizada para definir un comportamiento que debe ser implementado
por clases de diferentes jerarquas. Las interfaces son el medio por el cual las clases que no
estn relacionadas pueden hacer uso del poder del polimorfismo debido a que una
interfazcomo una clasedefine un tipo. Esto hace posible que las clases pertenecientes a
diferentes jerarquas sean tratadas como instancias del mismo tipo.

2.3.4 Patrones de Diseo


Lecturas:

Opcional:
o James W. Cooper, The Design Patterns Java
Companion. "Some Background on Design Patterns"
("Antecedentes sobre Patrones de Diseo") (pginas
106).

Los patrones de diseo describen soluciones prcticas para problemas comunes de diseo
que ocurren repetidamente en el desarrollo de software. Un patrn de diseo consta de:

Un nombre que identifica el patrn


Una descripcin del problema del cual trata patrn
Una descripcin de la solucin que incluye las estructuras de clase que resuelven el
problema
Una discusin de las consecuencias de utilizar el patrn

Los patrones de diseo documentan las buenas soluciones de diseo que pueden ser
utilizadas para problemas similares y forman un vocabulario compartido para las
discusiones de solucin de problemas. Adems, los patrones de diseo son una buena
ilustracin de los conceptos orientados a objetos.
Los patrones de diseo fueron popularizados por el libro Design Patterns: Elements of
Reusable Object-Oriented Software (Patrones de Diseo: Elementos de Software
Orientado a Objetos Reutilizable) de Erich Gamma, Richard Helm, Ralph Johnson y John
Vlissides. Este libro cubre 23 patrones, agrupados en tres categoras:
(Creational)
Patrones de Creacin:

(Structural)
Patrones Estructurales:

Abstract Factory
Builder
Factory Method
Prototype
Singleton

Adapter
Bridge
Composite
Decorator
Faade
Flyweight
Proxy

(Behavioral)
Patrones de Comportamiento:

Chain of Responsibility
Command
Iterator
Mediator
Memento
Observer
State
Strategy
Visitor
Interpreter
Template Method

En las siguientes pginas se discutirn los patrones Singular (Singleton) y Estrategia


(Strategy).

2.3.5 Patrn de Diseo Singular (Singleton)

Descripcin
Estructura
Ejemplo
Consecuencias
Lecturas:

Opcional:
o James W. Cooper, The Design Patterns Java
Companion. "The Singleton Pattern" ("El Patrn de
diseo Singular") (pginas 316).

Descripcin
En algunas aplicaciones, hay clases que deben ser instanciadas una sola vez. Por ejemplo,
un sistema operativo debe tener solo un sistema de reloj y una compaa debe tener solo un
sistema contable. El patrn de diseo Singular (Singleton) asegura que se cree slo una
instancia de la clase y provee un mtodo para acceder esa nica instancia. Todos los objetos
que utilizan una instancia de una clase Singular utilizan la misma instancia.

Estructura

Figura 1 Patrn de diseo Singular (Singleton)


Observa que los miembros estticos de la clase estn subrayados.
En este patrn de diseo:

El atributo esttico instance contiene la nica instancia de la clase.


El constructor es definido como private de modo que las otras clases no puedan
crear instancias.
El mtodo esttico getSingletonInstance regresa la nica instancia de la clase.
La primera vez que este mtodo es llamado, crea la nica instancia.

Ejemplo

La clase ICarnegieInfo contiene la informacin de contacto de iCarnegie. Solo es posible


crear una instancia de la clase ICarnegieInfo. La siguiente implementacin de la clase
ICarnegieInfo demuestra el patrn de diseo Singular:
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:

/**
* Esta clase es un singleton que contiene la informacin de
* contacto de <cite>iCarnegie</cite>.
*
* @author
* @version 1.0.0
*/
public class ICarnegieInfo {
static private ICarnegieInfo singletonInstance = null;
private String name;
private String address;
private String telephone;
/*
* Inicializa las variables de instancia. El constructor es
* declarado como privado de modo que slo pueda ser llamado por
mtodos
* de esta clase. Esto previene que otras clases creen ms
* instancias.
*/
private ICarnegieInfo () {
name = "iCarnegie, Inc";
address = "4615 Forbes Avenue Pittsburgh, PA 15213-3796";
telephone = "1.412.622.2150
begin_of_the_skype_highlighting
1.412.622.2150
end_
of_the_skype_highlighting";
}
/**
* Obtiene la nica instancia de la clase
* <code>ICarnegieInfo</code>
*
* @return la nica instancia de la clase
*
<code>ICarnegieInfo</code>
*/
static public ICarnegieInfo getSingletonInstance() {
if (singletonInstance == null) {
singletonInstance = new ICarnegieInfo();
}
return singletonInstance;
}
/**
* Obtiene el nombre de <cite>iCarnegie</cite>
*
* @return un string con el nombre de <cite>iCarnegie</cite>
*/

53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:

public String getName() {


return name;
}
/**
* Obtiene la direccin de <cite>iCarnegie</cite>
*
* @return un string con la direccin de <cite>iCarnegie</cite>
*/
public String getAddress() {
return address;
}
/**
* Obtiene el telfono de <cite>iCarnegie</cite>
*
* @return un string con el telfono de <cite>iCarnegie</cite>
*/
public String getTelephone() {
return telephone;
}
}

Listado 1 ICarnegieInfo.java
En la lnea 10, la variable esttica y privada singletonInstance es inicializada con una
instancia de la clase ICarnegieInfosingletonInstance ser la nica instancia de la
clase ICarnegieInfo en una aplicacin. En la lnea 22, el constructor es definido como
privado, de modo que otras clases no puedan crear instancias de ICarnegieInfo. En la
lnea 36, la clase define un mtodo esttico llamado getSingletonInstance que regresa
una referencia a la nica instancia de ICarnegieInfo. La primera llamada al mtodo
getSingletonInstance crea la nica instancia.
La siguiente clase demuestra el uso de la clase Singular ICarnegieInfo:
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:

import

java.io.*;

/**
* Esta clase demuestra el uso de la clase {@link ICarnegieInfo}.
*
* @author
* @version 1.0.0
* @see ICarnegieInfo
*/
public class ICarnegieInfoDemo {
private static PrintWriter stdOut =
new PrintWriter(System.out, true);
/**
* Demuestra el uso de la clase {@link ICarnegieInfo}.

17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29: }

*
* @param args no utilizado
*/
public static void main(String[]

args)

ICarnegieInfo companyInfo =
ICarnegieInfo.getSingletonInstance();
stdOut.println("Name:
" + companyInfo.getName());
stdOut.println("Address:
" + companyInfo.getAddress());
stdOut.println("Telephone: " + companyInfo.getTelephone());
}

Listado 2 ICarnegieInfoDemo.java
En las lneas 22 y 23, la aplicacin obtiene la nica instancia llamando al mtodo esttico
ICarnegieInfo.getSingletonInstance.

Consecuencias
El patrn de diseo Singular tiene los siguientes beneficios:

Una clase Singular puede controlar cmo y cuando el cdigo cliente puede acceder
a la nica instancia. El cdigo cliente no tiene la libertad de utilizar el operador new
para crear una instancia de la clase Singular. En vez de eso, debe llamar a un
mtodo esttico que regresa una referencia a la instancia nica.
Una clase Singular puede ser modificada fcilmente si los requerimientos cambian y
la aplicacin necesita limitar el nmero de instancias a un nmero diferente de uno.

2.3.6 Patrn de Diseo Estrategia (Strategy)

Introduccin
Descripcin
Diagrama de Clase UML
Ejemplo
La Interfaz BorrowersFormatter
La Clase PlainTextBorrowersFormatter
La Clase HTMLBorrowersFormatter
La Clase XMLBorrowersFormatter
La Clase LibrarySystem
El Sistema Completo
Lecturas:

Opcional:
o James W. Cooper, The Design Patterns Java
Companion. "The Strategy Pattern" ("El Patrn de
Diseo Estrategia (Strategy)") (pginas 194201).

Introduccin
El patrn de diseo Estrategia (Strategy) es ms difcil de entender que el patrn de diseo
Singular (Singleton) porque utiliza interfaces y polimorfismo. Empezaremos nuestra
discusin con un ejemplo simple. Una vez que tengas la idea bsica, te presentaremos una
descripcin ms formal.
Considera un sistema de comercio electrnico que soporta ventas en Estados Unidos,
Mxico y Canad. En un futuro cercano, la base de clientes ser expandida para incluir
pases de Sudamrica. El sistema debe saber cmo calcular el impuesto de la venta para los
clientes de los tres pases, cada uno de los cuales tiene sus propias reglas para calcular el
impuesto de la venta. El diseo del cdigo para calcular el impuesto de la venta debe ser
flexible, de modo que resulte fcil agregar otros pases. Una solucin es usar un mtodo
monoltico llamado calculateTax, que calcula el impuesto de las ventas para cada pas.
Este mtodo sera parte de la clase que modela una orden.
1: public class Order {
2:
3:
/**
4:
* Calcula el impuesto de una orden.
5:
*
6:
* @param country
El pas que cobrar el impuesto de la orden.
7:
* @param amount
El costo de la orden.
8:
* @return la cantidad de impuesto
9:
*/
10:
private double calculateTax(String country, double amount) {

11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32: }

double tax
if (country.equals("United States")) {
tax = ... ;
} else if (country.equals("Canada")) {
tax = ... ;
} else if (country.equals("Mexico")) {
tax = ... ;
}
...
return tax;
}

Listado 1 Mtodo calculateTax


Esta solucin tiene algunas desventajas:

Si las reglas para calcular el impuesto de las ventas son complejas, el mtodo
calculateTax ser largo y complejo.
La clase contiene el cdigo que utiliza calculateTax y el cdigo que implementa
calculateTax.

Una solucin que utiliza el patrn de diseo Estrategia no tiene dichas desventajas. En una
solucin basada en el patrn de diseo Estrategia, el cdigo para calcular el impuesto de las
ventas en Estados Unidos es encapsulado en su propia clase, al igual que el cdigo para
Canad y Mxico. Cada clase implementa su propia versin del mtodo calculateTax. La
relacin lgica entre las tres clases es expresada en el siguiente diagrama de clase:

Figura 1 Diagrama de clase de TaxCalculator


La interfaz TaxCalculator declara el mtodo calculateTax. Las clases que implementan
la interfaz TaxCalculator acceden a definir el mtodo calculateTax. La complejidad del
cdigo del impuesto de venta se reduce separndolo en tres clases. Si se agrega un pas al
sistema, se crea una nueva clase que encapsula las reglas del impuesto de ventas para dicho
pas. La nueva clase implementa la interfaz TaxCalculator y defina su propia versin del
mtodo calculateTax.

Descripcin
En esta pgina, examinaremos una forma de implementar el patrn de diseo Estrategia. El
libro Design Patterns (Patrones de Diseo) describe el patrn de diseo Estrategia con las
siguientes palabras:
"Define una familia de algoritmos, encapsula cada una y las vuelve intercambiables. El
patrn de diseo Estrategia permite que el algoritmo vare independientemente de los
clientes que lo utilizan."
En el patrn de diseo Estrategia, cada algoritmo es encapsulado en su propia clase. Se crea
una interfaz que declara un mtodo para ejecutar un algoritmo y las clases del algoritmo
implementan la interfaz. En consecuencia, cada clase algoritmo tiene su propia versin del
mtodo. Cuando surge la necesidad de un algoritmo en particular, es llamada la versin del
mtodo asociado con dicho algoritmo.
Las aplicaciones donde el patrn de diseo Estrategia puede resultar til son:

Una aplicacin para comprimir archivos que permite al usuario seleccionar el tipo
de compresin

Una aplicacin donde la naturaleza de los datos que sern ordenados determina el
algoritmo de ordenamiento

Hasta ahora, nuestra discusin se ha enfocado en algoritmos an y cuando el nombre del


patrn de diseo es Estrategia. Un algoritmo puede ser considerado una estrategia y de ah
el origen del nombre del patrn. En esta pgina, utilizaremos los trminos de forma
intercambiable.

Diagrama de Clase UML

Figura 2 Patrn de diseo Estrategia (Strategy)


En el patrn de diseo Estrategia:

La interfaz Strategy define la firma del mtodo que ser utilizado para llamar a un
algoritmo.
Las clases ConcreteStrategyX implementan el mtodo declarado en la interfaz
Strategy.
La clase Context mantiene una referencia a un objeto de tipo Strategy, llamada
strategy.
La clase Context contiene el mtodo setStrategy, que permite al cdigo cliente
especificar el algoritmo deseado. setStrategy toma un parmetro de entrada de
tipo Strategy de modo que el cdigo cliente debe pasarlo como una instancia de la
clase ConcreteStrategy asociado con el algoritmo deseado. setStrategy
actualiza la variable de referencia strategy.
La clase Context contiene el mtodo invokeStrategy, el cual es llamado por el
cdigo cliente cuando necesita ejecutar un algoritmo. El algoritmo utilizado est
determinando por la variable de referencia strategy, la cual hace referencia a una
instancia de la clase ConcreteStrategy.

El ejemplo que presentaremos en esta pgina es inusual debido a que la clase contendr el
cdigo cliente.

Ejemplo
El siguiente diagrama de clase muestra una mejora al sistema de la biblioteca. Esta mejora
hace posible dar formato a la informacin de la base de datos de usuarios en una de las
siguientes tres formas: texto plano, HTML y XML:

Figura 3 Un ejemplo del patrn de diseo Estrategia (Strategy)


En el sistema de la biblioteca:

La interfaz BorrowersFormatter es la interfaz de estrategia que declara un mtodo


llamado formatBorrowers que produce una representacin string de la base de
datos de usuarios.
La clase PlainTextBorrowersFormatter implementa formatBorrowers. Esta
versin del mtodo convierte la informacin de la base de datos de usuarios a un
formato de texto plano.
La clase HTMLBorrowersFormatter implementa formatBorrowers. Esta versin
del mtodo convierte la informacin de la base de datos de usuarios a un formato
HTML.
La clase XMLBorrowersFormatter implementa formatBorrowers. Esta versin del
mtodo convierte la informacin de la base de datos de usuarios a un formato XML.

La clase LibrarySystem es la clase de contexto. Tambin contiene el cdigo


cliente. El mtodo setBorrowersFormatter se utiliza para especificar el
mecanismo para dar formato. El mtodo displayBorrowers se utiliza para ejecutar
el mecanismo de formato especificado: llama al mtodo formatBorrowers para
desplegar la base de datos de usuarios en el formato especificado.

La Interfaz BorrowersFormatter
A continuacin se presenta una implementacin de la interfaz BorrowersFormatter:
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:

/**
* Esta interfaz define un mtodo que obtiene una representacin
* string de un objeto {@link BorrowerDatabase}.
*
* @author
* @version 1.0.0
* @see BorrowerDatabase
*/
public interface BorrowersFormatter {
/**
* Obtiene la representacin string de la base de datos de
usuarios
* especificada.
*
* @param borrowerDB la base de datos de usuarios.
* @return la representacin string del objeto
*
{@link BorrowerDatabase} especificado.
*/
String formatBorrowers (BorrowerDatabase borrowerDB);
}

Listado 2 BorrowersFormatter.java

La Clase PlainTextBorrowersFormatter
A

presenta una implementacin de la clase concreta


PlainTextBorrowersFormatter.
La clase PlainTextBorrowersFormatter es
implementada como Singular (Singleton), de modo que no se crear un nuevo objeto cada
vez que se utilice el formato de texto plano:
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:

continuacin

se

import java.util.*;
/**
* Esta clase implementa un mtodo que obtiene una representacin en
* texto plano de un objeto{@link BorrowerDatabase}.
*
* @author
* @version 1.0.0
* @see BorrowersFormatter
* @see BorrowerDatabase

12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:

* @see Borrower
* @see BorrowedItems
* @see CatalogItem
*/
public class PlainTextBorrowersFormatter
implements BorrowersFormatter {
/* Separador de lnea*/
private final static String NEW_LINE =
System.getProperty("line.separator");
/* nica instancia de esta clase */
static private PlainTextBorrowersFormatter singletonInstance =
null;
/**
* Obtiene la nica instancia de la clase
* <code>PlainTextBorrowersFormatter</code>
*
* @return la nica instancia de la clase
*
<code>PlainTextBorrowersFormatter</code>
*/
static public PlainTextBorrowersFormatter getSingletonInstance() {
if (singletonInstance == null) {
singletonInstance = new PlainTextBorrowersFormatter();
}
return singletonInstance;
}
/*
* El constructor se declara como privado de modo que otras clases
no
* puedan crear una instancia de esta clase.
*/
private PlainTextBorrowersFormatter() {
}
/**
* Obtiene una representacin en texto plano de la base de datos
de usuarios
* especificada.
*
* @param borrowerDB la base de datos de usuarios.
* @return una representacin en texto plano de un objeto
*
{@link BorrowerDatabase} especificado.
*/
public String formatBorrowers (BorrowerDatabase borrowerDB) {
String out = "Borrower Database" + NEW_LINE;
for (Borrower borrower : borrowerDB) {
out += borrower.getId() + "_" + borrower.getName();
for (CatalogItem item : borrower.getBorrowedItems()) {

69:
70:
71:

out += "_" + item.getCode();


}
out += NEW_LINE;
}
return out;
}
}

Listado 3 PlainTextBorrowersFormatter.java
La constante NEW_LINE, definida en la lnea 19, contiene el separador de lnea definido por
la propiedad del sistema line.separator. No todas las plataformas utilizan el carcter de
lnea nueva (\n) para terminar lneas. Por ejemplo, los sistemas Windows utilizan "\r\n" y
los sistemas Macintosh utilizan '\r'.

La Clase HTMLBorrowersFormatter
A

continuacin

se

presenta una implementacin de la clase concreta


La clase HTMLBorrowersFormatter es implementada como
Singular (Singleton), por lo que no se crear un nuevo objeto cada vez que se utilice el
formato HTML:
HTMLBorrowersFormatter.

1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:

import java.util.*;
/**
* Esta clase implementa un mtodo que obtiene una representacin
* HTML de un objeto {@link BorrowerDatabase}.
*
* @author
* @version 1.0.0
* @see BorrowersFormatter
* @see BorrowerDatabase
* @see Borrower
* @see BorrowedItems
* @see CatalogItem
*/
public class HTMLBorrowersFormatter
implements BorrowersFormatter {
/* Separador de lnea */
private final static String NEW_LINE =
System.getProperty("line.separator");
/* nica instancia de esta clase */
static private HTMLBorrowersFormatter singletonInstance = null;
/**
* Obtiene la nica instancia de la clase
* <code>HTMLBorrowersFormatter</code>
*
* @return la nica instancia de la clase
*
<code>HTMLBorrowersFormatter</code>

31:
*/
32:
static public HTMLBorrowersFormatter getSingletonInstance() {
33:
34:
if (singletonInstance == null) {
35:
singletonInstance = new HTMLBorrowersFormatter();
36:
}
37:
38:
return singletonInstance;
39:
}
40:
41:
/*
42:
* El constructor es declarado como privado de modo que otras
43: clases no
44:
* puedan crear una instancia de esta clase.
45:
*/
46:
private HTMLBorrowersFormatter() {
47:
}
48:
49:
/**
50:
* Obtiene una representacin HTML de la base de datos de usuarios
51:
* especificada.
52:
*
53:
* @param borrowerDB la base de datos de usuarios.
54:
* @return una representacin HTML del objeto
55:
*
{@link BorrowerDatabase} especificado.
56:
*/
57:
public String formatBorrowers (BorrowerDatabase borrowerDB) {
58:
59:
String out = "<html>"
60:
+ NEW_LINE
61:
+ " <body>"
62:
+ NEW_LINE + ""
63:
+ "
<center><h2>Borrower
64: Database</h2></center>"
65:
+ NEW_LINE;
66:
67:
for (Borrower borrower : borrowerDB) {
68:
out += "
<hr>"
69:
+ NEW_LINE
70:
+ "
<h4>"
71:
+ borrower.getId()
72:
+ " "
73:
+ borrower.getName()
74:
+ "</h4>"
75:
+ NEW_LINE;
76:
77:
BorrowedItems items = borrower.getBorrowedItems();
78:
79:
if (items.getNumberOfItems() > 0) {
80:
out += "
<blockquote>" + NEW_LINE;
81:
for (CatalogItem item : items) {
82:
out += "
"
83:
+ item.getCode()
84:
+ " "
85:
+ item.getTitle()
86:
+ "<br>"
87:
+ NEW_LINE;

88:
89:
90:
91:
92:
93:

}
out += "

</blockquote>" + NEW_LINE;

}
}
out += "

</body>" + NEW_LINE + "</html>";

return out;
}
}

Listado 4 HTMLBorrowersFormatter.java

La Clase XMLBorrowersFormatter
La siguiente es una implementacin de la clase concreta XMLBorrowersFormatter. La
clase XMLBorrowersFormatter es implementada como Singular (Singleton), de modo que
no se crear un nuevo objeto cada vez que se utilice el formato XML:
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:

import java.util.*;
/**
* Esta clase implementa un mtodo que obtiene una representacin
* de un objeto {@link BorrowerDatabase}.
*
* @author
* @version 1.0.0
* @see BorrowersFormatter
* @see BorrowerDatabase
* @see Borrower
* @see BorrowedItems
* @see CatalogItem
*/
public class XMLBorrowersFormatter
implements BorrowersFormatter {
/* Separador de lnea */
private final static String NEW_LINE =
System.getProperty("line.separator");
/* nica instancia de esta clase */
static private XMLBorrowersFormatter singletonInstance = null;
/**
* Obtiene la nica instancia de la clase
* <code>XMLBorrowersFormatter</code>
*
* @return la nica instancia de la clase
*
<code>XMLBorrowersFormatter</code>
*/
static public XMLBorrowersFormatter getSingletonInstance() {
if (singletonInstance == null) {
singletonInstance = new XMLBorrowersFormatter();
}

38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:
80:
81:
82:
83:
84:
85:
86:
87:

return singletonInstance;
}
/*
* El constructor se declara como privado de modo que otras
* clases no puedan crear una instancia de esta clase.
*/
private XMLBorrowersFormatter() {
}
/**
* Obtiene una representacin XML de la base de datos de usuarios
* especificada.
*
* @param borrowerDB la base de datos de usuarios.
* @return una representacin XML del objeto
*
{@link BorrowerDatabase} especificado.
*/
public String formatBorrowers (BorrowerDatabase borrowerDB) {
String out = "<BorrowerDatabase>" + NEW_LINE ;
for (Borrower borrower : borrowerDB) {
out += " <Borrower id=\""
+ borrower.getId()
+ "\" name=\""
+ borrower.getName()
+ "\">"
+ NEW_LINE;
BorrowedItems items = borrower.getBorrowedItems();
if (items.getNumberOfItems() > 0) {
out += "
<BorrowedItems>" + NEW_LINE;
for (CatalogItem item : items) {
out += "
<CatalogItem id=\""
+ item.getCode()
+ "\">"
+ item.getTitle()
+ "</CatalogItem>" + NEW_LINE;
}
out += "
</BorrowedItems>" + NEW_LINE;
}
out += "

</Borrower>" + NEW_LINE;
}
out += "</BorrowerDatabase>";
return out;
}
}

Listado 5 XMLBorrowersFormatter.java

La Clase LibrarySystem
A continuacin se presenta una implementacin de la clase LibrarySystem. La clase
LibrarySystem permite al usuario especificar un formato y despus desplegar la
informacin de la base de datos de usuarios en el formato especificado. La clase contiene:

1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:

Una variable de referencia de tipo BorrowersFormatter que hace referencia al


formato
actual
un
objeto
PlainTextBorrowersFormatter,
HMTLBorrowersFormatter o XMLBorrowersFormatter
Un mtodo setBorrowersFormatter para especificar el formato deseado
Un mtodo displayBorrowers para desplegar la informacin de la base de datos
de usuarios en el formato especificado
import java.io.*;
import java.util.*;
/**
* Esta clase implementa un sistema de biblioteca.
*
* @author
* @version 1.1.0
* @see CatalogItem
* @see Book
* @see Recording
* @see Catalog
* @see Borrower
* @see BorrowerDatabase
* @see BorrowersFormatter
* @see PlainTextBorrowersFormatter
* @see HTMLBorrowersFormatter
* @see XMLBorrowersFormatter
*/
public class LibrarySystem {
private static BufferedReader stdIn =
new BufferedReader(new InputStreamReader(System.in));
private static PrintWriter stdOut =
new PrintWriter(System.out, true);
private static PrintWriter stdErr =
new PrintWriter(System.err, true);
private BorrowerDatabase borrowerDB;
private BorrowersFormatter borrowersFormatter;
/**
* Carga un catlogo de la biblioteca y la base de datos de
usuarios
* y entonces inicia la aplicacin.
*
* @param args Argumentos de tipo string. No utilizado.
* @throws arroja IOException si hay errores en la entrada.
*/

41:
public static void main(String[] args) throws IOException {
42:
43:
LibrarySystem app = new LibrarySystem();
44:
45:
app.run();
46:
}
47:
48:
/**
49:
* Crea un objeto <code>LibrarySystem</code>.
50:
*/
51:
private LibrarySystem() {
52:
53:
borrowerDB = loadBorrowers(loadCatalog());
54:
borrowersFormatter =
55:
PlainTextBorrowersFormatter.getSingletonInstance();
56:
}
57:
58:
/**
59:
* Carga los datos del catlogo.
60:
*/
61:
private Catalog loadCatalog() {
62:
63:
Catalog catalog = new Catalog();
64:
65:
catalog.addItem(new Book("B001",
66:
"Effective Java Programming", 2001,
67:
"Joshua Bloch", 252));
68:
catalog.addItem(new Book("B002",
69:
"Design Patterns", 1995,
70:
"Erich Gamma et al", 395));
71:
catalog.addItem(new Book("B003",
72:
"Refactoring", 1999,
73:
"Martin Fowler", 431));
74:
catalog.addItem(new Book("B004",
75:
"The Mythical Man-Month", 1995,
76:
"Frederick P. Brooks", 322));
77:
catalog.addItem(new Book("B005",
78:
"Code Complete", 1993,
79:
"Steve C McConnell", 857));
80:
catalog.addItem(new Book("B006",
81:
"The Psychology of Comp. Progr.",
82: 1998,
83:
"Gerald M. Weinberg", 360));
84:
catalog.addItem(new Book("B007",
85:
"Programming Pearls ", 1999,
86:
"Jon Bentley", 239));
87:
catalog.addItem(new Book("B008",
88:
"The Practice of Programming", 1999,
89:
"Brian W. Kernighan", 257));
90:
catalog.addItem(new Book("B009",
91:
"Peopleware", 1999,
92:
"Tom Demarco", 245));
93:
catalog.addItem(new Book("B010",
94:
"The Java Programming Language",
95: 2000,
96:
"Ken Arnold", 595));
97:
catalog.addItem(new Book("B011",

98:
"Core J2EE Patterns", 2001,
99:
"Deepak Alur", 496));
100:
catalog.addItem(new Book("B012",
101:
"Rapid Development", 1996,
102:
"Steve C McConnell", 680));
103:
catalog.addItem(new Book("B013",
104:
"Applying UML and Patterns", 2001,
105:
"Craig Larman", 656));
106:
catalog.addItem(new Book("B014",
107:
"The Little Schemer", 1995,
108:
"Daniel P. Friedman", 216));
109:
catalog.addItem(new Book("B015",
110:
"Agile Software Development", 2001,
111:
"Alistair Cockburn", 256));
112:
catalog.addItem(new Recording("R001",
113:
"Getz/Gilberto", 1963,
114:
"Stan Getz and Joao Gilberto",
115: "CD"));
116:
catalog.addItem(new Recording("R002",
117:
"Kind of Blue", 1997,
118:
"Miles Davis", "CD"));
119:
catalog.addItem(new Recording("R003",
120:
"Supernatural", 1999,
121: "Santana",
122:
"Tape"));
123:
catalog.addItem(new Recording("R004",
124:
"Private Collection", 1983,
125:
"Jon & Vangelis", "Tape"));
126:
catalog.addItem(new Recording("R005",
127:
"Abbey Road", 1969,
128:
"Beatles", "CD"));
129:
catalog.addItem(new Recording("R006",
130:
"Joshua Tree", 1990,
131:
"U2", "CD"));
132:
133:
return catalog;
134:
}
135:
136:
/**
137:
* Carga una base de datos de usuarios.
138:
*/
139:
private BorrowerDatabase loadBorrowers(Catalog catalog) {
140:
141:
BorrowerDatabase borrowerDB = new BorrowerDatabase();
142:
143:
Borrower borrower = new Borrower("ID001", "James Addy");
144:
145:
borrower.getBorrowedItems().addItem(
146:
catalog.getItem("B003"));
147:
borrower.getBorrowedItems().addItem(
148:
catalog.getItem("R001"));
149:
borrower.getBorrowedItems().addItem(
150:
catalog.getItem("B012"));
151:
borrowerDB.addBorrower(borrower);
152:
153:
borrower = new Borrower("ID002", "John Doust");
154:
borrowerDB.addBorrower(borrower);

155:
156:
157:
158:
159:
160:
161:
162:
163:
164:
165:
166:
167:
168:
169:
170:
171:
172:
173:
174:
175:
176:
177:
178:
179:
180:
181:
182:
183:
184:
185:
186:
187:
188:
189:
190:
191:
192:
193:
194:
195:
196:
197:
198:
199:
200:
201:
202:
203:
204:
205:
206:
207:
208:
209:
210:
211:

borrower = new Borrower("ID003", "Constance Foster");


borrower.getBorrowedItems().addItem(
catalog.getItem("B006"));
borrowerDB.addBorrower(borrower);
borrower = new Borrower("ID004", "Harold Gurske");
borrower.getBorrowedItems().addItem(
catalog.getItem("B002"));
borrowerDB.addBorrower(borrower);
borrower = new Borrower("ID005", "Mary A. Rogers");
borrowerDB.addBorrower(borrower);
borrower = new Borrower("ID006", "Laura Novelle");
borrower.getBorrowedItems().addItem(
catalog.getItem("B007"));
borrower.getBorrowedItems().addItem(
catalog.getItem("B009"));
borrowerDB.addBorrower(borrower);
borrower = new Borrower("ID007", "David M. Prescott");
borrower.getBorrowedItems().addItem(
catalog.getItem("B011"));
borrowerDB.addBorrower(borrower);
borrower = new Borrower("ID008", "Francis Matthews");
borrower.getBorrowedItems().addItem(
catalog.getItem("R003"));
borrower.getBorrowedItems().addItem(
catalog.getItem("B005"));
borrowerDB.addBorrower(borrower);
borrower = new Borrower("ID009", "Thomas Ferris");
borrowerDB.addBorrower(borrower);
borrower = new Borrower("ID010", "John Johnson");
borrower.getBorrowedItems().addItem(
catalog.getItem("B004"));
borrowerDB.addBorrower(borrower);
return borrowerDB;
}
/**
* Presenta un men de opciones y ejecuta la
* tarea seleccionada.
*/
private void run() throws IOException {
int

choice = getChoice();

while (choice != 0)

if (choice == 1) {
setBorrowersFormatter(

212: PlainTextBorrowersFormatter.getSingletonInstance());
213:
} else if (choice == 2) {
214:
setBorrowersFormatter(
215:
HTMLBorrowersFormatter.getSingletonInstance());
216:
} else if (choice == 3) {
217:
setBorrowersFormatter(
218:
XMLBorrowersFormatter.getSingletonInstance());
219:
}
220:
displayBorrowers();
221:
222:
choice = getChoice();
223:
}
224:
}
225:
226:
/**
227:
* Despliega un men de opciones y verifica la opcin.
228:
*
229:
* @return un entero dentro del rango [0,3]
230:
*/
231:
private int getChoice() throws IOException {
232:
233:
int input;
234:
235:
do {
236:
try {
237:
stdErr.println();
238:
stdErr.print("[0] Quit\n"
239:
+ "[1] Display Plain Text\n"
240:
+ "[2] Display HTML\n"
241:
+ "[3] Display XML\n"
242:
+ "choice> ");
243:
stdErr.flush();
244:
245:
input = Integer.parseInt(stdIn.readLine());
246:
247:
stdErr.println();
248:
249:
if (0 <= input && 3 >= input) {
250:
break;
251:
} else {
252:
stdErr.println("Invalid choice: " + input);
253:
}
254:
} catch (NumberFormatException nfe) {
255:
stdErr.println(nfe);
256:
}
257:
} while (true);
258:
259:
return input;
260:
}
261:
262:
/**
263:
* Cambia el formato en el cual la base de datos de usuarios ser
264:
* desplegada.
265:
*
266:
* @param newFormatter formato en el cual la base de datos de
267: usuarios ser
268:
*
desplegada.

269:
270:
271:
272:
273:
274:
275:
276:
277:

*/
private void setBorrowersFormatter(
BorrowersFormatter newFormatter) {
borrowersFormatter = newFormatter;
}
/**
* Despliega los usuarios en el formato actual.
*/
private void displayBorrowers() {
stdOut.println(
borrowersFormatter.formatBorrowers(borrowerDB));
}
}

Listado 6 LibrarySystem.java
En las lneas 204 a 214, la aplicacin responde a la entrada del usuario. Los mtodos
setBorrowersFormatter y displayBorrowers son llamados uno despus de otro. Esto
no ocurre necesariamente. Considera una interfaz grfica de usuario (GUI) para el sistema
de la biblioteca que contiene botones de radio para especificar el formato y un botn para
especificar la base de datos de usuarios en el formato especificado. Cuando el usuario
selecciona un botn de radio, la clase GUI debe llamar a setBorrowersFormatter.
Posteriormente, cuando el usuario hace clic en el botn de Desplegar, la clase GUI debe
llamar a displayBorrowers.
Referencias
Shalloway, Alan and James R. Trott. Design Patterns Explained: A New Perspective on
Object-Oriented Design. Addison-Wesley Publishing Co., 2001.

Unidad 3. Implementacin Avanzada de


Clases

3.1 Programacin de Entrada y Salida


3.2 Intefaz Grfica del Usuario
3.3 Hacia el Uso Comercial

3.1 Programacin de Entrada y Salida

3.1.1 E/S con Archivos


3.1.2 Usando E/S con Archivos en el Sistema de Biblioteca

3.1.1 E/S con Archivos

Declaracin e Inicializacin de Objetos de E/S con Archivos


Utilizacin de Objetos de E/S con Archivos
Cmo Cerrar Archivos
Ejemplo de Programa de E/S con Archivos
Lecturas:

Requerido:
o Barker, primera edicin, captulo 15 (pginas 427
32).
o Barker, segunda edicin, captulo 15 (pginas 624
630).
Secuencia: Lee el libro de texto antes de leer esta pgina.

Declaracin e Inicializacin de Objetos de E/S con Archivos


Todo lo que hemos visto de E/S (I/O) hasta este punto ha sido las operaciones sobre la
consola. Recuerda que las clases de que necesitan E/S de la consola comienzan con las
siguientes declaraciones:
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:

/* Flujo de entrada estndar */


private static BufferedReader stdIn =
new BufferedReader(new InputStreamReader(System.in));
/* Flujo de salida estndar */
private static PrintWriter stdOut =
new PrintWriter(System.out, true);
/* Flujo de error estndar */
private static PrintWriter stdErr =
new PrintWriter(System.err, true);

Listado 1 Declaraciones E/S de la consola


BufferedReader y PrintWriter cubren simplemente los objetos ms primitivos de E/S de
la consola: System.in, System.out y System.err, proporcionando una interfaz ms
refinada y conveniente. Las clases BufferedReader y PrintWriter pueden utilizarse para

abarcar otros objetos de E/S, incluyendo aquellos utilizados para E/S con archivos. En este
curso, las clases que necesitan E/S con archivos emplearn las siguientes declaraciones:
1: BufferedReader fileIn =
2:
new BufferedReader(new FileReader(filename));
3:

4: PrintWriter fileOut =
5:
new PrintWriter(new FileWriter(filename));
6:
7: PrintWriter fileAppend =
8:
new PrintWriter(new FileWriter(filename, true);

Listado 2 Declaraciones de E/S con archivos


El argumento filename utilizado en las declaraciones es simplemente un String que
indica el nombre del archivo que se desea abrir.
El constructor de FileReader no slo crea un objeto, tambin abre el archivo especificado
en modo de lectura. Es decir, nos brinda un mecanismo para leer datos del archivo. El
constructor de FileWriter hace posible escribir datos en el archivo especificado. Cuando
el constructor de FileWriter de un argumento abre un archivo, borra los contenidos de
dicho archivo. Obviamente, esto no resulta apropiado en algunas situaciones. Cuando se
requiere aadir datos a un archivo, se debe utilizar el constructor de FileWriter de dos
argumentos: si el segundo argumento que se pasa a este constructor es true, los contenidos
del archivo se conservan al abrir el archivo. (Si el segundo elemento, llamado append, es
false, los contenidos se borran.)
Cuando se abre un archivo para escritura y no existe el archivo especificado, el sistema
servidor crea un nuevo archivo, inicialmente vaco.

Utilizacin de Objetos de E/S con Archivos


La declaracin de objetos E/S con archivos es muy similar a la declaracin de objetos E/S
de la consola. Y, debido a que los objetos FileReader y FileWriter son abarcados de
forma similar por BufferedReader y PrintWriter, respectivamente, los objetos E/S de
archivos y los objetos E/S de la consola comparten muchos mtodos. Como consecuencia,
el cdigo para E/S con archivos se ve muy similar al cdigo para E/S de la consola. A
continuacin se presenta un ejemplo para leer de un archivo, seguido inmediatamente por
un ejemplo similar para leer de la consola.
1:
2:
3:
4:
5:

// leyendo desde un archivo


int value = Integer.parseInt(fileIn.readLine());
// leyendo desde la consola
int value = Integer.parseInt(stdIn.readLine());

Listado 3 Usando el mtodo readLine


Si se utiliza el mtodo BufferedReader.readLine para leer los contenidos de un archivo,
regresar null al llegar al final del archivo. El siguiente bucle, que lee todas las lneas de
un archivo, toma ventaja de este hecho:
1: String line = fileIn.readLine();
2:
3: while (line != null) {

4:
5:
6:
7: }

// procesa la lnea
line = fileIn.readLine();

Listado 4 Leyendo un archivo


A continuacin se muestra un ejemplo de cmo escribir en un archivo, seguido de
inmediato por un ejemplo similar para escribir en la consola:
1:
2:
3:
4:
5:

// escribiendo en un archivo
fileOut.println(5);
// escribiendo en la consola
stdOut.println(5);

Listado 5 Usando el mtodo println


Existen dos reas que requieren atencin extra al utilizar E/S con archivos. Mientras que la
inicializacin de objetos E/S de la consola generalmente resulta exitosacomo qued
evidenciado por el hecho de que los constructores de BufferedReader,
InputStreamReader y PrintWriter presentados en esta pgina no lanzan ninguna
excepcininicializar objetos de E/S con archivos puede fracasar. El constructor de
FileReader que toma un nombre de archivo como argumento puede lanzar una excepcin
FileNotFoundException. Esto es de esperarse, ya que resulta lgico pensar que la cadena
de caracteres dada a este constructor podra ser el nombre de un archivo que no existe. Date
cuenta que FileNotFoundException es una subclase directa de IOException.
Los constructores de FileWriter que toman un nombre de archivo como argumento
tambin pueden lanzar una excepcin IOException. Adems, el mtodo readLine de la
clase BufferedReader lanza una excepcin IOException si hay algn error durante la
lectura.

Cmo Cerrar Archivos


Debido a que mantener archivos abiertos ocupa recursos del sistema, deben cerrarse los
archivos que ya no se utilizarn. Esta accin debe ser realizada explcitamente por el
programador:
1:
2:
3:
4:
5:
6:
7:
8:
9:

BufferedReader fileIn =
new BufferedReader(new FileReader(filename));
PrintWriter fileOut =
new PrintWriter(new FileWriter(filename));
...
fileIn.close();
fileOut.close();

Listado 6 Cerrando Archivos

El mtodo close de las clases BufferedReader y PrintWriter lanza una excepcin


IOException si hay algn error al cerrar los archivos.

Ejemplo de Programa de E/S con Archivos


La clase CopyFile es un ejemplo simple de E/S con archivos. En primer lugar, pide al
usuario dos nombres de archivo, el nombre de un archivo de entrada y el nombre de un
archivo de salida, y despus copia los contenidos del archivo de entrada al archivo de
salida.
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:

import

java.io.*;

/**
* Hace una copia de un archivo.
*
* @author
* @version 1.0.0
*/
public class CopyFile {
/* Flujo de entrada estndar */
private static BufferedReader stdIn =
new BufferedReader(new InputStreamReader(System.in));
/* Flujo de salida estndar */
private static PrintWriter stdOut =
new PrintWriter(System.out, true);
/* Flujo de error estndar */
private static PrintWriter stdErr =
new PrintWriter(System.err, true);
/**
* Hace una copia de un archivo.
*
* @param args no utilizado.
* @throws IOException Si ocurre un error de E/S.
*/
public static void main(String[] args) throws IOException
stdErr.print("Source filename:
stdErr.flush();

");

BufferedReader input =
new BufferedReader( new FileReader(stdIn.readLine()));
stdErr.print("Destination filename:
stdErr.flush();

");

PrintWriter output =
new PrintWriter(new FileWriter(stdIn.readLine()));
String

line = input.readLine();

45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55: }

while (line != null) {


output.println(line);
line = input.readLine();
}
input.close();
output.close();
stdOut.println("done");
}

Listado 7 CopyFile.java
En las lneas 34 y 40, se abren los archivos de entrada y salida. El cdigo de la lnea 43 a la
lnea 48 lee una lnea del archivo de entrada y escribe esa misma lnea en el archivo de
salida. Cuando se llega al final del archivo, el valor de la variable line toma un valor de
null y entonces la condicin no se cumple y se termina el bucle while. En las lneas 50 y
51, se cierran los archivos.

3.1.2 Usando E/S con Archivos en el Sistema de


Biblioteca

Leyendo Datos de un Archivo


Escribiendo Datos a un Archivo
El Sistema de Biblioteca Completo

En esta pgina te presentamos una versin del sistema de biblioteca que incorpora E/S con
archivos. En esta versin:
1. Los datos del catlogo de la biblioteca no estarn inmersos en la codificacin de la
aplicacin. En vez de eso, el catlogo estar almacenado en un archivo de datos y el
sistema cargar el catlogo de dicho archivo.
2. El sistema ser capaz de guardar la informacin de los usuarios de la biblioteca en un
archivo, utilizando alguno de los siguientes tres formatos: Texto plano, HTML y XML.

Leyendo Datos de un Archivo


Recuerda que el sistema de la biblioteca contiene dos tipos de elementos del catlogo:
libros y grabaciones. Cada lnea del archivo catalog.dat almacena slo un elemento del
catlogo.
Las lneas con la informacin de los libros tienen el siguiente formato:
Book_code_title_year_author_numberOfPages

Donde:

"Book" es un prefijo que indica el tipo de la lnea.


code es una cadena de caracteres que representa el cdigo del libro.
title es una cadena de caracteres que representa el ttulo del libro.
year es un entero que representa el ao en que fue publicado el libro.
author es una cadena de caracteres que representa el autor del libro.
numberOfPages es un entero que representa el nmero de pginas del libro.

Los campos estn delimitados por un guin bajo ( _ ). Los campos en s no contienen
guiones bajos.
Las lneas con la informacin de las grabaciones tienen el siguiente formato:
Recording_code_title_year_performer_format

Donde:

"Recording" es un prefijo que indica el tipo de la lnea.


code es una cadena de caracteres que representa el cdigo de la grabacin.

title es una cadena de caracteres que representa el ttulo de la grabacin.


year es un entero que representa el ao de la grabacin.
performer es una cadena de caracteres que representa el intrprete de la grabacin.
format es una cadena de caracteres que representa el formato de la grabacin.

Los campos estn delimitados por un guin bajo ( _ ). Los campos en s no contienen
guiones bajos.
El siguiente archivo contiene el catlogo de una biblioteca en el formato descrito
anteriormente:

catalog.dat. Archivo que contiene un catlogo de biblioteca.

El siguiente diagrama de clase resalta los elementos utilizados para implementar esta
versin del sistema de biblioteca:

Figura 1 Porcin del diagrama de clase del Sistema de Biblioteca

A continuacin se presentan las especificaciones de la interfaz LibraryCatalogLoader, la


clase FileLibraryCatalogLoader y la clase DataFormatException:
Interfaz LibraryCatalogLoader

La interfaz LibraryCatalogLoader declara un mtodo que carga un catlogo de biblioteca


desde un archivo.

Mtodo:

Catalog loadCatalog(String filename)


throws FileNotFoundException,
IOException,
DataFormatException

Carga la informacin que se encuentra en el archivo especificado en el catlogo de


biblioteca.

A continuacin se presenta una implementacin de la interfaz LibraryCatalogLoader:


1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:

import java.io.*;
/**
* Esta interfaz declara un mtodo para obtener un catlogo de
biblioteca
* de un archivo.
*
* @author
* @version 1.1.0
* @see Catalog
*/
public interface LibraryCatalogLoader {
/**
* Carga la informacin en el archivo especificado en un catlogo
* de biblioteca y regresa el catlogo.
*
* @param filename el nombre del archivo que contiene
*
los datos del catlogo.
* @return un {@link Catalog} con los datos indicados en el
archivo.
* @throws IOException si hay un error al leer la informacin del
*
archivo en el archivo especificado.
* @throws FileNotFoundException si el archivo especificado no
*
existe.
* @throws DataFormatException si el archivo contiene datos mal
*
formados.
*/
Catalog loadCatalog(String filename) throws IOException,
FileNotFoundException, DataFormatException;
}

Listado 1 LibraryCatalogLoader.java
Clase FileLibraryCatalogLoader

La clase FileLibraryCatalogLoader implementa la interfaz LibraryCatalogLoader. Se


utiliza para cargar un catlogo de biblioteca a partir de un archivo.

Mtodos:

public Catalog loadCatalog(String fileName)


throws FileNotFoundException,
IOException,
DataFormatException

Carga la informacin del archivo especificado en un catlogo de biblioteca. Este


mtodo comienza por abrir el archivo para lectura. Despus procede a leer cada
lnea del archivo. Si la lnea contiene datos de un libro, llama al mtodo readBook
para extraer la informacin del libro y crea un objeto Book; si la lnea contiene
datos de una grabacin, llama a readRecording. Por ltimo, loadCatalog aade el
libro (o grabacin ) al catlogo de biblioteca.
Este mtodo puede lanzar las siguientes excepciones:
o
o
o

FileNotFoundException. Si el archivo especificado no existe.


IOException. Si hay algn error al leer la informacin del archivo especificado.
DataFormatException. Si una lnea del archivo tiene errores (la excepcin

contendra la lnea de los datos mal formados).

private Book readBook (String line)


throws DataFormatException

Este mtodo utiliza la clase StringTokenizer para extraer los datos del libro de la
lnea especificada. Si la lnea no tiene ningn error, este mtodo regresa un objeto
Book que encapsula los datos del libro. Si la lnea tiene errores, es decir, si no tiene
el nmero de tokens esperado o los tokens que deberan contener un entero no lo
tienen, este mtodo lanza una excepcin DataFormatException que contiene la lnea
con los datos mal formados.

private Recording readRecording(String line)

Este mtodo usa la clase StringTokenizer para extraer los datos de la grabacin
de la lnea especificada. Si la lnea no tiene ningn error, este mtodo regresa un
objeto Recording que encapsula los datos de la grabacin. Si la lnea tiene errores,
es decir, si no tiene el nmero de tokens esperado o los tokens que deberan
contener un entero no lo tienen, este mtodo lanza una excepcin
DataFormatException que contiene la lnea con los datos mal formados.
A continuacin se presenta la implementacin de la clase FileLibraryCatalogLoader:
1:
2:
3:
4:
5:
6:
7:
8:
9:

import java.util.*;
import java.io.*;
/**
* Crea un catlogo de biblioteca y lo carga con los datos
almacenados
* en un archivo.
*
* @author
* @version 1.0.0
* @see LibraryCatalogLoader

10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:

* @see Catalog
* @see CatalogItem
* @see Recording
* @see Book
*/
public class FileLibraryCatalogLoader implements LibraryCatalogLoader
{
/* Prefijo de una lnea con datos de libros */
private final static String BOOK_PREFIX = "Book";
/* Prefijo de una lnea de datos de grabaciones */
private final static String RECORDING_PREFIX = "Recording";
/* Delimitador */
private final static String DELIM = "_";
/**
* Carga la informacin del archivo especificado en un catlogo
de
* biblioteca y regresa el catlogo.
*
* @param filename El nombre de un archivo que contiene
informacin
*
del catlogo.
* @return un {@link Catalog} con los datos indicados en el
archivo.
* @throws IOException si hay algn error al leer la
*
informacin del archivo especificado.
* @throws FileNotFoundException si el archivo especificado no
*
existe.
* @throws DataFormatException si el archivo contiene datos mal
*
formados.
*/
public Catalog loadCatalog (String filename) throws IOException,
FileNotFoundException, DataFormatException {
Catalog catalog = new Catalog();
BufferedReader reader =
new BufferedReader(new FileReader(filename));
String line = reader.readLine();
while (line != null) {
CatalogItem item = null;
if (line.startsWith(BOOK_PREFIX)) {
item = readBook(line);
} else if (line.startsWith(RECORDING_PREFIX)) {
item = readRecording(line);
} else {
throw new DataFormatException(line);
}
catalog.addItem(item);

59:
line = reader.readLine();
}
60:
61:
reader.close();
62:
63:
return catalog;
64:
}
65:
/**
66:
* Extrae los datos del libro del archivo en la lnea
67:
especificada
y regresa
68:
* un objeto {@link Book} que encapsula los datos del libro.
69:
*
70:
* @param line una cadena que contiene datos de libros.
71:
* @return un objeto <code>Book</code> que encapsula los datos
72: del
*
libro en la lnea especificada.
73:
*
@throws
DataFormatException
si la lnea contiene errores.
74:
*/
75:
private Book readBook (String line) throws DataFormatException {
76:
77:
StringTokenizer tokenizer = new StringTokenizer(line, DELIM);
78:
79:
if (tokenizer.countTokens() != 6) {
80:
throw new DataFormatException(line);
81:
} else {
82:
try {
83:
84:
String prefix = tokenizer.nextToken();
85:
return new Book (tokenizer.nextToken(),
86:
tokenizer.nextToken(),
87:
88:
Integer.parseInt(tokenizer.nextToken()),
89:
tokenizer.nextToken(),
90:
91: Integer.parseInt(tokenizer.nextToken()));
92:
} catch (NumberFormatException nfe) {
93:
throw new DataFormatException(line);
94:
}
95:
}
96:
}
97:
98:
/**
99:
* Extrae los datos de la grabacin en la lnea especificada y
100: regresa
* un objeto {@link Recording} que encapsula los datos del libro.
101:
*
102:
* @param line una cadena que contiene datos de la grabacin.
103:
* @return un objeto <code>Recording</code> que encapsula los
104:
*
datos de la grabacin en la lnea especificada.
105:
* @throws DataFormatException si la lnea contiene errores.
*/
106:
private Recording readRecording (String line)
107:
throws DataFormatException {

108:
StringTokenizer tokenizer =
new StringTokenizer(line,
109:
110: DELIM);
111:
if (tokenizer.countTokens() != 6) {
112:
113:
throw new DataFormatException(line);
114:
} else {
try {
115:
116:
String prefix = tokenizer.nextToken();
117:
118:
return new Recording (tokenizer.nextToken(),
119:
tokenizer.nextToken(),
120:
Integer.parseInt(
121:
tokenizer.nextToken()),
tokenizer.nextToken(),
122:
tokenizer.nextToken());
123:
}
catch
(NumberFormatException
nfe) {
124:
125:
throw new DataFormatException(line);
126:
}
127:
}
128:
}
129: }
130:
131:
132:
133:
134:
135:
136:
137:
138:
139:

Listado 2 FileLibraryCatalogLoader.java
Clase DataFormatException

Esta excepcin es lanzada cuando una lnea de un archivo que est siendo analizado
contiene errores:

La lnea no tiene el nmero de tokens esperado.


Los tokens que deben contener nmeros, no lo tienen.

La siguiente es una implementacin de la clase DataFormatException:


1: /**
2: * Esta excepcin es lanzada cuando se detectan datos mal formados
mientras

3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:

* se analiza un archivo.
*
* @author
* @version 1.0.0
*/
public class DataFormatException extends Exception

/**
* Construye una excepcin <code>DataFormatException</code> sin
mensaje de
* detalle.
*/
public DataFormatException() {
}
/**
* Construye una excepcin <code>DataFormatException</code> con un
* mensaje de detalle de la excepcin.
*
* @param message los datos mal formados
*/
public DataFormatException(String message) {
super(message);
}
}

Listado 3 DataFormatException.java

Escribiendo Datos a un Archivo


En la pgina Patrn de Diseo Estrategia (Strategy), presentamos una versin del sistema
de biblioteca que desplegaba la base de datos de usuarios en tres formatos: texto plano,
HTML y XML. En esta pgina, te presentaremos una versin que guarda la base de datos
de usuarios en un archivo en cualquiera de los tres formatos:
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:

import java.io.*;
import java.util.*;
/**
* Esta clase implementa un ejemplo del sistema de biblioteca.
*
* @author
* @version 1.1.0
* @see CatalogItem
* @see Book
* @see Recording
* @see Catalog
* @see Borrower
* @see BorrowerDatabase

13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:

* @see BorrowersFormatter
* @see PlainTextBorrowersFormatter
* @see HTMLBorrowersFormatter
* @see XMLBorrowersFormatter
* @see LibraryCatalogLoader
* @see FileLibraryCatalogLoader
*/
public class LibrarySystem {
private static BufferedReader stdIn =
new BufferedReader(new InputStreamReader(System.in));
private static PrintWriter stdOut =
new PrintWriter(System.out, true);
private static PrintWriter stdErr =
new PrintWriter(System.err, true);
private Catalog

catalog;

private BorrowerDatabase borrowerDB;


private BorrowersFormatter borrowersFormatter;
/**
* Carga un catlogo de biblioteca y una base de datos del
prestatario
* de un archivo y despus comienza la aplicacin.
* <p>
* El nombre del archivo es especificado en los argumentos del
comando
* </p>
*
* @param args argumentos String.
* @throws IOException si hay errores en la entrada.
*/
public static void main(String[] args) throws IOException {
if (args.length != 1) {
stdErr.println("Usage: java LibrarySystem filename");
} else {
Catalog catalog = null;
try {
LibraryCatalogLoader loader =
new FileLibraryCatalogLoader();
catalog = loader.loadCatalog(args[0]);
} catch (FileNotFoundException fnfe) {
stdErr.println("The file does not exist");
System.exit(1);
} catch (DataFormatException dfe) {
stdErr.println("The file contains malformed data: "
+ dfe.getMessage());

62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:
80:
81:
82:
83:
84:
85:
86:
87:
88:
89:
90:
91:
92:
93:
94:
95:
96:
97:
98:
99:
100:
101:
102:
103:
104:
105:
106:
107:
108:
109:
110:

System.exit(1);
}
LibrarySystem

app = new LibrarySystem(catalog);

app.run();
}
}
/*
* Construye un objeto <code>LibrarySystem</code>.
* Inicializa el catlogo y la base de datos del usuario con
* los valores especificados en el parmetro.
*/
private LibrarySystem(Catalog initialCatalog) {
this.catalog = initialCatalog;
this.borrowerDB = loadBorrowers(catalog);
this.borrowersFormatter =
PlainTextBorrowersFormatter.getSingletonInstance();
}
/*
* Carga un objeto BorrowerDatabase.
*/
private BorrowerDatabase loadBorrowers(Catalog catalog) {
BorrowerDatabase borrowerDB = new BorrowerDatabase();
Borrower borrower = new Borrower("ID001", "James Addy");
borrower.getBorrowedItems().addItem(
catalog.getItem("B003"));
borrower.getBorrowedItems().addItem(
catalog.getItem("R001"));
borrower.getBorrowedItems().addItem(
catalog.getItem("B012"));
borrowerDB.addBorrower(borrower);
borrower = new Borrower("ID002", "John Doust");
borrowerDB.addBorrower(borrower);
borrower = new Borrower("ID003", "Constance Foster");
borrower.getBorrowedItems().addItem(
catalog.getItem("B006"));
borrowerDB.addBorrower(borrower);
borrower = new Borrower("ID004", "Harold Gurske");
borrower.getBorrowedItems().addItem(
catalog.getItem("B002"));
borrowerDB.addBorrower(borrower);
borrower = new Borrower("ID005", "Mary A. Rogers");
borrowerDB.addBorrower(borrower);
borrower = new Borrower("ID006", "Laura Novelle");
borrower.getBorrowedItems().addItem(

111:
catalog.getItem("B007"));
borrower.getBorrowedItems().addItem(
112:
catalog.getItem("B009"));
113:
borrowerDB.addBorrower(borrower);
114:
115:
borrower = new Borrower("ID007", "David M. Prescott");
116:
borrower.getBorrowedItems().addItem(
117:
catalog.getItem("B011"));
borrowerDB.addBorrower(borrower);
118:
119:
borrower = new Borrower("ID008", "Francis Matthews");
120:
borrower.getBorrowedItems().addItem(
121:
catalog.getItem("R003"));
122:
borrower.getBorrowedItems().addItem(
123:
catalog.getItem("B005"));
124:
borrowerDB.addBorrower(borrower);
125:
borrower = new Borrower("ID009", "Thomas Ferris");
126:
borrowerDB.addBorrower(borrower);
127:
128:
borrower = new Borrower("ID010", "John Johnson");
129:
borrower.getBorrowedItems().addItem(
130:
catalog.getItem("B004"));
131:
borrowerDB.addBorrower(borrower);
132:
return borrowerDB;
133:
}
134:
135:
/*
136:
* Presenta un men de opciones y ejecuta la tarea seleccionada.
137:
*/
private void run() throws IOException {
138:
139:
int choice = getChoice();
140:
141:
while (choice != 0) {
142:
if (choice == 1) {
143:
displayCatalog();
144:
} else if (choice == 2) {
this.borrowersFormatter =
145:
146:
147: PlainTextBorrowersFormatter.getSingletonInstance();
writeFile(readFileName(),
148:
149: this.borrowersFormatter.formatBorrowers(this.borrowerDB));
150:
} else if (choice == 3) {
151:
this.borrowersFormatter =
HTMLBorrowersFormatter.getSingletonInstance();
152:
writeFile(readFileName(),
153:
154:
this.borrowersFormatter.formatBorrowers(this.borrowerDB));
155:
} else if (choice == 4) {
156:
this.borrowersFormatter =
157:
XMLBorrowersFormatter.getSingletonInstance();
writeFile(readFileName(),
158:
159:
this.borrowersFormatter.formatBorrowers(this.borrowerDB));

160:
}
161:
choice = getChoice();
162:
}
163:
}
164:
165:
/*
166:
* Despliega un men de opciones y verifica la seleccin del
167: usuario.
*/
168:
private
int getChoice() throws IOException {
169:
170:
int input;
171:
172:
do {
173:
try {
stdErr.println();
174:
stdErr.print("[0] Quit\n"
175:
+ "[1] Display catalog\n"
176:
+ "[2] Save borrower database (plain
177:
text)\n"
178:
+ "[3] Save borrower database (HTML)\n"
179:
+ "[4] Save borrower database (XML)\n"
180:
+ "choice> ");
stdErr.flush();
181:
182:
input = Integer.parseInt(stdIn.readLine());
183:
184:
stdErr.println();
185:
186:
if (0 <= input && 4 >= input) {
break;
187:
} else {
188:
stdErr.println("Invalid choice: " + input);
189:
}
190:
} catch (NumberFormatException nfe) {
191:
stdErr.println(nfe);
192:
}
193:
} while (true);
194:
return input;
195:
}
196:
197:
/*
198:
* Despliega el catlogo.
199:
*/
200:
private void displayCatalog() {
201:
int numberOfItems = this.catalog.getNumberOfItems();
202:
203:
if (numberOfItems == 0) {
204:
stdErr.println("The catalog is empty");
205:
} else {
206:
for (CatalogItem item : this.catalog) {
stdOut.println(item.getCode() + " "
207:
+ item.getTitle() + " " +
208:
(item.isAvailable()? "(A)" : "(NA)"));

209:
}
}
210:
}
211:
212:
/*
213:
* Solicita un nombre de archivo (el nombre del archivo que
214:
* almacenar la base de datos de usuarios) y regresa la
215: respuesta.
*/
216:
private String readFileName() throws IOException {
217:
218:
stdErr.print("File name> ");
219:
stdErr.flush();
220:
221:
return stdIn.readLine();
222:
}
223:
/*
224:
* Crea un nuevo archivo (que tiene el nombre especificado) y
225:
escribe
226:
* la cadena especificada en nuevo archivo
227:
*/
228:
private void writeFile(String fileName, String content)
229:
throws IOException {
230:
PrintWriter fileOut =
231:
new PrintWriter(new FileWriter(fileName));
232:
233:
fileOut.println(content);
234:
fileOut.close();
235:
}
236: }
237:
238:
239:
240:
241:
242:
243:
244:
245:
246:
247:
248:
249:
250:
251:
252:
253:
254:
255:
256:
257:

258:
259:
260:
261:
262:
263:
264:

Listado 4 LibrarySystem.java

El mtodo writeFile, en la lnea 255, recibe un nombre de archivo y una cadena de


caracteres formateada que contiene la informacin del usuario. En las lneas 258 y 259, el
mtodo crea un nuevo archivo (que tiene el nombre especificado) y despus, en la lnea
261, el mtodo escribe la cadena de caracteres formateada en un nuevo archivo. Observa
que la cadena de caracteres formateada contendr caracteres de fin de lnea ( \n ) porque
cada uno de los formatos utiliza caracteres de fin de lnea.
Utiliza el siguiente comando desde la lnea de comandos para correr el Sistema de
Biblioteca:
C:\>java LibrarySystem catalog.dat

3.2 Interfaz Grfica del Usuario

3.2.1 Componentes y Contenedores Swing


3.2.2 Manejo de Eventos Swing
3.2.3 Clase JFileChooser

3.2.1 Componentes y Contenedores Swing

Componente JLabel
Componente JButton
Componente JRadioButton
Componente JTextField
Componente JTextArea
Componente JList
Lecturas:

Requerida:
o Barker, primera edicin, captulo 16 (pginas 471
522).
o Barker, segunda edicin, captulo 16 (pginas 681
735).
Secuencia: Lee el libro de texto antes de leer esta pgina.

Esta pgina muestra cmo se crean y se personalizan los componentes Swing. La pgina
Manejo de Eventos Swing mostrar cmo se manejan los eventos de estos componentes.

Componente JLabel
Los componentes de la clase JLabel pueden desplegar texto, una imagen o ambos. La clase
JLabelDemo crea una ventana con tres componentes JLabel:
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:

import java.awt.*;
import javax.swing.*;
/**
* Demuestra el componente {@link JLabel}. Esta clase hereda de
* la clase {@link JPanel}.
*
* @author
* @version 1.0.0
*/
public class JLabelDemo extends JPanel {
private JLabel labelLeft;
private JLabel labelCenter;
private JLabel labelRight;
/**
* Crea una ventana.
*
* @param args no utilizado.
*/
public static void main(String[] args) {

23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62: }

JFrame frame = new JFrame("JLabelDemo");


frame.setContentPane(new JLabelDemo());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
// Ajusta el tamao de la ventana
frame.setVisible(true);
}
/**
* Crea tres componentes {@link JLabel}.
*/
public JLabelDemo() {
setLayout(new GridLayout(1, 3));
setBackground(Color.white);
ImageIcon icon = new ImageIcon("images/bananas.gif",
"an image with bananas");
// Crea los componentes
labelLeft = new JLabel("Hello", icon, JLabel.CENTER);
labelCenter = new JLabel("Hello");
labelRight = new JLabel(icon);
// Establece la posicin del texto, relativa al icono
labelLeft.setVerticalTextPosition(JLabel.BOTTOM);
labelLeft.setHorizontalTextPosition(JLabel.CENTER);
labelLeft.setFont(new Font("Serif", Font.BOLD, 16));
// Establece la alineacin y la fuente de la etiqueta
labelCenter.setHorizontalAlignment(JLabel.CENTER);
labelCenter.setFont(new Font("Serif", Font.BOLD, 30));
// Aade etiquetas al contenedor
add(labelLeft);
add(labelCenter);
add(labelRight);
}

Listado 1 JLabelDemo.java
La siguiente ventana se despliega al ejecutar JLabelDemo:

Figura 1 Ejecucin de JLabelDemo

La primera etiqueta (label) contiene texto e imagen, la segunda etiqueta contiene texto y la
tercera etiqueta contiene una imagen.
Observa los siguientes aspectos del cdigo:

En la lnea 40, el constructor ImageIcon recibe el nombre del archivo de imagen y


una cadena de caracteres con la descripcin de la imagen.

En

las

lneas

49

y 50, los mtodos setHorizontalTextPosition y


modifican la posicin horizontal y vertical del texto,

setVerticalTextPosition

en relacin a la imagen.

En las lneas 51 y 55, el mtodo setFont modifica la fuente del texto.

En la lnea 54, el mtodo setHorizontalAlignment modifica la alineacin del


texto a lo largo del eje X.

Los dems mtodos de JLabel incluyen:

void setText(String). Modifica el texto del componente.


String getText(). Obtiene el texto del componente.
void setIcon(Icon). Modifica la imagen del componente.
Icon getIcon(). Obtiene la imagen del componente.
void setIconTextGap(int). Define el espacio (en pxeles)

entre el texto y la

imagen.

Componente JButton
Los componentes de la clase JButton pueden desplegar texto, una imagen o ambos. La
clase JButtonDemo crea una ventana con dos componentes JButton:
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:

import java.awt.*;
import javax.swing.*;
/**
* Demuestra el componente {@link JButton}. Esta clase hereda de
* la clase {@link JPanel}.
*
* @author
* @version 1.0.0
*/
public class JButtonDemo extends JPanel {
private
private
private
private
/**

JButton buttonUp;
JButton buttonDown;
ImageIcon arrowUp;
ImageIcon arrowDown;

19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69: }

* Crea una ventana.


*
* @param args no utilizado.
*/
public static void main(String[] args) {
JFrame frame = new JFrame("JButtonDemo");
frame.setContentPane(new JButtonDemo());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
// Ajusta el tamao de la ventana
frame.setVisible(true);
}
/**
* Crea dos componentes {@link JButton}.
*/
public JButtonDemo() {
setLayout(new GridLayout(2, 1));
setBackground(Color.white);
arrowUp = new ImageIcon("images/up.gif",
"up arrow");
arrowDown= new ImageIcon("images/down.gif",
"down arrow");
// Crea los componentes
buttonUp = new JButton("Up", arrowUp);
buttonDown = new JButton("Down", arrowDown);
// Establece la posicin del texto, relativa al icono
buttonUp.setVerticalTextPosition(AbstractButton.CENTER);
buttonUp.setHorizontalTextPosition(AbstractButton.LEFT);
buttonDown.setVerticalTextPosition(AbstractButton.CENTER);
buttonDown.setHorizontalTextPosition(AbstractButton.LEFT);
// Establece el color de los botones
buttonUp.setBackground(new Color(0, 100, 0));
buttonDown.setBackground(new Color(0, 100, 0));
buttonUp.setForeground(Color.white);
buttonDown.setForeground(Color.white);
// Deshabilita el botn Down
buttonDown.setEnabled(false);
// Aade botones al contenedor
add(buttonUp);
add(buttonDown);
}

Listado 2 JButtonDemo.java
La siguiente ventana es desplegada cuando se ejecuta JButtonDemo:

Figura 2 Ejecucin de JButtonDemo


Observa los siguientes aspectos del cdigo:

En las lneas 41 y 43, el constructor ImageIcon recibe el nombre del archivo de


imagen y una cadena de caracteres con la descripcin de la imagen.

En

54, los mtodos setHorizontalTextPosition y


setVerticalTextPosition modifican la posicin horizontal y vertical del texto,
en relacin con la imagen.

En las lneas 57 a 60, los mtodos setBackground y setForeground modifican el


color del fondo y el color del texto del componente.

En la lnea 63, el mtodo setEnabled deshabilita el botn Down.

las

lneas

51

Los dems mtodos de JButton incluyen:

void setText(String). Modifica el texto del componente.


String getText(). Obtiene el texto del componente.
void setIcon(Icon). Modifica la imagen del componente.
Icon getIcon(). Obtiene la imagen del componente.
void setFont(Font). Modifica la fuente del componente.

Componente JRadioButton
Los componentes de la clase JRadioButton pueden ser seleccionados o deseleccionados
por el usuario. Si los componentes JRadioButton son agrupados, por medio de la clase
ButtonGroup, slo puede seleccionarse un botn a la vez. La clase JButtonDemo crea una
ventana con tres componentes JRadioButton y los agrupa:
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:

import java.awt.*;
import javax.swing.*;
/**
* Demuestra el componente {@link JRadioButton}. Esta clase hereda de
* la clase {@link JPanel}.
*
* @author
* @version 1.0.0
*/
public class JRadioButtonDemo extends JPanel {

12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61: }

private JRadioButton
private JRadioButton
private JRadioButton

buttonOne;
buttonTwo;
buttonThree;

/**
* Crea una ventana.
*
* @param args no utilizado.
*/
public static void main(String[] args) {
JFrame frame = new JFrame("JRadioButtonDemo");
frame.setContentPane(new JRadioButtonDemo());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
// Ajusta el tamao de la ventana
frame.setVisible(true);
}
/**
* Crea tres componentes {@link JRadioButton}.
*/
public JRadioButtonDemo() {
setLayout(new GridLayout(1, 3));
setBackground(Color.white);
// Crea los
buttonOne =
buttonTwo =
buttonThree

botones de radio
new JRadioButton("One", true);
new JRadioButton("Two");
= new JRadioButton("Three");

// Agrupa los botones de radio


ButtonGroup group = new ButtonGroup();
group.add(buttonOne);
group.add(buttonTwo);
group.add(buttonThree);
// Cambia los colores de los botones de radio
buttonOne.setBackground(Color.white);
buttonTwo.setBackground(Color.white);
buttonThree.setBackground(Color.white);
// Aade botones de radio al contenedor
add(buttonOne);
add(buttonTwo);
add(buttonThree);
}

Listado 3 JRadioButtonDemo.java
La siguiente ventana es desplegada al ejecutar JRadioButtonDemo:

Figura 3 Ejecucin de JRadioButtonDemo


Observa los siguientes aspectos del cdigo:

En la lnea 41, el constructor JRadioButton(String text, boolean selected)


recibe una cadena con el texto del botn y un valor booleano indicando que el botn
debe ser seleccionado.

En las lneas 46 a 49, los componentes JRadioButton son aadidos al objeto


ButtonGroup. Slo un botn de radio de un grupo de botones puede ser
seleccionado a la vez.

En las lneas 52 a 54, el mtodo setBackground modifica el color de fondo de los


botones de radio.

Los dems mtodos de JRadioButton incluyen:

void setText(String). Modifica el texto del componente.


String getText(). Obtiene el texto del componente.
void setFont(Font). Modifica el tipo de letra del componente.

void setSelected(boolean b).

Modifica el estado del botn. El valor true


cambia el estado a seleccionado, mientras que el valor false cambia el estado a no
seleccionado.

boolean isSelected().

Obtiene el estado del botn.

Componente JTextField
Los componentes de la clase JTextField permiten al usuario introducir (o editar) una
pequea cantidad de texto. Estos componentes son utilizados tambin para desplegar
pequeas cantidades de texto. La clase JTextFieldDemo crea una ventana con todos
componentes JLabel y componentes JTextField:
1:
2:
3:
4:
5:
6:
7:
8:
9:

import java.awt.*;
import javax.swing.*;
/**
* Demuestra el componente {@link JTextField}. Esta clase hereda de
* la clase {@link JPanel}.
*
* @author
* @version 1.0.0

10: */
11: public class JTextFieldDemo extends JPanel {
12:
13:
private JLabel labelCountry;
14:
private JLabel labelCapital;
15:
private JTextField textFieldCountry;
16:
private JTextField textFieldCapital;
17:
18:
/**
19:
* Crea una ventana.
20:
*
21:
* @param args no utilizado.
22:
*/
23:
public static void main(String[] args) {
24:
25:
JFrame frame = new JFrame("JTextFieldDemo");
26:
27:
frame.setContentPane(new JTextFieldDemo());
28:
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
29:
frame.pack();
// Ajusta el tamao de la ventana
30:
frame.setVisible(true);
31:
}
32:
33:
/**
34:
* Crea dos componentes {@link JLabel} y dos componentes
35:
* {@link JTextField}.
36:
*/
37:
public JTextFieldDemo() {
38:
39:
setLayout(new GridLayout(2, 1));
40:
setBackground(Color.white);
41:
42:
// Crea los componentes
43:
labelCountry = new JLabel("Country:");
44:
textFieldCountry = new JTextField("Spain", 10);
45:
labelCapital = new JLabel("Capital:");
46:
textFieldCapital = new JTextField("Madrid", 10);
47:
48:
// Cambia los colores de los campos de texto
49:
textFieldCapital.setBackground(new Color(150, 0, 0));
50:
textFieldCapital.setForeground(Color.white);
51:
52:
// Define la alineacin del texto
53:
textFieldCapital.setHorizontalAlignment(JTextField.CENTER);
54:
55:
// Hace que el rea de texto sea no editable
56:
textFieldCapital.setEditable(false);
57:
58:
// Aade componentes al contenedor.
59:
JPanel panelCountry = new JPanel();
60:
61:
panelCountry.setBackground(Color.white);
62:
panelCountry.add(labelCountry);
63:
panelCountry.add(textFieldCountry);
64:
add(panelCountry);
65:
66:
JPanel panelCapital = new JPanel();

67:
68:
69:
70:
71:
72:
73: }

panelCapital.setBackground(Color.white);
panelCapital.add(labelCapital);
panelCapital.add(textFieldCapital);
add(panelCapital);
}

Listado 4 JTextFieldDemo.java
La siguiente ventana es desplegada cuando se ejecuta JTextFieldDemo:

Figura 4 Ejecucin de JTextFieldDemo


Observa los siguientes aspectos del cdigo:

En las lneas 44 y 46, el constructor JTextField(String text, int columns)


crea un campo de texto de diez columnas de ancho, que contiene una cadena de
caracteres. La clase JTextField tambin contiene el constructor JTextField(int
columns), que crea un campo de texto vaco.

En las lneas 49 y 50, los mtodos setBackground y setForeground modifican el


color del fondo y el color del texto.

En la lnea 56, el mtodo setEditable hace que el campo de texto no sea editable.

En las lneas 59 a 71, se crean dos paneles. Se aade una etiqueta y un campo de
texto a cada panel y despus los paneles son agregados al marco. Date cuenta que el
diseo predeterminado de un panel es diseo de flujo. En diseo de flujo, cada
componente asume su tamao preferido.

Los dems mtodos de JTextField incluyen:

void setText(String). Modifica el texto del componente.


String getText(). Obtiene el texto del componente.
void setFont(Font). Modifica la fuente del componente.

Componente JTextArea
Los componentes de la clase JTextArea permiten al usuario introducir (o editar) mltiples
lneas de texto. Estos componentes se utilizan tambin para desplegar bloques de texto. Un
componente JTextArea no tiene barras de desplazamiento. Si se requieren barras de

desplazamiento, el JTextArea es envuelto en un JScrollPane, el cual provee las barras de


desplazamiento. La clase JTextAreaDemo crea una ventana con dos componentes
JTextArea:
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:

import java.awt.*;
import javax.swing.*;
/**
* Demuestra el componente {@link JTextArea}. Esta clase hereda de
* la clase {@link JPanel}.
*
* @author
* @version 1.0.0
*/
public class JTextAreaDemo extends JPanel {
private JTextArea textAreaOne;
private JTextArea textAreaTwo;
/**
* Crea una ventana.
*
* @param args no utilizado.
*/
public static void main(String[] args) {
JFrame frame = new JFrame("JTextAreaDemo");
frame.setContentPane(new JTextAreaDemo());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
// Ajusta el tamao de la ventana
frame.setVisible(true);
}
/**
* Crea dos componentes {@link JTextArea}.
*/
public JTextAreaDemo() {
setBackground(Color.white);
String text = "Line1\nLine2\nLine3\nLine4\nLine5\n"
+ "Line6\nLine7\nLine8\nLine9\nLine10\n";
// Crea los componentes
textAreaOne = new JTextArea(text, 7, 10);
textAreaTwo = new JTextArea(text, 7, 10);
// Cambia los colores de los componentes
textAreaOne.setBackground(new Color(0, 0, 150));
textAreaTwo.setBackground(new Color(0, 150, 0));
textAreaOne.setForeground(Color.white);
textAreaTwo.setForeground(Color.white);
// Hace que el rea de texto no sea editable
textAreaTwo.setEditable(false);

53:
54:
// Aade componentes de rea de texto al contenedor de la
55: barra de desplazamiento.
56:
add(new JScrollPane(textAreaOne,
57:
JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED,
58:
JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED));
59:
add(new JScrollPane(textAreaTwo,
60:
JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,
61:
JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS));
62:
}
}

Listado 5 JTextAreaDemo.java
La siguiente ventana es desplegada cuando se ejecuta JTextAreaDemo:

Figura 5 Ejecucin de JTextAreaDemo


Observa los siguientes aspectos del cdigo:

En las lneas 42 y 43, el constructor JTextArea(String text, int rows, int


columns)crea un rea de texto de 7 por 10 que contiene una cadena de caracteres.

En las lneas 46 a 49, los mtodos setBackground y setForeground modifican el


color del fondo y el color del texto.

En la lnea 52, el mtodo setEditable hace que el rea de texto no sea editable.

En las lneas 55 a 60, cada rea de texto es aadida a un panel de desplazamiento,


mismos
que
despus
son
aadidos
al
marco.
El
constructor
JScrollPane(Component view, int vsbPolicy, int hsbPolicy) crea un
panel que despliega el rea de texto. El segundo y el tercer parmetro del
constructor indican si se necesitan barras de desplazamiento horizontales y
verticales:

VERTICAL_SCROLLBAR_AS_NEEDED

La barra de desplazamiento
vertical debe aparecer slo si
el texto no cabe
verticalmente.

La barra de desplazamiento
horizontal debe aparecer slo
HORIZONTAL_SCROLLBAR_AS_NEEDED
si el texto no cabe
horizontalmente.
VERTICAL_SCROLLBAR_ALWAYS

Debe aparecer la barra de


desplazamiento vertical.

HORIZONTAL_SCROLLBAR_ALWAYS

Debe aparecer la barra de


desplazamiento horizontal.

VERTICAL_SCROLLBAR_NEVER

No debe aparecer la barra de


desplazamiento vertical.

HORIZONTAL_SCROLLBAR_NEVER

No debe aparecer la barra de


desplazamiento horizontal.

Los dems mtodos de JTextArea incluyen:

void setText(String). Modifica el texto del componente.


void append(String). Aade la cadena de caracteres al final
String getText(). Obtiene el texto del componente.
void setFont(Font). Modifica la fuente del componente.

del texto.

Componente JList
Los componentes de la clase JList permiten al usuario seleccionar uno o ms elementos de
una lista. Un componente JList no debe tener barras de desplazamiento . Si se requieren
barras de desplazamiento, JList es envuelta por JScrollPane, misma que proporciona las
barras de desplazamiento. La clase JListDemo crea una ventana con dos componentes
JList:
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:

import java.awt.*;
import javax.swing.*;
/**
* Demuestra el componente {@link JList}. Esta clase hereda de
* la clase {@link JPanel}.
*
* @author
* @version 1.0.0
*/
public class JListDemo extends JPanel {
private JList listOne;
private JList listTwo;
private static final String fruitNames[] =
{"Orange", "Pear", "Apple", "Pineapple", "Peach",
"Grapefruit", "Lemon", "Grape"};
/**
* Crea una ventana.

22:
*
23:
* @param args no utilizado.
24:
*/
25:
public static void main(String[] args) {
26:
27:
JFrame frame = new JFrame("JListDemo");
28:
29:
frame.setContentPane(new JListDemo());
30:
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
31:
frame.pack();
// Ajusta el tamao de la ventana
32:
frame.setVisible(true);
33:
}
34:
35:
/**
36:
* Crea dos componentes {@link JList}.
37:
*/
38:
public JListDemo() {
39:
40:
setBackground(Color.white);
41:
42:
// Crea los componentes
43:
listOne = new JList(fruitNames);
44:
listTwo = new JList(fruitNames);
45:
46:
// Personaliza las propiedades de la lista
47:
listOne.setVisibleRowCount(5);
48:
listTwo.setVisibleRowCount(5);
49:
listOne.setSelectionMode(
50:
ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
51:
listTwo.setSelectionMode(
52:
ListSelectionModel.SINGLE_SELECTION);
53:
listOne.setFixedCellHeight(15);
54:
listOne.setFixedCellWidth(100);
55:
listTwo.setFixedCellHeight(15);
56:
listTwo.setFixedCellWidth(100);
57:
58:
// Cambia los colores de las listas
59:
listOne.setBackground(new Color(0, 0, 150));
60:
listTwo.setBackground(new Color(0, 150, 0));
61:
listOne.setForeground(Color.white);
62:
listTwo.setForeground(Color.white);
63:
64:
// Aade listas a los contenedores de las barras de
65: desplazamiento
66:
add(new JScrollPane(listOne,
67:
JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED,
68:
JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED));
69:
add(new JScrollPane(listTwo,
70:
JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,
71:
JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS));
72:
}
}

Listado 6 JListDemo.java
La siguiente ventana es desplegada cuando se ejecuta JListDemo:

Figura 6 Ejecucin de JListDemo


Observa los siguientes aspectos del cdigo:

En las lneas 43 y 44, un constructor JList crea una lista que despliega los
elementos del arreglo especificado. La clase JList tambin proporciona un
constructor de un argumento que toma un arreglo como parmetro de entrada.

En las lneas 47 y 48, el mtodo setVisibleRowCount indica el nmero de


elementos en JList que sern visibles en cualquier momento.

En las lneas 49 y 51, el mtodo setSelectionMode indica qu tipo de seleccin


del elemento ser provista por el usuario:

SINGLE_SELECTION

Slo puede seleccionarse un


elemento a la vez.

SINGLE_INTERVAL_SELECTION

Puede seleccionarse un intervalo


contiguo de elementos a la vez.

MULTIPLE_INTERVAL_SELECTION

Pueden seleccionarse mltiples


intervalos de elementos a la vez.

En las lneas 53 a 56, los mtodos setFixedCellHeight y setFixedCellWidth


definen el ancho y la altura de los elementos.

En las lneas 59 a 62, los mtodos setBackground y setForeground modifican el


color del fondo y el color del fondo.

En las lneas 65 a 70, cada lista es aadida a un panel de desplazamiento, mismas


que despus son aadidas al marco. El constructor JScrollPane(Component
view, int vsbPolicy, int hsbPolicy) crea un panel que despliega la lista. El
segundo y el tercer parmetro del constructor indican si se requieren barras de
desplazamiento horizontales y verticales:

VERTICAL_SCROLLBAR_AS_NEEDED

Debe aparecer la barra de


desplazamiento vertical slo
si el texto no cabe
verticalmente.

Debe aparecer la barra de


desplazamiento horizontal
HORIZONTAL_SCROLLBAR_AS_NEEDED
slo si el texto no cabe
horizontalmente.
VERTICAL_SCROLLBAR_ALWAYS

Debe aparecer la barra de


desplazamiento vertical.

HORIZONTAL_SCROLLBAR_ALWAYS

Debe aparecer la barra de


desplazamiento horizontal.

VERTICAL_SCROLLBAR_NEVER

No debe aparecer la barra de


desplazamiento vertical

HORIZONTAL_SCROLLBAR_NEVER

No debe aparecer la barra de


desplazamiento horizontal.

Los dems mtodos de JList incluyen:

Object getSelectedValue(). Obtiene el elemento


Object[] getSelectedValues(). Obtiene un

seleccionado.
arreglo de los elementos

seleccionados.

int getSelectedIndex(). Obtiene el ndice del elemento seleccionado.


int[] getSelectedIndices(). Obtiene un arreglo con los ndices

de los

elementos seleccionados.

void clearSelection(). Borra la seleccin del usuario.


boolean isSelectedIndex(int index). Revisa si el

ndice especificado est seleccionado.


boolean isSelectionEmpty(). Regresa true
seleccionado.

elemento que est en el

si ningn elemento est

3.2.2 Manejo de Eventos Swing

Clase ButtonEventsDemo
Clase FruitListDemo
Lecturas:

Requerida:
o Barker, primera edicin, captulo 16 (pginas 52244).
o Barker, segunda edicin, captulo 16 (pginas 735
61).
Secuencia: Lee el libro de texto antes de leer esta pgina.

Esta pgina presenta dos aplicaciones simples que demuestran el manejo de eventos. Estas
aplicaciones tambin muestran cmo deben utilizarse los siguientes componentes:

JLabel
JRadioButton
JTextArea
JList
JButton

Clase ButtonEventsDemo
La clase ButtonEventsDemo contiene tres componentes JRadioButton y un componente
JLabel. Cuando un usuario hace clic en uno de los botones de radio, el texto de la etiqueta
se actualiza. Slo puede seleccionarse un botn de radio a la vez, porque los botones de
radio estn agrupados.
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:

import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
/**
* Demuestra el manejo de eventos para los botones de radio. Esta
clase hereda de
* la clase {@link JPanel}.
*
* @author
* @version 1.0.0
*/
public class ButtonEventsDemo extends JPanel {
private
private
private
private

JRadioButton buttonOne;
JRadioButton buttonTwo;
JRadioButton buttonThree;
JLabel label;

19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:

/**
* Crea una ventana.
*
* @param args no utilizado.
*/
public static void main(String[] args) {
JFrame frame = new JFrame("ButtonEventsDemo");
frame.setContentPane(new ButtonEventsDemo());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(200, 200);
frame.setVisible(true);
}
/**
* Crea los componentes.
*/
public ButtonEventsDemo() {
setBackground(Color.white);
// Crea los componentes
buttonOne = new JRadioButton("One", true);
buttonTwo = new JRadioButton("Two");
buttonThree = new JRadioButton("Three");
label = new JLabel(buttonOne.getText());
label.setFont(new Font("Serif", Font.BOLD, 42));
label.setHorizontalAlignment(JLabel.CENTER);
// Agrupa los botones de radio
ButtonGroup group = new ButtonGroup();
group.add(buttonOne);
group.add(buttonTwo);
group.add(buttonThree);
// Cambia los colores de los botones
buttonOne.setBackground(Color.white);
buttonTwo.setBackground(Color.white);
buttonThree.setBackground(Color.white);
// Registra los oyentes (listeners) de los botones de radio.
buttonOne.addActionListener(new ListenerOne());
buttonTwo.addActionListener(new ListenerTwo());
buttonThree.addActionListener(new ListenerThree());
// Agrega botones de radio a un panel
JPanel panel = new JPanel();
panel.setLayout(new GridLayout(3, 1));
panel.add(buttonOne);
panel.add(buttonTwo);
panel.add(buttonThree);
// Crea el diseo
setLayout(new BorderLayout());
add(panel, BorderLayout.WEST);

76:
77:
78:
79:
80:
81:
82:
83:
84:
85:
86:
87:
88:
89:
90:
91:
92:
93:
94:
95:
96:
97:
98:
99:
100: de
101:
102:
103:
104:
105:
106:
107:
108:
109:
110:
111:
112:
113:
114:
115:
116:
117:
118:
119:
120:
121:
122:
123:
124:
125:
126:
127:
128:
129:
130:

add(label, BorderLayout.CENTER);
panel.setBorder(BorderFactory.createEtchedBorder());
label.setBorder(BorderFactory.createLoweredBevelBorder());
}
/**
* Esta clase interna maneja eventos asociados con el botn de
* radio "One".
*/
class ListenerOne implements ActionListener {
/**
* Cambia el texto de la etiqueta.
*
* @param event el objeto del evento.
*/
public void actionPerformed(ActionEvent event) {
label.setText(buttonOne.getText());
}
}
/**
* Esta clase interna maneja los eventos asociados con el botn
* radio "Two".
*/
class ListenerTwo implements ActionListener {
/**
* Cambia el texto de la etiqueta.
*
* @param event el objeto del evento.
*/
public void actionPerformed(ActionEvent event) {
label.setText(buttonTwo.getText());
}
}
/**
* Esta clase interna maneja los eventos del botn de
* radio "Three".
*/
class ListenerThree implements ActionListener {
/**
* Cambia el texto de la etiqueta.
*
* @param event el objeto del evento.
*/
public void actionPerformed(ActionEvent event) {
label.setText(buttonThree.getText());
}
}

Listado 1 ButtonEventsDemo.java
La siguiente ventana es desplegada al ejecutar ButtonEventsDemo:

Figura 1 Ejecucin de ButtonEventsDemo


En esta aplicacin, el cdigo que maneja los clic del botn de radio est separado en tres
clases internas con nombre (named inner classes). Cada clase interna implementa la
interfaz ActionListener y de este modo, cada clase interna tiene un mtodo llamado
actionPerformed que responde al clic en un botn de radio.
Observa los siguientes aspectos del cdigo:

En las lneas 61 a 63, el mtodo addActionListener registra los oyentes (listeners)


para los botones de radio.
La clase interna ListenerOne, definida en las lneas 84 a 95, maneja los eventos
asociados con buttonOne.
La clase interna ListenerTwo, definida en las lneas 101 a 112, maneja los eventos
asociados con buttonTwo.
La clase interna ListenerThree, definida en las lneas 118 a 129, maneja los
eventos asociados con buttonThree.

Clase FruitListDemo
La clase FruitListDemo utiliza tres componentes: un componente JList, uno JTextArea
y uno JButton. El componente JList contiene una lista de frutas y el rea de texto
JTextArea est vaca inicialmente. El usuario puede mover una fruta de la lista al rea de
texto. Cuando el usuario selecciona una fruta, la aplicacin elimina la fruta seleccionada de
la lista y la aade al final del rea de texto. Cuando el usuario hace clic en el botn, la
aplicacin restaura la lista de frutas original y limpia el rea de texto.
1:
2:
3:
4:

import
import
import
import

java.awt.*;
java.awt.event.*;
javax.swing.*;
javax.swing.event.*;

5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:

import java.util.*;
/**
* Demuestra el manejo de eventos para las listas y botones. Esta
clase
* hereda de la clase {@link JPanel}.
*
* @author
* @version 1.0.0
*/
public class FruitListDemo extends JPanel {
private JList fruitList;
private JButton resetButton;
private JTextArea resultTextArea;
private ArrayList<String> fruitArrayList;
/**
* Crea una ventana.
*
*@param args no utilizado.
*/
public static void main(String[] args) {
JFrame frame = new JFrame("FruitListDemo");
frame.setContentPane(new FruitListDemo());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(200, 290);
frame.setVisible(true);
}
/**
* Crea una Interfaz Grfica del Usuario (GUI).
*/
public FruitListDemo() {
setBackground(Color.white);
setupFruitArrayList();
// Crea los componentes
fruitList = new JList(fruitArrayList.toArray());
resultTextArea = new JTextArea(6, 15);
resetButton = new JButton("Reset Fruit List");
// Personaliza las propiedades del componente
fruitList.setVisibleRowCount(8);
fruitList.setSelectionMode(
ListSelectionModel.SINGLE_SELECTION);
fruitList.setFixedCellHeight(15);
fruitList.setFixedCellWidth(100);
resultTextArea.setEditable(false);
// Registra el oyente (listener) del componente de la lista

62:
fruitList.addListSelectionListener(new FruitListListener());
63:
64:
// Registra el oyente (listener) para el componente de un
65: botn
66:
resetButton.addActionListener(new ResetButtonListener());
67:
68:
// Aade componentes al contenedor
69:
JPanel listPanel = new JPanel();
70:
listPanel.setBackground(Color.white);
71:
listPanel.add(
72:
new JScrollPane(fruitList,
73:
JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,
74:
JScrollPane.HORIZONTAL_SCROLLBAR_NEVER));
75:
76:
JPanel textAreaPanel = new JPanel();
77:
textAreaPanel.setBackground(Color.white);
78:
textAreaPanel.add(
79:
new JScrollPane(resultTextArea,
80:
JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,
81:
JScrollPane.HORIZONTAL_SCROLLBAR_NEVER));
82:
83:
setLayout(new BorderLayout());
84:
add(listPanel, BorderLayout.NORTH);
85:
add(resetButton, BorderLayout.CENTER);
86:
add(textAreaPanel, BorderLayout.SOUTH);
87:
}
88:
89:
/*
90:
* Inicializa la coleccin fruitArrayList.
91:
*/
92:
private void setupFruitArrayList() {
93:
94:
fruitArrayList = new ArrayList<String>();
95:
96:
fruitArrayList.add("Orange");
97:
fruitArrayList.add("Pear");
98:
fruitArrayList.add("Apple");
99:
fruitArrayList.add("Pineapple");
100:
fruitArrayList.add("Peach");
101:
fruitArrayList.add("Grapefruit");
102:
fruitArrayList.add("Lemon");
103:
fruitArrayList.add("Grape");
104:
fruitArrayList.add("Banana");
105:
fruitArrayList.add("Tangerine");
106:
}
107:
108:
/**
109:
* Esta clase interna maneja los eventos de la seleccin de la
110: lista.
111:
*/
112:
class FruitListListener implements ListSelectionListener {
113:
114:
/**
115:
* Mueve el elemento seleccionado de la lista al rea de
116: texto.
117:
*
118:
* @param event el objeto del evento.

119:
120:
121:
122:
123:
124:
125:
126:
127:
128:
129:
130:
131:
132:
133:
134:
135:
136:
137:
138:
139:
140:
141:
142:
143:
144:
145:
146:

*/
public void valueChanged(ListSelectionEvent event) {
int index = fruitList.getSelectedIndex();
if (! fruitList.getValueIsAdjusting() && index != -1) {
resultTextArea.append(fruitList.getSelectedValue()
+ "\n");
fruitArrayList.remove(index);
fruitList.setListData(fruitArrayList.toArray());
}
}
}
/**
* Esta clase interna maneja los eventos de los botones.
*/
class ResetButtonListener implements ActionListener {
/**
* Restaura la lista a su estado original.
*
* @param event el objeto del evento.
*/
public void actionPerformed(ActionEvent event) {
setupFruitArrayList();
fruitList.setListData(fruitArrayList.toArray());
resultTextArea.setText("");
}
}
}

Listado 2 FruitListDemo.java
La siguiente ventana es desplegada despus que el usuario ha eliminado "Pineapple" (Pia)
y "Grapefruit" (Toronja) de la lista:

Figura 2 Ejecucin de FruitListDemo


El cdigo que maneja el clic del botn est contenido en la clase interna con nombre
ButtonListener. ButtonListener implementa la interfaz ActionListener y define un
mtodo actionPerformed que responde al clic de un botn.
El cdigo que maneja la seleccin de la lista est contenido en la clase interna con nombre
FruitListListener
implementa
la
interfaz
y defina un mtodo valueChanged que responde a la seleccin
de una lista. En esta aplicacin, se generan muchos eventos de seleccin de lista cuando un
usuario selecciona un elemento de la lista: uno cuando el usuario presiona el ratn, una
cada vez que el usuario arrastra el ratn y selecciona otro elemento de la lista y otro cuando
el usuario libera el ratn. El mtodo getValueIsAdjusting se utiliza para distinguir los
eventos: regresa true cuando el ratn es presionado o arrastrado, false cuando el ratn es
liberado. Cuando el usuario ha terminado de hacer una seleccin, es decir, cuando
getValueIsAdjusting regresa false, el mtodo valueChanged mueve la fruta
seleccionada de la lista al rea de texto.
FruitListListener.
ListSelectionListener

Observa los siguientes aspectos del cdigo:

En la lnea 47, un constructor JList crea una lista que despliega los elementos de la
coleccin fruitArrayList.
En la lnea 61, el mtodo addListSelectionListener registra el oyente (listener)
de la lista.
En la lnea 64, el mtodo addActionListener registra el oyente (listener) del
botn.
La clase interna FruitListListener, definida en las lneas 109 a 127, maneja los
eventos asociados con la lista:
o En la lnea 118, el mtodo JList.getSelectedIndex obtiene el ndice de la
fruta que ha seleccionado el usuario.

En la lnea 120, el estatuto if revisa si el usuario ha terminado de seleccionar


una fruta de la lista.
o En la lnea 121, el mtodo JList.getSelectedValue obtiene el nombre de
la fruta seleccionada y el mtodo TextArea.append aade el nombre al
final del rea de texto.
o En la lnea 123, el mtodo ArrayList.remove elimina la fruta seleccionada
de la coleccin fruitArrayList.
o En la lnea 124, el mtodo JList.setListData actualiza la lista con los
datos la coleccin fruitArrayList, que ahora contiene una fruta menos.
La clase internaResetButtonListener, definida en las lneas 132 a 146, maneja los
eventos asociados con el botn:
o En la lnea 141, el mtodo setupFruitArrayList restaura la coleccin
fruitArrayList a su estado original.
o En la lnea 142, el mtodo JList.setListData actualiza la lista con los
datos de la coleccin fruitArrayList, que ahora contiene diez frutas.
o En la lnea 143, el mtodo JTextArea.setText elimina todo el texto del
rea de texto.
o

3.2.3 Clase JFileChooser


Lecturas:

Requerida:
o Barker, primera edicin, captulo 16 (pginas 545
52).
o Barker, segunda edicin, captulo 16 (pginas 761
69).
Secuencia: Lee el libro de texto antes de leer esta pgina.

Esta pgina presenta una aplicacin que utiliza un seleccionador de archivos, un cuadro de
dilogo que permite al usuario examinar el sistema de archivos y seleccionar un archivo (o
directorio) de una lista o introducir el nombre de un archivo (o directorio). El API Swing
provee esta funcionalidad en la clase JFileChooser. El cuadro de dilogo creado por
JFileChooser es modal. Cuando una aplicacin abre un cuadro de dilogo modal, el resto
de la aplicacin deja de responder al usuario, por lo que el usuario est forzado a responder
al cuadro de dilogo. Un JFileChooser puede crear un cuadro de dilogo para abrir un
archivo as como para guardar un archivo: el cuadro de dilogo para abrir un archivo
permite al usuario localizar un archivo, mientras que el cuadro de dilogo para guardar,
permite al usuario especificar el directorio donde ser guardado el archivo y el nombre del
archivo guardado.

Figura 1 Un seleccionador de archivos

La clase TextEditor permite a un usuario abrir un archivo de texto y guardar el archivo


modificado. Para abrir un archivo, el usuario da un clic en el botn Open (abrir), que arroja
un seleccionador de archivos para abrir un archivo. Cuando el usuario selecciona un
archivo, el seleccionador de archivos se cierra y la aplicacin despliega los contenidos del
archivo en el rea de texto. El usuario puede editar el texto en el rea de texto: aadir
lneas, borrar lneas, cambiar palabras, etc. Para guardar los cambios, el usuario da un clic
en el botn Save (guardar), mismo que arroja otro seleccionador de archivos, esta vez para
guardar un archivo. Cuando el usuario especifica un directorio y un nombre, el
seleccionador se cierra y la aplicacin crea un nuevo archivo que contiene el texto del rea
de texto.
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:

import
import
import
import

java.awt.*;
java.awt.event.*;
javax.swing.*;
java.io.*;

/**
* Demuestra la clase {@link JFileChooser}. Esta clase hereda de
* la clase {@link @JPanel}.
*
* @author
* @version 1.0.0
*/
public class TextEditor extends JPanel {
/* Separador de lnea */
private final static String NEW_LINE =
System.getProperty("line.separator");
/* Flujo de error estndar */
private static PrintWriter stdErr =
new PrintWriter(System.err, true);

private JButton openButton;


private JButton saveButton;
private TextArea textArea;
private JFileChooser

fileChooser;

/**
* Crea una ventana.
*
* @param args no utilizado.
*/
public static void main(String[] args) {
JFrame frame = new JFrame("TextEditor");
frame.setContentPane(new TextEditor());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(400,400);
frame.setVisible(true);
}

44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:
80:
81:
82:
83:
84:
85:
86:
87:
88:
89:
90:
91:
92:
93:
94:
95:
96:
97:
98:
99:
100:

/**
* Crea una Interfaz Grfica del Usuario.
*/
public TextEditor() {
setBackground(Color.white);
// Crea los componentes
openButton = new JButton("Open");
saveButton = new JButton("Save");
textArea = new TextArea();
fileChooser = new JFileChooser();
fileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
// Registra los escuchadores de los botones
openButton.addActionListener(new OpenButtonListener());
saveButton.addActionListener(new SaveButtonListener());
// Agrega componentes al contenedor
setLayout(new BorderLayout());
add(openButton, BorderLayout.NORTH);
add(textArea, BorderLayout.CENTER);
add(saveButton, BorderLayout.SOUTH);
}
/**
* Esta clase interna maneja los clics del botn del botn Open.
*/
class OpenButtonListener implements ActionListener {
/**
* Abre un archivo de texto.
*
* @param event el objeto del evento.
*/
public void actionPerformed(ActionEvent event)

int result = fileChooser.showOpenDialog(null);


if (result == JFileChooser.APPROVE_OPTION) {
try {
File file = fileChooser.getSelectedFile();
BufferedReader input =
new BufferedReader(new FileReader(file));
String

line = input.readLine();

while (line != null) {


textArea.append(line + NEW_LINE);
line = input.readLine();
}
input.close();
} catch (IOException ioe) {

101:
stdErr.println(ioe.toString());
102:
}
103:
}
104:
}
105:
}
106:
107:
/**
108:
* Esta clase intenna maneja los clics del botn para el botn
109: Save.
110:
*/
111:
class SaveButtonListener implements ActionListener {
112:
113:
/**
114:
* Guarda un archivo de texto.
115:
*
116:
* @param event el objeto del evento.
117:
*/
118:
public void actionPerformed(ActionEvent event) {
119:
120:
int result = fileChooser.showSaveDialog(null);
121:
122:
if (result == JFileChooser.APPROVE_OPTION) {
123:
124:
try {
125:
126:
File file = fileChooser.getSelectedFile();
127:
PrintWriter output =
128:
new PrintWriter(new FileWriter(file));
129:
130:
output.print(textArea.getText());
131:
output.close();
132:
} catch (IOException ioe) {
133:
stdErr.println(ioe.toString());
134:
}
135:
}
136:
}
137:
}
}

Listado 1 TextEditor.java
La siguiente figura muestra el seleccionador de archivos para guardar los contenidos del
rea de texto:

Figura 2 Ejecucin de TextEditor


Observa los siguientes aspectos del cdigo:

En la lnea 57, el constructor JFileChooser crea una instancia de JFileChooser


que presentar los contenidos del directorio predeterminado del usuario cuando se
abra un cuadro de dilogo.

En la lnea 58, el mtodo setFileSelectionMode modifica el seleccionador de


archivos, de modo que el usuario solo pueda seleccionar archivos.

En la lnea 83, el mtodo showOpenDialog abre un seleccionador de archivos para


abrir un archivo. El argumento null indica que el cuadro de dilogo debe ser
desplegado en el centro de la ventana. (Si el argumento pasado a este mtodo es un
componente, el cuadro de dilogo est centrado sobre el componente especificado).
El mtodo showOpenDialog regresa los siguientes valores:

o
o
o

si el usuario da un clic en el botn Cancel


(cancelar) o en el botn Close (cerrar)
JFileChooser.APPROVE_OPTION si el usuario selecciona un archivo y hace
clic en el botn Open (abrir)
JFileChooser.ERROR_OPTION si ocurre un error
JFileChooser.CANCEL_OPTION

En la lnea 119, el mtodo showSaveDialog abre un seleccionador de archivos para


guardar un archivo. De nuevo, el argumento null indica que el cuadro de dilogo
debe ser desplegado en el centro de la ventana.
El mtodo showSaveDialog regresa los siguientes valores:
o
o
o

si el usuario hace clic en el botn Cancel


(cancelar) o en el botn Close (cerrar)
JFileChooser.APPROVE_OPTION si el usuario especifica un nombre y hace
clic en el botn Save (guardar)
JFileChooser.ERROR_OPTION si ocurre un error
JFileChooser.CANCEL_OPTION

En las lneas 89 y 125, el mtodo getSelectedFile regresa un objeto File con la


descripcin del archivo especificado. El constructor FileReader que toma un
objeto File es utilizado en la lnea 91 para abrir el archivo (si el archivo no existe,
ser creado).

En las lneas 89 a 99, la aplicacin crea un BufferedReader, lee el archivo


especificado y despliega los contenidos del archivo en el rea de texto.

En las lneas 125 a 130, la aplicacin crea un PrintWriter y escribe los contenidos
del rea de texto a un archivo con el nombre especificado.

3.3 Hacia el Uso Comercial

3.3.1 Para Continuar Estudiando Java

3.3.1 Para Continuar Estudiando Java

Otros API de Java


Informacin sobre Java
Informacin sobre UML
Informacin sobre Patrones de Diseo

Otros API de Java


Java tiene muchos API, adems de los que hemos visto hasta ahora. Aqu te presentamos
algunos de ellos:
Java 2D. El API para grficos en dos dimensiones "permite a los programadores
producir elementos visuales tipo jaw-dropping".
Java Sound. Este API te proporciona soporte para reproduccin y grabacin de
audio.
JDBC. El API para la Conectividad de Bases de Datos en Java (Java Database
Connectivity) permite que las aplicaciones de Java interacten con bases de datos
relacionales. Si ests familiarizado con bases de datos y deseas aprender ms, revisa
el tutorial de Sun JDBC Basics.
Java Games. Este API brinda soporte para el desarrollo de juegos en lnea simples.

Informacin sobre Java


Comenzamos este curso diciendo que Java ha estado cambiando rpidamente y que la
mejor manera de mantenerse al da es leer el sitio Web de Sun sobre Tecnologa de Java.
Concluimos este curso enfatizando una vez ms que este sitio Web contiene informacin
invaluable. Debido a que ahora ests familiarizado con la lectura de la Especificacin del
API de Java, debes ser capaz de manejar la mayora de los cambios y mejoras. Adems de
leer el API, a continuacin te presentamos varias formas en las que puedes aprender ms y
mantenerte al da:

Documentacin de Sun
o Glosario de Trminos Relacionados con Java
o Tutorial de Java
o FAQs. Para encontrar respuestas a las preguntas ms frecuentes.
o Especificacin del Lenguaje Java
Servicios del Desarrollador de Sun. Registrarse para una membresa gratuita.
o Foros de Discusin. Un tablero de noticias interactivo para compartir
conocimiento y preguntas sobre tecnologas de Java y tcnicas de
programacin.
o Sesiones de Chat. Ingenieros de Sun y otras personas con acceso a
informacin del software de Java comparten su conocimiento y perspectivas
sobre los ltimos eventos de la tecnologa de Java en estos chats en lnea.
o Grupos de Usuarios de Java. Un JUG (Java User Group) es un grupo de
personas que comparten un inters comn en la tecnologa de Java y que se
encuentran regularmente para compartir ideas tcnicas e informacin. La

mayora de los JUGs cuentan con listas de correo electrnico donde los
miembros pueden publicar preguntas.
Consejos sobre las Tecnologas Centrales de Java. Un boletn de noticias
mensual que contiene consejos, tcnicos y cdigo ejemplo sobre varios
temas de inters.

Por ltimo, presentamos una lista de algunos libros que podras encontrar interesantes:

Effective Java Programming Language Guide [Gua Efectiva sobre el Lenguaje de


Programacin Java], de Joshua Bloch
Core Java 2, Volume 1: Fundamentals [Java Central 2: Volumen 1: Aspectos
Bsicos](5ta Edicin) de Gary Cornell, Cay Horstmann, and Cay Forstmann
Thinking in Java [Pensando en Java] (3ra Edicin) de Bruce Eckel
Just Java 2 [Simplemente Java 2] (5ta Edicin) de Peter van der Linden
Head First Java [Java Primero en la Cabeza] de Bert Bates, Kathy Sierra
The Elements of Java Style [Los Elementos del Estilo de Java] publicado por
Cambridge University Press

Informacin sobre UML


La notacin de diagramas de clase presentada en este curso representa slo un pequeo
subconjunto de lo que es UML. Como mencionamos en la Unidad 1, el Grupo de
Administracin de Objetos (OMG) gui el desarrollo del estndar UML. Su sitio Web
contiene una lista de tutoriales; sugerimos que comiences con el tutorial de Borland porque
es muy claro y conciso.
Martin Fowler, un prolfico escritor de temas de software, ha escrito una excelente
introduccin a UML: UML Distilled: A Brief Guide to the Standard Object Modeling
Language [UML Sintetizado: Una Gua Breve al Lenguaje de Modelacin de Objetos
Estndar] (2da Edicin).

Informacin sobre Patrones de Diseo


La mayora de los libros sobre patrones de diseo son escritos para una audiencia
profesional y no son adecuados para los principiantes. Los siguientes libros tienen una
naturaleza ms introductoria:

Design Patterns Explained: A New Perspective on Object-Oriented Design


[Explicacin de los Patrones de Diseo: Una Nueva Perspectiva sobre el Diseo
Orientado a Objetos] por Alan Shalloway, James R. Trott
Applying UML and Patterns: An Introduction to Object-Oriented Analysis and
Design and the Unified Process [Aplicando UML y Patrones: Una Introduccin al
Anlisis y Diseo Orientado a Objetos y el Proceso Unificado] (2da Edicin) por
Craig Larman

Apndice A. Glosario
A
Abstract class (Clase abstracta). Una clase que no puede ser instanciada, slo puede ser
una subclase.
Abstract method (Mtodo abstracto). Un mtodo sin implementacin. El mtodo abstracto
debe ser implementado en una subclase.
Aggregation (Agregacin). Una forma especial de asociacin que indica un relacin "es
parte de".
Accesor method (Mtodo de acceso o accesor). Mtodo para obtener el valor de un
atributo.
Association (Asociacin). Relacin entre dos o ms clases.

C
Class diagram (Diagrama de clase). Representacin grfica que muestra la estructura
esttica del modelo, en particular, la estructura interna de las clases e interfaces y sus
relaciones.
Class method (Mtodo de clase). Mtodo asociado con un nombre de clase.
Class variable (Variable de clase). Variable asociada con un nombre de clase. Todas las
instancias comparten la misma copia de las variables de clase.
Collection (Coleccin). Un objeto que contiene un grupo de objetos, conocido como sus
elementos.

G
Generalization/specialization relationship (Relacin de generalizacin/especializacin).
Representa la relacin es-un. La especializacin/generalizacin entre la clase A y B permite
a una clase A ser definida como especializacin de una clase B ms general.

I
Inheritance (Herencia). Mecanismo que permite extender una clase existente.
Instance method (Mtodo de instancia). Mtodo asociado con un objeto.
Instance variable (Variable de instancia). Variable asociada con un objeto. Cada instancia
mantiene una copia de las variables de instancia de la clase.
Integrated development environment (IDE, Ambiente Integrado de Desarrollo).
Herramientas utilizadas por los desarrolladores de sistemas para asistirlos en las diferentes
fases del desarrollo de un sistema. Normalmente, el IDE incluye un navegador de archivos

de proyecto, compiladores, editores de cdigo y depuradores.


Interface (Interfaz). Una interfaz es una coleccin de definiciones de mtodos (sin
implementacin) y valores constantes.

M
Multiplicity (Multiplicidad). Multiplicidad indica el nmero de instancias de la clase que
pueden ser asociadas con una nica instancia de otra clase.
Mutator method (Mtodo modificador o mutator). Mtodo para modificar el valor de un
atributo.

O
Object Management Group (OMG o Grupo de Administracin de Objetos). Organizacin
sin fines de lucro que promueve el uso de tecnologa orientada a objetos.
Open source (Cdigo abierto). Software distribuido bajo una licencia que garantiza el
derecho para leer, redistribuir, modificar y utilizar el software libremente.

P
Polymorphism (Polimorfismo). Caracterstica de una referencia que denota instancias de
muchas clases relacionadas por alguna superclase comn. Esta referencia es capaz de
responder a un conjunto de mensaje comn de diferentes maneras.

S
Specialization/generalization relationship (Relacin de especializacin/generalizacin).
Representa la relacin "es un". La especializacin/generalizacin entre la clase A y B
permite a una clase A ser definida como especializacin de una clase B ms general.
Standard error stream object: System.err (Objeto de flujo de error estndar). Un objeto
que permite a un programa pedir informacin y desplegar mensajes de error en pantalla.
Standard input stream object: System.in (Objeto de flujo de entrada estndar). Un
objeto que permite a un programa introducir datos del teclado.
Standard output stream object: System.out (Objeto de flujo de salida estndar). Un
objeto que permite a un programa desplegar una salida regular en pantalla.

U
Unified Modeling Language (UML o Lenguaje Unificado de Modelacin). Un lenguaje
grfico para especificar, visualizar, construir y documentar sistemas de software.

Apndice D. Lecturas
Libro:

Barker, Jacquie. Beginning Java Objects: From Concepts to Code. Apress.

Lecturas:
Secciones del Curso

Lecturas

1.1.1 Aplicaciones en
Java

Requerida:

1.1.5 Objetos
Excepcin

Requerida:

1.1.6 Convenciones de
Cdigo

Java Software, Sun


Microsystems, Inc, Code
Conventions for the Java
Programming Language.

Requerida:

1.2.1 Diagramas UML


de Clases

Barker, primera edicin, captulo


13 (pginas 3202).
Barker, segunda edicin,
captulo 13 (pginas 473501).

Requerida:

1.1.7 Javadoc

Barker, primera edicin, captulo


1 (pginas 137).
Barker, segunda edicin,
captulo 2 (pginas 1532).

Java Software, Sun


Microsystems, Inc., How to
Write Doc Comments for the
Javadoc Tool.

Requerida:

Barker, primera edicin, captulo


10 (pginas 2303).

1.2.2 Relaciones entre


Clases

Requerida:

1.2.5 Modelando
Clases

toString

Barker, primera edicin, captulo


3 (pginas 5962), captulo 4
(pginas 83109), captulo 7
(pginas 179-85), captulo 13
(pginas 326-33).
Barker, segunda edicin,
captulo 3 (pginas 6871),
captulo 4 (pginas 97161),
captulo 7 (pginas 313-20).

Requerida:

2.1.3 Mtodo equals y


Mtodo

Barker, primera edicin, captulo


10 (pginas 213 30).
Barker, segunda edicin,
captulo 10 (pginas 35572).

Requerida:

2.1.2 Herencia

Barker, primera edicin, captulo


5 (pginas 113 20); captulo 10
(pginas 233 40).
Barker, segunda edicin,
captulo 5 (pginas 16774);
captulo 10 (pginas 37686).

Requerida:

2.1.1 Definiendo
Clases

Barker, segunda edicin,


captulo 10 (pginas 3726).

Barker, primera edicin, captulo


5 (pginas 12039); captulo 13
(pginas 305-11 and 33543).
Barker, segunda edicin,
captulo 5 (pginas 174208).

Requerida:

Barker, primera edicin, captulo


13 (pginas 3625).

2.1.4 Prueba de
Unidades

Barker, segunda edicin,


captulo 13 (pginas 52332).

Opcional:

IPL Information Processing Ltd,


Why Bother to Unit Test?.

Opcional:

2.2.1 Arreglos

Requerida:

2.2.2 ArrayList e
Iteradores

IPL Information Processing Ltd,


Designing Unit Test Cases.

Barker, primera edicin, captulo


6 (pginas 1438); captulo 13
(pginas 3168).
Barker, segunda edicin,
captulo 6 (pginas 21927).

Requerida:

Barker, primera edicin, captulo


13 (pginas 3436).
Barker, segunda edicin,
captulo 6 (pginas 227-40,
pginas 249-59); captulo 13
(pginas 3168).
Nota: La primera edicin no
cubre el uso de la clase
ArrayList y genricos.

2.3.1 Clases
Abstractas

Requerida:

2.3.2 Polimorfismo

Barker, primera edicin, captulo


7 (pginas 16975).
Barker, segunda edicin,
captulo 7 (pginas 28290).

Requerida:

Barker, primera edicin, captulo

2.3.3 Interfaces

Requerida:

2.3.4 Patrones de
Diseo

7 (pginas 1648).
Barker, segunda edicin,
captulo 7 (pginas 27480).

Barker, primera edicin, captulo


7 (pginas 1758).
Barker, segunda edicin,
captulo 7 (pginas 290304).

Opcional:

James W. Cooper, The Design


Patterns Java Companion.
"Some Background on Design
Patterns" (pginas 106).

2.3.5 Patrn de Diseo Opcional:


Singular
James W. Cooper, The Design
(Singleton)
Patterns Java Companion. "The
Singleton Pattern" (pginas 31
6).
2.3.6 Patrn de Diseo Opcional:
Estrategia
James W. Cooper, The Design
(Strategy)
Patterns Java Companion. "The
Strategy Pattern" (pginas 194
201).
3.1.1 E/S con Archivos Requerida:

3.2.1 Componentes y
Contenedores
Swing

Barker, primera edicin, captulo


15 (pginas 42732).
Barker, segunda edicin,
captulo 15 (pginas 624630).

Requerida:

Barker, primera edicin, captulo

3.2.2 Manejo de
Eventos Swing

Requerida:

3.2.3 Clase

16 (pginas 471522).
Barker, segunda edicin,
captulo 16 (pginas 681735).

Barker, primera edicin, captulo


16 (pginas 522-44).
Barker, segunda edicin,
captulo 16 (pginas 73561).

Requerida:

JFileChooser

Barker, primera edicin, captulo


16 (pginas 54552).
Barker, segunda edicin,
captulo 16 (pginas 76169).

Вам также может понравиться