Vous êtes sur la page 1sur 205

Programacin

orientada a objetos
(con Java)

Capitulo 1: Objetos y clases


 Simula: 1967 -> Introduce el concepto de Objeto
Smalltalk: 1980 -> POO puro, desarrollado en Xerox
C++: 1983-1990 -> por Bjarne Stroustrup (C con clases)
Object Pascal: 1986 -> Esqueleto simplificado de lenguaje POO por desarrolladores de Apple Computer y Niklaus Wirth
Eiffel 1985 -> Bertrand Meyer

Java: 1995, 1997, 1998 -> Sun Microsystems: Write once, run everywhere,
C# (C Sharp) 2001 -> Microsoft. Plataforma .Net
 2012 : Lo que sea con objetos: Cobol con objetos, ensamblador con objetos, Fortran con objetos, Pocoy con objetos

Muchas
arquitecturas: x86,
itanium, sparc,
powerpc, alpha,
as400, mainframe,
silicon graphics
(x64, itanium)
2

Capitulo 1: Objetos y clases


Lenguajes de POO puros
Todo es un objeto.
Smalltalk, Eiffel, alguien los usa?

Lenguajes de POO impuros


Prcticamente todos los dems
3

Capitulo 1: Objetos y clases


POO es un paradigma: El lenguaje
puede ayudar o no
Cualquier lenguaje sirve para respetar el
espritu de POO: C, ensamblador

y el programador puede seguirlo o no


Si es lenguaje no es POO puro es fcil hacer
las mayores chapuzas, de hecho se hacen
4

Capitulo 1: Objetos y clases


Qu es una clase?
Es un concepto abstracto: Persona, Coche,
Incluye otros conceptos (atributos). Tambin puede marcar tareas
y como se realizan (funciones miembro, mtodos).

Y un objeto?
Una instanciacin (ejemplo) de una clase: Obama, el Opel
Corsa de mi primo. Dos Opel Corsa son distintos, aunque no haya
manera de distinguirlos. Si hay dobles de Obama, tambin se
consideran objetos distintos.
Un atributo de un coche podra ser el color. Un mtodo de una
persona podra ser recitar su DNI

Capitulo 1: Objetos y clases


Ms sobre los mtodos:
Son como las funciones
de
toda
la
vida.
public class Coche {
private String color;
public void cambiarColor(String nuevoColor) {
color = nuevoColor;
}
}
Coche opelCorsa = new coche();
opelCorsa.cambiarColor(verde);
opelCorsa = new coche();
opelCorsa.cambiarColor(azul); 6
Coche mismoOpelCorsa = opelCorsa;

Capitulo 1: Objetos y clases


Crear objetos con BlueJ es fcil

As como ejecutar mtodos, incluso con parmetros

Vamos a comprobarlo

Capitulo 1: Objetos y clases


Los datos lo son todo
Kronecker
Dios hizo los nmeros naturales, el resto es obra del hombre
Dedekind
Los nmeros son la libre creacin de la mente humana
Cabrera
Dios hizo el nmero uno, lo dems es obra del hombre
Yo
El informtico llamo 0 a la ausencia de 1. El resto es historia.

Capitulo 1: Objetos y clases


OTipos bsicos en Java (todos a partir de 0s y 1s):
OEnteros:

OLong (64 bits)


OInt (32 bits)
OShort (16 bits)
OByte (8 bits)

OComa flotante:

OFloat (32 bits)


ODouble (64 bits)

OCaracteres (16 bits, UNICODE)


OLgicos (1 bit): true, false

OString (no es bsico)


OCunto espacio ocupan? Nadie lo sabe
9

Capitulo 1: Objetos y clases


OClase: Patrn que define atributos y mtodos comunes

a los objetos de cierto tipo.


OComponentes de un Objeto:
OOperaciones (mtodos)
OEstado (atributos)

OEj:
OClase: Telfono Mvil
OCampos: Marca, Modelo, Color, Dimensiones,
OOperaciones: Encender, Apagar, Llamar,
OObjeto: Telfono Mvil de Jos
OAtributos: Marca=Nokia, Modelo=3310, Color=Rojo,
OOperaciones: Encender, Apagar, Llamar,
10

Capitulo 1: Objetos y clases


Los mtodos pueden devolver resultados o no:
String obtenerNombre();
void cabiarNombre(String nuevoNombre);
El encabezado de un mtodo se denomina su signatura.
Proporciona la informacin necesaria para invocar dicho
mtodo.

11

Captulo 2: Comprender las


deniciones de clases
Clases -> Campos
Atributos <- Objetos
Las clases tienen campos, constructores y mtodos
Constructor: Reserva el espacio necesario para contener un
objeto, produce una referencia al objeto y tal vez ms cosas.
public MaquinaDeBoletos(int precioDelBoleto);
{
precio = precioDelBoleto;
saldo = 0;
Parmetro formal
total = 0;
}

Parmetro actual

MaquinaDeBoletos mm = new MaquinaDeBoletos(100);

12

Captulo 2: Comprender las


deniciones de clases
Campos , mtodos de acceso y modificacin:
public class MaquinaDeBoletos
{
private int precio;
private int saldo;
private int total;
.
}

Campos privados, no se puede


acceder de forma directa:
MaquinaDeBoletos mm = new
MaquinaDeBoletos(20);
mm.saldo = 1000;

13

Captulo 2: Comprender las


deniciones de clases
Mtodos de acceso
/* Este mtodo obtiene el saldo */
public int obtenerSaldo()
{
return saldo;
}
Mtodos de modificacin
public void ingresarDinero(int cantidad)
{
saldo = saldo + cantidad;
}

14

Captulo 2: Comprender las


deniciones de clases
La sentencia condicional
Expresin booleana

if (saldo >= precio)


System.out.println(Boleto comprado);
else
System.out.println(Aqu falta dinero);
.

15

Captulo 2: Comprender las


deniciones de clases
Campos, parmetros y variables locales:
lugar de definicin, tiempo de vida y accesibilidad
Variables locales:

public int reintegrarSaldo()


{
int cantidadAReintegrar;
cantidadAReintegrar = saldo;
saldo = 0;
return cantidadAReintegrar;
}
16

Captulo 3:
Interaccin de objetos
Conceptos principales:
Abstraccin
Modularizacin
Creacin de objetos
Diagramas de objetos
Llamadas a mtodos

17

Captulo 3:
Interaccin de objetos
Abstraccin y modularizacin:
1. Modularizacin: Dividir un problema complejo en partes
ms sencillas.
coche -> volante, ruedas, carrocera,
rueda -> llanta, neumtico, tornillos,
Cada mdulo correspondera a una clase.
1. Abstraccin: Concentrarse en un subproblema concreto y
olvidarse del problema general.
Cuando estoy trabajando con la rueda, me olvido del
volante, de los intermitentes, etc

18

Captulo 3:
Interaccin de objetos
Diagrama de objetos

Diagrama de clases
VisorDeReloj

miVisor:
VisorDeReloj
horas
minutos

:VisorDeNumero

11
VisorDeNumeros
:VisorDeNumero

03
19

Captulo 3:
Interaccin de objetos
miVisor:
VisorDeReloj
horas

:VisorDeNumero

minutos

limite

24

valor

15

:VisorDeNumero
limite

60

valor

23

20

Captulo 3:
Interaccin de objetos
Clase VisorDeNumeros:
setValor
getValor
getValorDelVisor
incrementar

Operadores lgicos
&& (y)
|| (o)
! (no)

public void setValor(int nuevoValor)


{
If (nuevoValor >= 0) && (nuevoValor < limite))
valor = nuevoValor;
}

a && b
a || b
!a
21

Captulo 3:
Interaccin de objetos
% = resto de la

divisin entera:
0%8=0
public void incrementar()
1%8=1
{
2%8=2
valor = (valor + 1) % limite;

}
8%8=0
9%8=1
limite = 8
public String getValorDelVisor()
{
7 0
if (valor < 10)
1
6
return 0 + valor;

5
4

2
3

else
return + valor;
}
22

Captulo 3:
Interaccin de objetos
Objetos que crean objetos
public class VisorDeReloj
{
private VisorDeNumeros horas;
private VisorDeNumeros minutos;

Parmetro actual
new VisorDeNumeros(24);
Constructores mltiples
new VisorDeReloj()
new VisorDeReloj(hora, minuto)

public VisorDeNumeros(int limiteMaximo)


Parmetro formal
23

Captulo 3:
Interaccin de objetos
Llamadas a mtodos internos:

Llamadas a mtodos externos:

public VisorDeReloj()
{
horas = new VisorDeNumeros(24);
minutos = new VisorDeNumeros(60);
actualizarVisor();
}
public void TicTac()
{
minutos.incrementar();
if (minutos.getValor() == 0)
// alcanz el lmite!
horas.incrementar();
actualizarVisor();
}

24

Captulo 4:
Agrupar objetos
Ejemplo de la agenda personal:
Permite almacenar notas (strings, concretamente)
No hay lmite al nmero de notas que se pueden almacenar
Muestra las notas de manera individual
Se puede saber cuntas notas hay almacenadas
clase genrica
La clase ArrayList

private ArrayList<String> notas;

Paquetes en java

import java.util.ArrayList
25

Captulo 4:
Agrupar objetos
Mtodos destacados : add,
get, size

notas = new ArrayList<String>();

notas.add(nota);

return notas.size();

System.out.println(notas.get(numeroDeNota));

notas.remove(numeroDeNota);

26

Captulo 4:
Agrupar objetos
Puede aumentar su capacidad
interna tanto como sea necesario

Caractersticas de
ArrayList:

Mantiene la cuenta de cuntos


objetos contiene. El mtodo size
devuelve dicha cantidad

Mantiene el orden de los elementos tal y


como han sido agregados, de modo que
se pueden recuperar en el mismo orden
27

Captulo 4:
Agrupar objetos
ArrayList<Persona> ArrayList<MaquinaDeBoletos>

Los ndices permitidos para get van de 0 hasta size - 1

Si se accede con un ndice incorrecto:


IndexOutOfBoundsException
28

Captulo 4:
Agrupar objetos
Procesar una coleccin completa

Variable de ciclo

System.out.println(notas.get(0));
System.out.println(notas.get(1));
System.out.println(notas.get(2));
.

public void imprimirNotas()


{
for(String nota : notas) {
System.out.println(nota);
}
}

ciclo for-each
29

Captulo 4:
Agrupar objetos
Procesar una coleccin completa 2

int indice = 0;
while (indice < notas.size()) {
System.out.println(notas.get(indice));
indice++;
}

bucle
while

Hay que declarar e inicializar una variable local.


Los elementos no se pasan automticamente a la variable
Tenemos que incrementar la variable indice nosotros mismos
indice++ equivale indice = indice + 1;

30

Captulo 4:
Agrupar objetos
El bucle while no slo sirve para recorrer colecciones
Si olvidamos incrementar la variable del bucle, puede haber
un bucle infinito
Podemos acabar cuando queramos, no tiene porque seguir
hasta el final
int numero = 0;
while (numero <= 30) {
System.out.println(numero);
numero = numero + 2;
}
31

Captulo 4:
Agrupar objetos
Otro ejemplo con bucle while: El patrn de bsqueda
int indice = 0;
boolean encontrado = false;
while (indice < notas.size() && !encontrado) {
String nota = notas.get(indice);
if (nota.contains(cadABuscar)) {
encontrado = true;
}
else {
indice++;
}
}

32

Captulo 4:
Agrupar objetos
Procesar una coleccin completa 3

public void listarTodasLasNotas()


{
Iterator<String> it = notas.iterator();
while (it.hasNext()) {
System.out.println(it.next());
}
}
33

Captulo 4:
Agrupar objetos
null y cortocircuito

if ((ofertaMaxima == null) ||(oferta.getValor() > ofertaMaxima.getValor()))

Objetos annimos
public void ingresarLote(String descripcion)
{
lotes.add(new Lote(numeroDeLoteSiguiente, descripcion));
numeroDeLoteSiguiente++;
}

34

Captulo 4:
Agrupar objetos
Objetos annimos
public void ingresarLote(String descripcion)
{
Lote nuevoLote = new Lote(numeroDeLoteSiguiente, descripcion));
lotes.add(nuevoLote));
numeroDeLoteSiguiente++;
}

35

Captulo 4:
Agrupar objetos
Colecciones de tamao fijo: arrays
Ventajas frente a colecciones de tamao variable:
El acceso a los elementos del array es ms eficiente
Los arrays pueden almacenar objetos o valores de tipos
primitivos, las colecciones no (autoboxing, el vector de
booleanos);
Desventajas:
Sintaxis de C

36

Captulo 4:
Agrupar objetos
Arrays
Declaracin:
private int[] contadoresPorHora;

Creacin:
contadoresPorHora = new int[24];

String [] nombres = new String[10];


(crea el array, pero no crea 10 cadenas, sino diez referencias a
null)
37

Captulo 4:
Agrupar objetos
Arrays

Uso:
etiquetas[6];
maquinas[0];
gente[x + 10 y];

etiqueta[5] = "Salir";
double mitad = lecturas[0] / 2;
System.out.println(gente[3].getNombre());
maquinas[0] = new MaquinaDeBoletos(500);

38

Captulo 4:
Agrupar objetos
Arrays y bucle for:
for(inicializacin; condicin;
modificacin) {
sentencias a repetir
}
for(int hora = 0;
hora < contadoresPorHora.length;
hora++)
System.out.println(hora+ " : "+
contadoresPorHora[hora]);
}

inicializacin;
while (condicin) {
sentencias a repetir;
modificacin;
}
int hora = 0;
while (hora < contadoresPorHora.length) {
System.out.println(hora+" : "+
contadoresPorHora[hora];
hora++;
39
}

Captulo 5:
Comportamiento ms sosticado
Aprender a usar las clases de la bibloteca!
String, ArrayList, Random, HashMap, HashSet, Iterator, Arrays
Construcciones: static y final

40

Captulo 5:
Comportamiento ms sosticado
Consultar la documentacin

41

Captulo 5:
Comportamiento ms sosticado
boolean

startsWith(Stringprefix)
Comprueba si esta cadena empieza con el prefijo
especificado.

String entrada =
lector.getEntrada();
if (entrada.startsWith("bye") {
terminado = true;
}
String

String entrada = lector.getEntrada().trim();


if (entrada.startsWith("bye")) {
terminado = true;
}

trim()
Devuelve una copia de la cadena, con los
espacios en blanco del principio y final omitidos.
42

Captulo 5:
Comportamiento ms sosticado
Comprobar la igualdad de cadenas

if (entrada == "bye") { // no siempre funciona!

if (entrada = "bye") { // asignacin!


if (entrada.equals("chau") {

43

Captulo 5:
Comportamiento ms sosticado
Numeros aleatorios

import java.util.Random;

Random generator = new Random();


int indice = generator.nextInt(); // Cualquier entero
int lolailo = generator.nextInt(n); // Entre 0 y n-1

Random generator = new Random(seed);


// nextChar, nextDouble, nextGaussian,
44

Captulo 5:
Comportamiento ms sosticado
Documentacin de clases parametrizadas:
Class ArrayList<E>

boolean

add(Eo)
Aade el elemento espcificado al final de la lista

45

Captulo 5:
Comportamiento ms sosticado
Hashmap
HashMap<String, String> agenda = new Hashmap<String, String>();
agenda.put("Charles Nguyen", " (531) 9392 4587");
agenda.put("Lisa Jones", " (402) 4536 4674");
agenda.put("Pepe Puertas", " (998) 5488 0123");

String numero = agenda.get("Lisa Jones");


System.out.println(numero);
V
get(Objectkey)
Devuelve el valor al que el valor especificado est asociado o
46
null si la asociacin no asociada nada a esta clave.

Captulo 5:
Comportamiento ms sosticado
HashSet:
set: Una coleccin que no contiene elementos duplicados. Mas
formalmente, un conjunto no contiene ningn par de elementos, e1 y
e2 tal que e1.equals(e2), y como mucho contiene el elemento null
una vez. Como implica su nombre, este interfaz modela la asbtraccin
matemtica de conjunto.
import java.util.HashSet;
import java.util.Iterator;

HashSet<String> miConjunto = new HashSet<String>();


miConjunto.add("uno"); miConjunto.add("dos"); miConjunto.add("tres");

47
for(String lala = miConjunto) {
hacer algo con lala
}

Captulo 5:
Comportamiento ms sosticado
Dividir cadenas
split
public String[] split(Stringregex, intlimit)
Divide esta cadena alrededor de los ajustes con la expresin regular.
El parmetro lmite controla el nmero de veces que se ajusta el patrn,
y afecta por tanto a la longitud del array resultante.
Si el lmite n es mayor que cero, el patrn se aplicar como mximo
n-1 veces.
String[] arregloDePalabras =
lector.lineaSiguiente().trim().toLowerCase().split(" ");
48

Captulo 5:
Comportamiento ms sosticado
Variables de clase y constantes
static :
Sirve para definir variables "de clase", Las variables de clase son
campos que se almacenan en la misma clase y no en un objeto:
private static final int GRAVEDAD = 3;

49

Captulo 5:
Comportamiento ms sosticado
ReboteDePelota
es instancia de

es instancia de
Gravedad

pelota1:ReboteDePelota
posicionX

10

posicionY

233

variable de clase

pelota3:ReboteDePelota

es instancia de

posicionX

782

posicionY

33

pelota2:ReboteDePelota

variables de instancia

posicionX

76

posicionY

155

50

Captulo 5:
Comportamiento ms sosticado
Escribir documentacin de clase
Es bueno para uno mismo cuando programa su propio cdigo
Es bueno para los dems cuando trabajan con nuestro cdigo
Es bueno para nosotros cuando necesitamos utilizar clases de
la bibiloteca de Java como HashSet o Random.
Es fcil usando javadoc
Pero la verdad es que No siempre merece la pena!

51

Captulo
5
:
Usar javadoc en BlueJ
Comportamiento ms sosticado

52

Captulo 5:
Comportamiento ms sosticado

53

Captulo 5:
Comportamiento ms sosticado

54

Captulo 5:
Comportamiento ms sosticado

55

Captulo 5:
Comportamiento ms sosticado
Etiquetas de javadoc:
@author
@deprecated
@exception
@param
@return
@see
@serial
@since
@throws
@version

Tambin se puede escribir HTML!

56

Captulo 7:
Disear clases
World of zuul

57

Captulo 7:
Disear clases
PalabrasComando: Define todos los comandos vlidos del
juego mediante un array de cadenas que contienen la
palabras que se usarn como comandos
Analizador: Lee las lneas de entrada desde el terminal y trata
de interpretarlas como comandos. Crea objetos de clase
comando.
Comando: Representa al comando introducido por el usuario,
consta de primera palabra y segunda palabra
Habitacin: Un objeto habitacin representa una ubicacin en
el juego. Tiene una descripcin y unas salidas que conducen a
otras habitaciones
Juego: Es la clase principal del programa. Establece el inicio
del juego e incluye un ciclo de leer e interpreta los comandos
del usuario. Tambin implementa los comandos del usuario.

58

Captulo 7:
Disear clases
Acoplamiento

El trmino acoplamiento describe la interconectividad de las


clases. Nos esforzamos por lograr acoplamiento dbil en un
sistema. Es decir, un sistema en el que cada clase es altamente
independiente y se comunica con otras clases mediante una
pequea interfaz bien definida.
El grado de acoplamiento determina el grado de dificultad de
realizar modificaciones en una aplicacin; en una estructura de
clases fuertemente acoplada, un cambio en una clase hace
necesario cambiar varias otras clases.
59

Captulo 7:
Disear clases
Cohesin

El trmino cohesin describe cunto se ajusta una unidad de


cdigo a una tarea lgica o a una entidad. En un sistema
altamente cohesivo, cada unidad de cdigo (mtodo, clase o
mdulo) es responsable de una tarea bien definida o de una
entidad.
Un diseo de clases de buena calidad exhibe un alto grado de
cohesin
60

Captulo 7:
Duplicacin de cdigo
Disear
c
lases
private void imprimirBienvenida()
{
System.out.println();
System.out.println(Bienvenido al World of Warcraft!");
System.out.println(World of Warcraft es un nuevo juego de
aventuras conversacional increiblemente aburrido,");
System.out.println(Teclea ayuda si necesitas ayuda.");
System.out.println();
System.out.println(Estas en " +
habitacionActual.getDescripcion());
System.out.print(Salidas: ");
if(habitacionActual.salidaNorte != null)
System.out.print("norte ");
if(habitacionActual.salidaEste != null)
System.out.print("este ");
if(habitacionActual.salidaSur != null)
System.out.print("sur ");
if(habitacionActual.salidaOeste != null)

61

Captulo 7:
Duplicacin de cdigo
Disear clases

private void irHAbitacion(Comando comando)


{
if(!comando.tieneSegundaPalabra()) {
// Si no hay segunda palabra, no
sabemos
// adnde ir
System.out.println(Ir adnde?");
return;
}
String direccion =
comando.getSegundaPalabra();
// Intenta abandonar la habitacion actual
Habitacion siguienteHabitacion = null;
if (direccion.equals("norte))
siguienteHabitacion =
habitacionActual.salidaNorte;
if (direction.equals("este"))
siguienteHabitacion =
habitacionActual.salidaEste;
if (direction.equals("sur"))
siguienteHabitacion =

if (siguienteHabitacion == null)
System.out.println(No hay puerta!");
else {
habitacionActual =
siguienteHabitacion;
System.out.println(Estas en " +
habitacionActual.getDescripcion());
System.out.print(Salidas: ");
if (habitacionActual.salidaNorte != null)
System.out.print("norte ");
if (habitacionActual.salidaEste != null)
System.out.print("este ");
if (habitacionActual.salidaSur != null)
System.out.print("sue ");
62 != null)
if (habitacionActual.salidaOeste
System.out.print(oeste");
System.out.println();

Captulo 7:
Disear clases
Solucin: Aadir un nuevo mtodo
private void imprimirInformacionDeUbicacion() {
System.out.println("Ests en " habitacionActual.getDescripcion());
System.out.print("Salidas: ");
if(habitacionActual.salidaNorte != null)
System.out.print("norte ");
if(habitacionActual.salidaEste != null)
System.out.print("este ");
if(habitacionActual.salidaSur != null)
System.out.print("sur ");
if(habitacionActual.salidaOeste != null)
System.out.print("oeste ");
System.out.println();
}

63

Hacer extensiones (I): Aadir nuevas direcciones

Captulo 7:
Disear clases

public class Habitacion


{
public String descripcion;
public Habitacion salidaNorte;
public Habitacion salidaSur;
public Habitacion salidaEste;
public Habitacion salidaOeste;

public void ponSalidas(Habitacion norte, Habitacion este, Habitacion sur,


Habitacion oestet)
{
if (norte != null)
salidaNorte = norte;
if (este != null)
salidaEste = este;
if (sur != null)
salidaSur = sur;
if(west != null)
salidaOeste = oestet;
}

64

Captulo 7:
Disear clases

Hacer extensiones (I): Aadir nuevas direcciones

public class Juego


{

private void crearHabitaciones()


{

// inicializa las salidas de las habitaciones


afueras.ponSalidas(null, teatro, laboratorio, garito);
teatro.ponSalidas(null, null, null, afueras);
garito.ponSalidas(null, afueras, null, null);
laboratorio.ponSalidas(afueras, oficina, null, null);
oficina.ponSalidas(null, null, null, laboratorio);

private void imprimirInformacionDeUbicacion() { }


private void irHabitacion(Comando comando) { }

65

Captulo 7:
Disear clases
Hacer extensiones (I): Aadir nuevas direcciones
El diseo es psimo:
1. En la clase Habitacin:
Tenemos una variable para cada salida posible.
En establecerSalidas, hay un if por cada direccin
2. En la clase Juego:
En el mtodo irHabitacion, hay un if por cada direccin
En el mtodo imprimirInformacionDeUbicacion, lo mismo.
Aadir las direcciones "arriba" y "abajo", sera un infierno, hay que
aadirlas en muchos sitios. No digamos si hubiera direcciones como
noroeste y sureste.

66

Captulo 7:
Disear clases
Hacer extensiones (I): Aadir nuevas direcciones

Vamos a usar un HashMap<String, Habitacion>

clave del hasmap, es el nombre de la


direccin (p.e. "norte").

una referencia a la
habitacion a la que
nos desplazamos
en esa direccin
67

Captulo 7:
Disear clases
Hacer extensiones (I): Aadir nuevas direcciones
Se trata de un cambio de implementacin (como se almacenan las
habitaciones), no de interfaz (qu almacenan las habitaciones).
No debera afectar a las dems clases (cambios localizados), si el
acoplamiento fuese dbil
Pero el caso es que s lo hace, porque el acoplamiento es muy
fuerte y el proyecto ya no compila.

Antes de poder limpiar la situacin, hay que desacoplar las clases

68

Captulo 7:
Disear clases
Hacer extensiones (I bis): Desacoplar

Usar encapsulamiento para reducir el acoplamiento

Todos los campos de la clase Habitacion son pblicos, por lo que


no hay encapsulamiento.
Solamente lo que hace una clase debe ser visible desde el
exterior, no como lo hace. De ese modo, podemos cambiar la
implementacin interna de la clase sin romper el proyecto.
Primer paso: Hacer todos los campos privados y declarar mtodos de acceso.
69

Captulo 7:
Disear clases

public class Habitacion


{
private String description;
private Habitacion salidaNorte;
private Habitacion salidaSur;
private Habitacion salidaEste;
private Habitacion salidaOeste;
....
public Habitacion getSalida(String
direccion) {
if (direccion.equals("norte"))
return salidaNorte;
if (direccion.equals("este"))
return salidaEste;
if (direccion.equals("sur"))
return salidaSur;
if (direccion.equals("oeste"))
return salidaOeste;

clase juego

private void irHabitacion(String direccion)


{
Habitacion siguienteHabitacion = null:
if(direccion.equals("norte")) {
siguienteHabitacion = habitacionActual.getSalida("norte");
}
if(direccion.equals("este")) {
siguienteHabitacion = habitacionActual.getSalida("este");
}
if(direccion.equals("sur")) {
siguienteHabitacion = habitacionActual.getSalida("sur");
}
if(direccion.equals("oeste")) {
siguienteHabitacion = habitacionActual.getSalida("oeste");
}

Habitacion siguienteHabitacion
70 =
habitacionActual.getSalida(direccion);

public void establecerSalidas(Habitacion norte,


Habitacion este,
public class Habitacion {
Habitacion sur,
private String descripcion;
Con el HashMap:
Habitacion oeste)
private HashMap<String, Habitacion> salidas
{
if (norte != null)
/**
salidas.put("norte", norte);
* Crea un lugar descrito por "descripcion".
if (norte != null)
* Inicialmente no tiene salidas. "descripcion" es
salidas.put("este", este);
* algo as como "una cocina" o "un patio".
if (norte != null)
*/
salidas.put("sur", sur);
if (norte != null)
public Habitacion(String descripcion)
salidas.put("oeste", oeste);
{
}
this.descripcion = descripcion;

Captulo 7:
Disear clases

salidas = new HashMap<String, Habitacion>();


}

/**
* Define las salidas para esta habitacion. Cada
* direccin conduce a otra habitacin o bien es
null
* (es decir, no hay salida)
*/

/**
* Devuelve la direccion a la que se llega si
* vamos desde esta habitacion en direccion
* "direccion". Si no existe ninguna
* habitacion en esta habitacion, devolvemos
null.
*/
public Habitacion getSalida(String direccion) {
return salidas.get(direccion); }71
...
}

Captulo 7:
Disear clases
establecerSalidas(Habitacion norte, Habitacion este, Habitacion sur,
Habitacion oeste)
esto an chirra, pero si lo cambiamos afectar a Juego,
que est muy acoplada a Habitacion
public void establecerSalidas(String direccion, Habitacion vecina) {
salidas.put(direccion, vecina);
}

72

Captulo 7:
Disear clases
Donde antes hacamos (en la clase Juego)
laboratorio.establecerSalida(exterior, oficina, null, null);
Ahora simplemente escribimos:
laboratorio.establecerSalida("norte", exterior);
laboratorio.establecerSalida("este", oficina);

Hemos desacoplado bastante Juego y Habitacion, y ahora cualquier


direccion es posible, solo hay que usarla como salida de una habitacin
y todo funcionar automticamente
73

Captulo 7:
Disear clases
Si queremos aadir una habitacin llamada "sotano", debajo de la
oficina, no tenemos ms que aadir unas lneas al mtodo
crearHabitaciones de Juego y todo (ms o menos) funcionar:
public class Juego {

private void crearHabitaciones() {


Habitacion exterior, teatro, bar, laboratorio, oficina, sotano;

sotano = new Habitacion("en el stano");

oficina.establecerSalida("abajo", sotano);
sotano.establecerSalida("arriba", oficina);

74

Captulo 7:
Disear clases
Diseo dirigido por responsabilidades
Tcnicas para reducir el acoplamiento:
Encapsulamiento (lo acabamos de ver)
Diseo dirigido por responsabilidades:
Cada clase es responsable de manejar sus propios datos

La clase que almacena los datos es tambin la responsable de manipularlos

75

Captulo 7:
Disear clases

Responsabilidades y acoplamiento

Antes:

Despus:

public String getStringDeSalidas() {


String stringADevolver = "Salidas: ";
Set<String> llaves = salidas.keySet();
for(String salida : llaves)
stringADevolver += " " + salida;
return stringADevolver;
}

public String getStringDeSalidas() {


String stringDeSalidas = "Salidas: ";
if (salidaNorte != null)
stringDeSalidas += "norte";
if (salidaEste != null)
stringDeSalidas += "este";
if (salidaSur != null)
La clase Habitacion ya no accede a los nombre
stringDeSalidas += "sur";
de las direcciones.
if (salidaOeste != null)
Ahora son responsabilidad de Juego!
stringDeSalidas += "oeste";
76

Captulo 7:
Disear clases

En un futuro podramos querer aadir monstruos o


ms jugadores...
Juego

Habitacin
public getDescripcionLarga() {
System.out.println("Ud. est "+
descripcion + ".\n" +
getStringDeSalidas();
}

private void imprimirInformacionDeUbicacion() {


System.out.println("Ests en "
habitacionActual.getDescripcion());
System.out.print("Salidas: ");
if(habitacionActual.salidaNorte != null)
System.out.print("norte ");
if(habitacionActual.salidaEste != null)
System.out.print("este ");
if(habitacionActual.salidaSur != null)
System.out.print("sur ");
if(habitacionActual.salidaOeste != null)System.out.println(
System.out.print("oeste ");
habitacionActual.getDescripcionLarga()
System.out.println();
);
}

77

Captulo 7:
Disear clases
Localizacin de cambios
Una modificacin debera circunscribirse al menor nmero
posible de clases, eso indicara un buen diseo, dicha
localizacin de cambios es el resultado natural de
El bajo acoplamiento
La alta cohesin
El diseo dirigido por responsabilidades

78

Captulo 7:
Disear clases
Acoplamiento implcito
Es tan malo como usar campos pblicos, pero ms peligroso
porque no lo detecta el compilador, sucede cuando un cambio en
una clase implica el mismo cambio en otra.

Hacer extensiones (II): Aadir nuevos comandos


Queremos aadir un nuevo comando, "ver", que nos repita la
descripcin larga de la habitacin actual
79

Captulo 7:
Disear clases
Hacer extensiones (II): Aadir nuevos comandos
PalabrasComando
// Un array constante que contiene todas las palabras comando vlidas
private static final String comandosValidos[] = {
"ir", "salir", "ayuda", "ver"
};
Lo probamos y no hace nada, pero tampoco da error, los comandos
desconcidos producen el error: "No s qu significa"
Eso es porque no hemos implementado el comando!
80

Captulo 7:
Disear clases
Hacer extensiones (II): Aadir nuevos comandos
Aadimos un mtodo para este comando "ver":
Juego
private void ver() {
System.out.println(habitacionActual.getDescripcionLarga());
}
Y un caso ms en procesarComando:
Juego
if (palabraComando.equals("ayuda")) imprimirAyuda();
else if (palabraComando.equals("ir")) irAHabitacion(comando);
else if (palabraComando.equals("ver")) ver();
else if (palabraComando.equals("salir")) quiereSalir = salir(comando);

81

Captulo 7:
Disear clases
Hacer extensiones (II): Aadir nuevos comandos
Haba un acoplamiento implcito entre PalabrasComando y Juego,
pero ya lo hemos solucionado. O no.
Si ejecutamos el comando ayuda...
Est perdido. Est solo. Vagabundea por la universidad.
Sus palabras comando son:
ir salir ayuda
El problema se puede corregir fcilmente modificando el mtodo
imprimirAyuda de la clase Juego, el problema es que este tipo de
problemas suele pasar desapercibido.
No se ha seguido el diseo dirigido por responsabilidades!

82

Captulo 7:
Disear clases
Hacer extensiones (II): Aadir nuevos comandos
Lo correcto es que la clase PalabrasComando proporcione a las
dems los datos sobre los distintos comandos que hay
PalabrasComando
public void mostrarTodos() {
for(String comando : comandosValidos)
Sigue sin ser una buena
System.out.print(comando+" ");
solucin, por qu?
System.out.println();
}
Ahora podemos aadir nuevos comandos sin tener que cambiar
imprimirAyuda en la clase Juego cada vez
El problema es que Juego no tiene acceso a la clase PalabrasComando83

Captulo 7:
Disear clases
Opcin 1: Usar una referencia a
PalabrasComando dentro de Juego

Opcin 2: Aadir un mtodo en


Analizador para mostrar las palabras
comando

La opcin correcta es la 2

84

Captulo 7:
Disear clases
Hacer extensiones (II): Aadir nuevos comandos
Juego
imprimirAyuda
...
System.out.println("Las palabras comando son: ");
analizador.mostrarComandos();
Analizador
public void mostrarComandos() {
comandos.mostrarTodos();
}

No es un buen diseo, no
hay "vista"

Es de la clase PalabrasComando

85

Captulo 7:
Disear clases
Hacer extensiones (III): Aadir elementos

Cohesin de clases

Aadimos dos campos en


la clase Habitacion:
descripcionDeElemento y
pesoDeElemento

Creamos una nueva clase,


Elemento. En esta clase
tenemos un campo para la
descripcion y otro para el peso.

86

Captulo 7:
Disear clases
Refactorizacin

Nuevos requisitos funcionales:


El jugador puede dejar elementos de la habitacin
actual
El jugador puede tomar cualquier nmero de elementos,
pero solo hasta un peso mximo predeterminado
Algunos elementos no pueden ser cogidos
El jugador puede dejar los elementos en la habitacin
actual
87

Captulo 7:
Disear clases
Tareas concretas por realizar
Creamos una clase Elemento (si no la tenamos ya)
Aadimos un campo nombre a la clase Elemento para
simplificar los comandos.
Podemos hacer que los objetos que no se pueden coger
tengan un peso muy grande, o bien usar un bandern lgico
del tipo, puede ser cogido?
Aadimos los comandos tomar y dejar para recoger y soltar
los Elementos.
Debemos aadir algn tipo de coleccin para guardar los
elementos que ha cogido un jugador.
Tambin un campo para el peso mximo que el jugador puede
cargar. Tambin habra que decidir donde se pone ese campo.

88

Captulo 7:
Disear clases
Refactorizacin para independizarse del idioma
Acoplamiento implcito: Los comandos en espaol aparecen tanto
en PalabrasComando como en Juego, en su mtodo
procesarComando.
Si queremos cambiar el idioma de la interfaz, habra que hacer
cambios en dos sitios.
Lo ideal sera que las palabras de los comandos estuvieran en un
slo sitio, y que se referenciaran los comandos de una manera
independiente del idioma.

89

Captulo 7:
Disear clases
Tipos enumerados
public enum PalabraComando {
// Un valor para cada palabra comando, ms una para los
// comandos no reconocidos
IR, SALIR, AYUDA, DESCONOCIDA;
}

Cada uno de estos es un objeto de tipo enumerado.


Se hace referencia a elos como PalabraComando.SALIR
90

Captulo 7:
Disear clases
Juego

if (palabraComando.equals("ayuda"))
imprimirAyuda();
...

if (palabraComando == PalabraComando.AYUD
imprimirAyuda();
...

PalabrasComando
public PalabrasComando() {
comandosValidos = new HashMap<String, PalabraComando>;
comandosValidos.put("ir", PalabraComando.IR);
comandosValidos.put("ayuda", PalabraComando.AYUDA);
comandosValidos.put("ir", PalabraComando.SALIR);
Ahora las palabras solo habra que
cambiarlas en un sitio

91

Captulo 7:
Disear clases
No se vayan, todava hay ms desacoplamiento
public enum PalabraComando {
IR("ir"), SALIR("salir"), AYUDA("ayuda"), DESCONOCIDA("?");
private String cadenaComando;
PalabraComando(String cadenaComando) {
this.cadenaComando = cadenaComando;
}

no hay public

public String toString() { return cadenacomando; }


}
92

Captulo 7:
Disear clases
PalabrasComando
comandosValidos = new HashMap<String, PalabraComando>();
for (PalabraComando comando : PalabraComando.values())
comandosValidos.put(comando.toString(), comando);

Asociamos cada valor enumerado con su descripcion


(e.g. ver con PalabraComando.VER) y as sucesivamente

93

Captulo 7:
Disear clases
Mtodos de clase
Calendario
public static int getNumeroDeDiasDeEsteMes() { ... };
int dias = Calendario.getNumeroDeDiasDeEsteMes();

public static void main(String[] arg)


Los mtodos de clase slo pueden acceder a variables de clase y
a mtodos de clase, nunca a variables o mtodos de instancia

94

Captulo 8: Mejorar la
estructura mediante herencia
DoME: Base de datos de informacin multimedia

CD:
Ttulo del albm
Intrprete
Nmero de temas
Tiempo de duracin
Lo tengo o no lo tengo
Comentario

DVD:
Ttulo del DVD
Nombre del director
Tiempo de duracin
Lo tengo o no lo tengo
Comentario

95

Captulo 8: Mejorar la
estructura mediante herencia
CD
titulo
interprete
numeroDeTemas
duracion
loTengo
comentario
setComentario
getComentario
setLotengo
getLotengo
imprimir

DVD
titulo
director
duracion
loTengo
comentario
setComentario
getComentario
setLotengo
getLotengo
imprimir
96

Captulo 8: Mejorar la
estructura mediante herencia
:BaseDeDatos

:ArrayList<CD>

cds
dvds
:CD

:CD

:CD

:CD

:ArrayList<DVD>

:DVD

:DVD

:DVD

:DVD

97

Captulo 8: Mejorar la
estructura mediante herencia
Problemas:
Duplicacin de cdigo: Las clases de CD y DVD son casi iguales
La clase BaseDeDatos tambin tiene casi todo el cdigo duplicado:
Dos variables de ArrayList, dos objetos lista, dos mtodos para
agregar cosas y dos bloques casi idnticos para imprimir un
listado.
Si aadimos un nuevo tipo de material multimedia, como libro,
la cosa sera terrible

98

Captulo 8: Mejorar la
Elemento
titulo
estructura
m
ediante
h
erencia
duracion
loTengo
comentario
setComentario
getComentario
setLotengo
getLotengo
imprimir
CD
interprete
numeroDeTemas
getInterprete
getNumeroDeTemas

DVD
director
getDirector
99

public class Elemento {


private String titulo;
private int
duracion;
private boolean loTengo;
privatre String comentario;

Captulo 8: Mejorar la
Elemento
titulo
estructura
m
ediante
h
erencia
duracion

public class CD extends Elemento {


private String interprete;
private int numeroDeTemas;

CD
interprete
numeroDeTemas
getInterprete
getNumeroDeTemas

loTengo
comentario

public class DVD extends Elemento {


setComentario
private String director;
getComentario

setLotengo
}
getLotengo
imprimir
DVD
director
getDirector
100

Herencia y derechos de acceso

Captulo 8: Mejorar la
estructura mediante herencia
Lo pblico es pblico y lo privado es privado
public class Elemento {
private String titulo;
public class CD extends Elemento {
private int duracion;
private String interprete;
private boolean loTengo;
private int
numeroDeTemas;
public CD(String elTitulo,
public Elemento(String elTitulo,
String elInterprete,
int tiempo) {
int temas, int tiempo) {
titulo = elTitulo;
super(elTitulo, tiempo);
duracion = tiempo;
interprete = elInterprete;
lotengo = false;
numeroDeTemas = temas;
comentario = "";
}
}

} constructor de superclase (obligatorio)


}
1 instruccin de la subclase101

Captulo 8: Mejorar la
estructura mediante herencia
Elemento

Reutilizacin

titulo
duracion
loTengo
comentario
*
CD
interprete
numderoDeTemas
*

VideoJuego

DVD
director
*

numeroDeJugadores
plataforma
*
102

Elemento
titulo
duracion
loTengo
comentario

Captulo 8: Mejorar la
*
estructura
mediante herencia
CD

Juego

DVD

interprete
numeroDeTemas
*

director

numeroDeJugadores

VideoJuego

JuegoDeMesa

plataforma

*
103

Captulo 8: Mejorar la
estructura mediante herencia
Ventajas de la herencia

Evita la duplicacin de cdigo


Se reutiliza cdigo
Facilita el mantenimiento
Facilita la extensibilidad

104

Captulo 8: Mejorar la
y subtipos herencia
estructura Subclases
mediante
public class BaseDeDatos {
private ArrayList<Elemento> elementos;
public BaseDeDatos() { elementos = new ArrayList<Elemento>();
public void agregarElemento(Elemento elElemento) {
elementos.add(elElemento);
}
public void listar() {
agregarCD
for(Elemento elemento : elementos) {
agregarDVD
elemento.imprimir();
System.out.println();
Los parmetros formales y los
}
actuales deben ser compatibles,
}
no idnticos
}
105

Captulo 8: Mejorar la
estructura mediante herencia
Subtipos y asignacin
Vehiculo

coche miCoche = new Coche();

Vehiculo v1 = new Vehiculo();


Vehiculo v2 = new Coche();
Vehiculo v3 = new Bicicleta();
Una variable puede contener objetos del
tipo declarado o de cualquier subtipo del
tipo declarado

Coche

Bicicleta

Error!
Coche a1 = new Vehiculo();
Coche a2 = new Bicicleta();

106

Captulo 8: Mejorar la
estructura mediante herencia
Subtipos y paso de parmetros
public void agregarElemento(Elemento elElemento) { }

BaseDeDatos bd = new BaseDeDatos();


DVD dvd = new DVD();
CD cd = new CD();
bd.agregarElemento(dvd);
bd.agregarElemento(cd);

107

Captulo 8: Mejorar la
estructura mediante herencia
Variables polimrficas
Variable polimrfica: Una misma variable puede contener objetos
de diferentes tipos (del tipo declarado o de cualquier subtipo del
tipo declarado)

for(Elemento elemento : elementos) {


elemento.imprimir();
System.out.println();
}
108

Captulo 8: Mejorar la
estructura mediante herencia
Enmascaramiento de tipos (casting)

Vehiculo v;
Coche a = new Coche();
v = a; // correcto
a = v; // incorrecto

a = (Coche) v; // downcasting

Vehiculo v;
Coche a;
Bicicleta b;
a = new Coche();
v = a; // Ok
b = (Bicicleta) a; // Error de Compilacion
b = (Bicicleta) v: //ClassCastException
Vehiculo

Coche

Bicicleta

109

Captulo 8: Mejorar la
estructura mediante herencia
La clase Object
Object

String

Persona

Vehiculo

Java viejuno

ArrayList v;
Object a = new Coche();
v.add(a);
Coche c = v.get(0): // Error
c = (Coche) v.get(0); // OK

Coche

Bicicleta

110

Captulo 8: Mejorar la
estructura mediante herencia
Clases envoltorio, autoboxing
Qu pasa si queremos hacer un conjunto de enteros o un hashmap
de strings a booleanos? Los tipos primitivos no son objetos
Tipo primitvo

Tipo envoltorio

byte

Byte

short

Short

int

Integer

long

Long

float

Float

double

Double

char

Character

boolean

Boolean

// Con clase envoltorio


Integer ienvuelto = new Integer(ix);

// Con autoboxing
ArrayList<Integer> listaMarcas;
// Boxing
listaMarcas.add(42);
// (auto)unboxing
int primerMarca = listaMarcas.remove(0);
111

Captulo 9:
Algo ms sobre herencia
Problema: El mtodo imprimir de la base de datos multimedia
CD:
Frank Sinatra: A Swingin' Affair
16 temas
64 minutos
Lo tengo: S
Comentario: Es mi album
favorito de Sinatra

ttulo: A Swingin' Affair *


es mi album favorito de Sinatra

DVD:
O Brother, Where Art Thou?
Director: Joel & Ethan Coen
106 minutos
Lo tengo: No
Comentario: La mejor pelcula de
los hermanos Coen
ttulo: O Brother, Where Art Thou?
La mejor pelcula de los hermanos
Coen!
112

Captulo 9:
Algo ms sobre herencia
BaseDeDatos

Elemento no sabe nada sobre los


campos de CD y DVD

Elemento

...
imprimir
CD

DVD
113

Captulo 9:
Algo ms sobre herencia
Tipo esttico y tipo dinmico
BaseDeDatos

No compila! Llamamos todo el tiempo a


Elemento.imprimir() y ahora no existe

for (Elemento elemento : elementos) {


elemento.imprimir();
System.out.println();
}

CD
...
imprimir

Elemento

DVD
...
imprimir

114

Captulo 9:
Algo ms sobre herencia
Tipo de la variable Tipo del objeto
Vehiculo v1 = new Coche();

Tipo de la variable: Vehiculo


(tipo esttico, siempre es igual)

Tipo del objeto: Coche


(tipo dinmico, la variable
podra apuntar a otro objeto
ms adelante)

Elemento elemento;
elemento.print();
:DVD

El tipo esttico de
elemento es
Elemento, el dinmico
115
puede ser CD o DVD

Captulo 9:
Algo ms sobre herencia
Tipo esttico y tipo dinmico
El compilador solo conoce los tipos estticos, as que si la
clase Elemento no tiene un mtodo imprimir, se produce un
error.
Por tanto, Elemento debe tener un tipo imprimir, lo cual nos
lleva de vuelta al punto de partida.

116

public class Elemento {


...
public void imprimir() {
System.out.print(titulo+ " ("+duracion +
Redefinicin
"minutos) ";
if (loTengo) System.out.println("*");
OVERRIDE!
Sobreescritura
else System.out.println();
System.out.println(" " + comentario);
BaseDeDatos
}
public class CD extends Elemento {
public void imprimir() {
...
System.out.println("
}
"+interprete);
System.out.println(" temas: "+
Elemento
public class DVD extends
numeroDeTemas);
Elemento {
}
public void imprimir()
...
...
{ System.out.println("director:
}
imprimir
"+
director);

Captulo 9:
Algo ms sobre herencia

CD

...
}

...
imprimir

DVD
...

117

Captulo 9:
Algo ms sobre herencia
Bsqueda de mtodo, ligadura de mtodo o despacho de mtodo
Los controles de tipo que hace el compilador son estticos
La bsqueda del mtodo que se ha de ejecutar es dinmica (e.d. en
tiempo de ejecucin):
1. Se accede a la variable (no se puede acceder directamente a un
objeto)
2. Se encuentra el objeto
3. Se encuentra la clase del objeto
4. Se busca si tiene el mtodo invocado. Si lo tiene, se ejecuta
5. Si no lo tiene, entonces se busca en su superclase
6. Y as sucesivamente... hasta que aparezca.
(Siempre aparece, porque si no el programa no habra compilado).118

Captulo 9:
Algo ms sobre herencia
Llamada a super en mtodos
public void imprimir() {
super.imprimir();
System.out.println(" " + interprete);
System.out.println(" temas: " + numeroDeTemas);
A diferencia de la llamada a super en los constructores:
1. El nombre del mtodo hay que ponerlo.
2. La llamada a super puede ocurrir en cualquier parte del cuerpo
del mtodo.
3. No se genera ninguna llamada a super automticamente, ni es
necesario hacerla, es completamente opcional.
119

Captulo 9:
Algo ms sobre herencia
Mtodos polimrficos
elemento.imprimir();

Puede referirse al mtodo


imprimir de CD

O al mtodo imprimir de DVD

120

Captulo 9:
Algo ms sobre herencia
Mtodos de Objetc: toString
public class Elemento {
...
public String toString() {
String linea1 = titulo +
" ("+duracion+ "
minutos");
if (loTengo) return linea1 + "*\n"+"
"+
comentario + "\n";
else return linea1+"\n"+"
"+comentario+ "\n";
}
public void imprimir() {
System.out.println(toString());
}

public class CD extends Elemento {


...
public String toString() {
return super.toString()+" "
+interprete+"\n temas: "
+numeroDeTemas + "\n");
}
public void imprimir() {
System.out.println(toString());
}
121
}

Captulo 9:
Algo ms sobre herencia
Mtodos de Objetc: toString
System.out.print y System.out.println llaman a toString de sus
parmetros si no son de tipo String
public BaseDeDatos {
...
public void listar() {
for(Elemento elemento : elementos)
System.out.println(elemento);
}
Sobreescribir toString para hacer depuracin es
...
una buena idea
}

122

Captulo 9:
Algo ms sobre herencia
Otro ejemplo de herencia con sobreescritura:
World of Warcraft
Queremos aadir una habitacin transportadora (o varias)
Opcin 1
habitacionSiguiente = habitacionActual.getSalida(direccion);

if (habitacionActual.getNombre().equals("Habitacion transportadora"))
habitacionSiguiente = getHabitacionAlAzar();
else
habitacionSiguiente = habitacionActual.getSalida(direccion);
123

Captulo 9:
Algo ms sobre herencia
Otro ejemplo de herencia con sobreescritura:
World of Warcraft
Queremos aadir una habitacin transportadora (o varias)
Opcin 2
habitacionSiguiente = habitacionActual.getSalida(direccion);

if (habitacionActual == habitacionTransportadora)
habitacionSiguiente = getHabitacionAlAzar();
else
habitacionSiguiente = habitacionActual.getSalida(direccion);
124

Captulo 9:
Algo ms sobre herencia
Otro ejemplo de herencia con sobreescritura:
World of Warcraft
Queremos aadir varias habitaciones transportadoras
Opcin 3
habitacionSiguiente = habitacionActual.getSalida(direccion);

if (habitacionActual.esHabitacionTransportadora())
habitacionSiguiente = getHabitacionAlAzar();
else
habitacionSiguiente = habitacionActual.getSalida(direccion);
125

Captulo 9:
Algo ms sobre herencia
Otro ejemplo de herencia con sobreescritura:
World of Warcraft
Opcin 4
public class HabitacionTransportadora extends Habitacion {
/**
* Devuelve una habitacin al azar, independiente del
* parmetro direccin
*/
public Habitacion getSalida(String direccion) {
return encontrarHabitacionAlAzar();
}
public encontrarHabitacionAlAzar() { ... }
...
126
No ha cambiado nada en las clases Juego ni Habitacin!
}
(es mentira, pero bueno, eso dice el libro)

Captulo 10:
Ms tcnicas de abstraccin
Simulacin: Zorros y conejos

public void simularUnPaso() {


paso++;
List<Conejo> conejosNuevos = new
ArrayList<Conejo>;
for(Iterator<Conejo> it =
conejos.iterator();
it.hasNext();) {
Conejo conejo = it.next();
conejo.correr(campoActualizado,
conejosNuevos);
if (! conejo.estaVivo()) it.remove();
}

conejos.addAll(conejosNuevos);
List<Zorro> zorrosNuevos = new
ArrayList<Zorro>();
for(Iterator<Zorro> it = zorros.iterator();
it.hasNext();) {
Zorro zorro = it.next();
zorro.cazar(campo,
campoActualizado, zorrosNuevos);
if (! zorro.estaVivo()) it.remove();
}
zorros.addAll(zorrosNuevos);
Campo temp = campo;
campo = campoActualizado; 127
campoActualizado.limpiar();
visor.mostrarEstado(paso, campo);
}

Captulo 10:
Ms tcnicas de abstraccin
Clases abstractas
El cdigo de simularUnPaso es muy repetitivo. Pasa como con el
ejemplo de la BaseDeDatos. Vamos a crear una superclase de
Conejo y Zorro: Animal.
Zorro y conejo definen los campos: edad, vive y ubicacin
Si los movemos a Animal podramos definirlos como protegidos o
crear mtodos de acceso y modificacin.
Podemos renombrar el mtodo setComido de Conejo por
setMuerto, para unificar comportamientos

128

Captulo 10:
Ms tcnicas de abstraccin
Clases abstractas
Nos gustara recorrer la lista de animales una sola vez, pero los
nombres de sus mtodos son distintos.
instanceof
for(Iterator<Animal> iter = animales.iterator(); iter.hasNext();) {
Animal animal = iter.next();
if (animal instanceof Conejo) {
Conejo conejo = (Conejo) animal;
conejo.correr(campoActualizado, animalesNuevos);
}
else if (animal instanceof Zorro) {
Zorro zorro = (Zorro) animal;
zorro.cazar(campo, campoActualizado, animalesNuevos);
}
else System.out.println("Se encontr un animal desconocido");
if ( ! animal.estaVivo()) iter.remove();
}

129

Captulo 10:
Ms tcnicas de abstraccin
Clases abstractas
Nos gustara tener un cdigo ms parecido a esto:
for(Iterator<Animal> it = animal.iterator(); it.hasNext(); ){
Animal animal = it.next();
animal.actuar(campo, campoActualizado, animalesNuevos);
if (! animal.estaVivo()) it.remove();
}
Sin evaluar el tipo dinmico de las variables de objeto
Sin enmascarar tipos
Sin distincin de casos
130

Captulo 10:
Ms tcnicas de abstraccin
Clases abstractas
Para que esto funcione:
Hay renombrar los mtodos correr de Conejo y cazar de Zorro,
como actuar
El mtodo correr de Conejo, slo tiene dos parmetros:
campoActualizado y animalesNuevos. Hay que aadir un parmetro
campo para hacerlo compatible con el mtodo cazar de Zorro.
Este cdigo slo compilar si la clase Animal tiene un mtodo
llamado actuar con la signatura correcta.
En el ejemplo de la base de datos multimedia, Elemento haca cosas
en su mtodo imprimir. En nuestro caso, Animal necesita el mtodo
actuar para que el programa compile, pero no necesita hacer nada
con l.
131

Captulo 10:
Ms tcnicas de abstraccin
Clases abstractas
Nunca vamos a crear un objeto de tipo Animal que no sea un Zorro o un
Conejo. Por ese motivo, podemos declarar la clase como abstracta.
Igualmente, actuar ser un mtodo abstracto:
public abstract class Animal {
...
abstract public void actuar( Campo campoActual,
Campo campoActualizado,
List<Animal> animalesNuevos);
...
}
132

Captulo 10:
Ms tcnicas de abstraccin
Clases abstractas
No se puede crear ninguna instancia de una clase abstracta
Slo las clases abstractas pueden tener mtodos abstractos
Las clases abstractas con mtodos abstractos fuerzan a las
subclases a sobreescribir una implementacin de los supermtodos
abstractos. De lo contrario, la subclase es a su vez abstracta
La clases que no son abstractas se denominan clases concretas.

133

Captulo 10:
Ms tcnicas de abstraccin
Ms mtodos abstractos
private int reproducir() {
int nacimientos = 0;
if (puedeReproducir() && rand.nextDouble() <=
PROBABILIDAD_DE_REPRODUCCION)
nacimientos = rand.nextInt(MAX_TAMANIO_DE_CAMADA)+1;
return nacimientos;
}
La probabilidad de reproduccin es distinta entre los zorros y los
conejos: Cada uno tiene su variable (constante en este caso) de clase
correspondiente. Pero aparte de eso, lo dems es igual.
134

Captulo 10:
Ms tcnicas de abstraccin
Ms mtodos abstractos
Queremos meter el mtodo puedeReproducir en la clase Animal
Pero si lo hacemos, EDAD_DE_REPRODUCCION tendra que estar
definido en Animal
Pero eso no puede ser porque tiene dos valores distintos: uno
para los conejos y otro para los zorros
Los mtodos se pueden sobreescribir, pero los campos no
Animal
Zorro y Conejo
public boolean puedeReproducir() {
return edad >= getEdadDeReproduccion();
public int getEdadDeReproduccion() {
return EDAD_DE_REPRODUCCION;
}

}
abstract public int getEdadDeReproduccion();
135

Captulo 10:
Ms tcnicas de abstraccin
Herencia mltiple
Extensiones interesantes de la simulacin de zorros y conejos:
Nuevos animales
Humanos cazadores
Tramperos
Actor
Plantas
Clima
public abstract class Actor {
abstract public void actuar(
}
}

Campo CampoActual,
Campo CampoActualizado,
List<Actor> actoresNuevos);
136

Captulo 10:
Ms tcnicas de abstraccin
Simulador
Actor

Animal

Conejo

Cazador

Zorro
137

Captulo 10:
Ms tcnicas de abstraccin
Herencia mltiple
Todava ms flexibilidad: Dibujo selectivo
Cosas que podramos no querer mostrar en la simulacin pero importan:
Plancton
El clima
Hormigas
Caries
// permitir que todos los actores acten
for(Actor actor : actores) actor.actuar();
// dibujar todos los dibujables
for(Dibujable elemento : dibujables) elemento,dibujar();
138

Captulo 10:
Ms tcnicas de abstraccin
Dibujable

Actor

Animal

Conejo

Zorro

Cazador

Hormiga
139

Captulo 10:
Ms tcnicas de abstraccin
Interfaces
public interface Actor {
void actuar(Campo campoActual, Ubicacin ubicacin, Campo campoActualizado);
}
Se escribe interface, en lugar de class
Todos los mtodos de un interfaz son abstractos; no se
permiten mtodos con cuerpo
No tienen constructor
Solo se permiten campos constantes (public static y final).
Se pueden omitir las palabras public, static y final, pero los
campos seguirn siendo constantes
public class Zorro extends Animal implements Dibujable

140

Captulo 10:
Ms tcnicas de abstraccin
Interfaces
Actor y Dibujable son dos buenas candidatas para ser reescritas
como interfaces, Animal no.
Herencia mltiple de interfaces
public class Cazador implements Actor, Dibujable {}

141

Captulo 10:
Ms tcnicas de abstraccin
Interfaces como tipos
Si de las interfaces no se hereda cdigo, para qu las queremos?
Esto no

Pero
esto s

Una subclase hereda el cdigo (la implementacin de mtodos y


campos) de la superclase. Esto permite la reutilizacin de cdigo
y evita la duplicacin del mismo.
La subclase se convierte en un subtipo de la superclase. Esto
permite la existencia de variables polimrficas y la invocacin
polimrfica de mtodos.
En otras palabras, permite que los casos especiales de objetos se
traten de manera uniforme.
142

Captulo 10:
Ms tcnicas de abstraccin
Interfaces como tipos
Si de las interfaces no se hereda cdigo, para qu las queremos?
Las interfaces no brindan el primer beneficio (ya que no contienen
ninguna implementacin), pero s ofrecen el segundo:
Una interfaz define un tipo tal como lo hace una (super) clase. Eso
quiere decir que las variables pueden ser definidas del tipo de la
interfaz, aun cuando no pueda existir un objeto de tal tipo.

Actor es ahora una interfaz, pero aun podemos declarar una


variable de tipo Actor en la clase Simulador. El ciclo de la
simulacin todavia funciona sin ningn cambio

143

Captulo 10:
Ms tcnicas de abstraccin
Interfaces como especificaciones
<<interfaz>>
List
implementa

ArrayList

implementa

LinkedList

La caracterstica ms importante de las interfaces es que


separan completamente la definicin de la funcionalidad
Tanto ArrayList como LinkedList proveen la funcionalidad de List,
pero de forma distinta: P.e. el acceso aleatorio a un elemento es
ms rpido en ArrayList, pero la eliminacin de un elemento es
144
ms rpido en LinkedList

Captulo 10:
Ms tcnicas de abstraccin
Interfaces como especificaciones
Si se usan correctamente, se puede mejorar fcilmente la eficiencia
private List<Tipo> miLista = new ArrayList<Tipo>();
Se puede probar esta alternativa cambiando una sola cosa:
private List<Tipo> miLista = new LinkedList<Tipo>();

145

Captulo 10:
Ms tcnicas de abstraccin
Interfaces para rebajar el acoplamiento
Las interfaces permiten reducir el acoplamiento, de forma que se
puedan hacer diversas implementaciones sin afectar al resto del
desarrollo. En el caso del visor del campo de caza podramos
manejar varias alternativas:
1. Un tablero con casillas, donde cada casilla representa los actores
dibujables
2. Una grfica donde el eje x muestre el tiempo y el y el nmero de
animales o actores (cada uno con su color).
3. Imprimir secuencias de texto por la consola: Fcil de
implementar y permite guardar la salida en un fichero.
146

Captulo 10:
Ms tcnicas de abstraccin
Interfaces para rebajar el acoplamiento

147

Captulo 10:
Ms tcnicas de abstraccin
Interfaces para rebajar el acoplamiento
Para ello deberamos convertir la clase VisorDelSimulador en una
interfaz:
import java.awt.color;
public interface VisorDelSimulador {
Class?
void setColor(Class cl, Color color);
boolean esViable(Campo campo);
void mostrarEstado(int paso, Campo campo);
}
Y renombrar la actual clase VisorDelSimulador como VisorAnimado:
public class VisorAnimado extends JFrame implements VisorDelSimulador {...}
148

Captulo 10:
Simulador
Ms vista.setColor(Conejo.class,
tcnicas de aColor.orange);
bstraccin
Class como tipo

vista.setColor(Zorro.class, Color.blue);

VisorAnimado
for(int fila = 0; fila < Campo.getLargo(); fila++) {
for(int col = 0; col < campo.getAncho(); col++) {
Object animal = campo.getObjectAt(fila, col);
if (animal != null) {
estadisticas.incrementaCuenta(animal.getClass());
visorDelCampo.dibuja(col, fila, getColor(animal.getClass()));
}
else {
visorDelCampo.dibuja(col, fila, COLOR_VACIO);
}
}
149
}

Captulo 11:
Construir interfaces grcas de usuario
Desambiguacin. Una interfaz puede ser:
1. La parte pblica de una clase
2. Una "interface" de Java
3. Una interfaz grfica de usuario (GUI)
Las preguntas fundamentales de una GUI
Componentes: Qu podemos mostrar en la pantalla?
Gestores de disposicin: Dnde mostramos los componentes?
Manejo de eventos: Como podemos reaccionar a un cambio?
150

Captulo 11:
Construir interfaces grcas de usuario
AWT y Swing
AWT: De Java 1, que era una mierda: Button, Frame, Menu
Swing: Las clases empiezan (casi) todas por J, mucho mejor, donde
va a parar: JButton, JFrame, JMenu...

151

El proyecto del da: Visor de imgenes

Captulo 11:
Construir interfaces grcas de usuario

152

Captulo 11:
Construir interfaces grcas de usuario
El proyecto del da: Visor de imgenes

153

Captulo 11:
Construir interfaces grcas de usuario
Crear una ventana
import java.awt.*;
import java.awt.event.*;
import javax.swing;
public class VisorDeImagen {
private JFrame ventana;
public VisorDeImagen() { construirVentana(); }
private void construirVentana() {
ventana = new JFrame("Visor de imgenes");
Container panelContenedor = ventana.getContentPane();
JLabel etiqueta = new JLabel("Soy una etiqueta");
panelContenedor.add(etiqueta);
ventana.pack();
ventana.setVisible(true);
}
}

154

Captulo 11:
Construir interfaces grcas de usuario
Las partes de una ventana
Barra de ttulo

Barra de men

Panel contenedor

Ventana
155

Captulo 11:
Construir interfaces grcas de usuario
Agregar menes (oh yeah!): La teora

JMenuBar: La barra. Una como mximo.

JMenu: Un slo men, como "Archivo", "Edicin" o "Ayuda"

JMenuItem: Los elementos de cada men, como "Abrir" o "Guardar"

156

Captulo 11:
Construir interfaces grcas de usuario
Agregar menes (oh yeah!): La prctica

JMenuBar barraDeMenu = new JMenuBar();


ventana.setJMenuBar(barraDeMenu);
...
JMenu menuArchivo = new JMenu("Archivo");
barraDeMenu.add(menuArchivo);
...
JMenuItem elementoAbrir = new JMenuItem("Abrir");
menuArchivo.add(elementoAbrir);
JMenuItem elementoSalir = new JMenuItem("Salir");
menuArchivo.add(elementoSalir);
As se muestra el men, pero todava no hace nada...

157

Captulo 11:
Construir interfaces grcas de usuario
Manejo de eventos: Recepcin centralizada
Los items del menu producen eventos (ActionEvents)
Estos eventos deben ser escuchados con un "ActionListener"
Debemos decir que nuestra clase VisorDeImagen implementa la
interfaz ActionListener
Hay que implementar un mtodo con la siguiente signatura:
public void actionPerformed(ActionEvent e)
es el nico mtodo que se define en la interfaz ActionListener
Hay que invocar al mtodo addActionListener de todos los JMenuItem:
elementoAbrir.addActionListener(this);
elementoSalir.addActionListener(this);
Qu contiene un ActionEvent? Una cadena de texto, el estado de las teclas
modificadoras (CTRL, ALT, ESC) y el momento exacto del evento, y ms...158

Captulo 11:
Construir interfaces grcas de usuario
Manejo de eventos: Recepcin centralizada
En el mtodo actionPerformed tendramos cosas como:

...
if (evento.getActionCommand().equals("Abrir")) ...
if (evento.getActionCommand().equals("Salir")) ...
if (evento.getActionCommand().equals("Guardar")) ...
....

Pero entonces tendramos un mtodo gigantesco, mal estructurado y


volveran los problemas de traduccin, de aadir nuevos elementos
al men, etc...
159

Captulo 11:
Construir interfaces grcas de usuario
Clases internas
class ClaseEnvolvente {
...
class ClaseInterna {
...
}
}
Las instancias de las clases internas se adjuntan a las
instancias de la clase envolvente
Las clases internas pueden acceder a los campos y mtodos de
la clase envolvente, aunque sean privados
La convencin es escribir las clases internas al final de las
160
clases envolventes, al final de los mtodos

Captulo 11:
Construir interfaces grcas de usuario
Manejo de eventos:
Recepcin independiente (I)
class VisorDeImagen {
...
class AbrirActionListener implements ActionListener {
public void actionPerformed(ActionEvent evento) {
// lleva a cabo la accin abrir
}
class salirActionListener implements ActionListener {
public void actionPerformed(ActionEvent evento) {
// lleva a cabo la accin de salir
}
}
}
161

Captulo 11:
Construir interfaces grcas de usuario
Manejo de eventos:
Recepcin independiente (I)
Ahora la clase VisorDeImagen ya no tiene el mtodo actionPerformed, en
lugar de eso, vamos a crear instancias de las clases internas, que s
lo implementan:
JMenuItem elementoAbrir = new JMenuItem("Abrir");
elementoAbrir.addActionListener(new AbrirActionListener());
...
JMenuItem elementoSalir = new JMenuItem("Salir");
elementoSalir.addActionListener(new SalirActionListener());
As no necesitamos un mtodo actionPerformed enorme y con un montn
de if. Por otro lado, reducimos notablemente el acoplamiento.
162

Captulo 11:
Construir interfaces grcas de usuario
Clases internas annimas
JMenuItem elementoAbrir = new JMenuItem("Abrir");
elementoAbrir.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
archivoAbrir();
}
});

Declaramos la clase y definimos una instancia en el mismo paso


La clase est justo en el sitio en el que se necesita
Como slo vamos a crear una instancia, no necesita nombre
Lo que s necesita es un supertipo
Puede acceder a los parmetros y variables locales del mtodo,
163
pero las variables locales deben ser definidas como final

Por qu?

Captulo 11:
Construir interfaces grcas de usuario
Manejo de eventos:
Recepcin independiente (II)
El mtodo de las clases internas annimas permite eliminar
completamente el mtodo actionPerformed centralizado
Para cada evento creamos un oyente de accin independiente,
hecho a medida para cada elemento del men.
Este oyente puede llamar a un mtodo especfico de la clase
envolvente para implementar la funcin correspondiente
La estructura es ms cohesiva y extensible. Ahora es muy fcil
aadir cdigo para aadir otro elemento del men, su oyente de
accin y el mtodo manejador de la funcin
Las clases internas annimas dificultan la lectura del cdigo y
se deben restringir a modismos muy determinados, como el manejo
de eventos
164

Captulo 11:
Construir interfaces grcas de usuario
Visor de imgenes 1.0

165

Captulo 11:
Construir interfaces grcas de usuario
Visor de imgenes 1.0
VisorDeImagen: Clase principal
ImagenOF: Subclase de BufferedImage, proporciona
1. getPixel
2. setPixel
3. getHeight
4. getWidth
AdministradorDeArchivos:
1. Leer archivo
2. Guardar archivo (con caja de dilogo)
PanelDeImagen: Subclase de JComponent (hereda el mtodo paint)
1. setImage(ImagenOF) muestra en pantalla la imagen
166

Visor de imgenes 1.0

Captulo 11:
public
class VisorDeImagen
{
Construir
interfaces
grcas de usuario
private JFrame
ventana;
private PanelDeImagen panelDeImagen;
// ...
private void archivoAbrir() {
ImagenOF imagen = AdministradorDeArchivos.getImagen();
panelDeImagen.setImagen(imagen);
ventana.pack();
}
private construirVentana() {
ventana = new JFrame("Visor de imgenes");
construirBarraDeMenu(ventana);
Container panelContenedor = ventana.getContentPane();
panelDeImagen = new PanelDeImagen();
panelContenedor.add(panelDeImagen);
ventana.pack();
ventana.setVisible(true);
}

...
}

167

Captulo 11:
Construir interfaces grcas de usuario
Visor de imgenes 1.0
An faltan algunas cosas para nuestra versin 1.0:
Queremos dos etiquetas; una arriba, que muestre el nombre del
archivo de imagen y otra abajo que muestre el estado
Queremos agregar un men filtro que contenga unos filtros que
modifiquen la apariencia de la imagen
Queremos aadir tambin un men Ayuda que contenga un
elemento Acerca del Visor de Imgenes que muestre la versin y los
crditos
Container panelContenedor = ventana.getContentPane();
etiquetaNombreDeArchivo = new JLabel();
panelContenedor.add(etiquetaNombreDeArchivo);
panelDeImagen = new PanelDeImagen();
panelContenedor.add(panelDeImagen);
etiquetaEstado = new JLabel("Versin 1.0");
panelContenedor.add(etiquetaEstado);

168

Captulo 11:
Construir interfaces grcas de usuario
Gestores de disposicin
Adnde van los componentes cuando se aaden con un add a un
contenedor?
Depende del gestor de disposicin que use el contenedor

En Swing hay cuatro gestores de disposicin:


1. FlowLayout
2. BorderLayout
3. GridLayout
4. BoxLayout

169

Captulo 11:
Construir interfaces grcas de usuario
FlowLayout

Los componentes se aaden de izquierda a derecha


Cada componente se dibuja con su tamao preferido
Los componentes se dibujan centrados en el contenedor
Si no hay suficiente espacio en una lnea para que quepan
todos, se aade una nueva lnea
Se puede cambiar la alineacin a izquierda o a derecha

170

Captulo 11:
Construir interfaces grcas de usuario
BorderLayout
BorderLayout usa cinco componentes: CENTER, NORTH, EAST,
SOUTH y WEST
No es necesario usar todas las posiciones
Parece una chorrada, pero se usa mucho
En BlueJ, sin ir ms lejos
Si se modifica el tamao, el campo central cambia de altura y
anchura,
Los campos EAST y WEST cambian su altura, pero no su anchura
Los campos NORTH y SOUTH cambian de anchura, pero no de altura

171

Captulo 11:
Construir interfaces grcas de usuario
GridLayout
Grid = rejilla (en espaol) = grilla (en argentino)
Se puede especificar el nmero de filas y de columnas
y los componentes se colocan en la rejilla
Todos los componentes tienen el mismo tamao (que es
el tamao del componente ms gordo)
Bueno para hacer que todos los botones sean igual de grandes
Malo para todo lo dems

172

Captulo 11:
Construir interfaces grcas de usuario
BoxLayout
Bsicamente, se pueden apilar los componentes, bien de forma
vertical o de forma horizontal
A diferencia de FlowLayout, no crea nuevas lineas (ni columnas)
Cada componente puede medir lo que quiera, cosa que no es
evidente en los dems casos
Se puede alinear al centro, la izquierda o la derecha

173

Captulo 11:
Construir interfaces grcas de usuario
Contenedores anidados

En mi casa nunca
faltan unos
contenedores
anidados

174

Captulo 11:
Construir interfaces grcas de usuario
Contenedores anidados

175

Captulo 11:
Construir interfaces grcas de usuario
Contenedores anidados

176

Captulo 11:
Construir interfaces grcas de usuario
Contenedores anidados

177

Captulo 11:
Construir interfaces grcas de usuario
Cada tipo de componente tiene su gestor de disposicin por defecto:
para JFrame es un BorderLayout, para JPanel es FlowLayout
Para el visor de imgenes vamos a usar el BorderLayout (por defecto)

Container panelContenedor = ventana.getContentPane();


panelContenedor.setLayout(new BorderLayout());
etiquetaNombreDeArchivo = new JLabel();
panelContenedor.add(etiquetaNombreDeArchivo), BorderLayout.NORTH);
panelDeImagen = new PanelDeImagen();
panelContenedor.add(panelDeImagen, BorderLayout.CENTER);
etiquetaEstado = new JLabel("Versin 1.0");
panelContenedor.add(etiquetaEstado, BorderLayout.SOUTH);
178

Captulo 11:
Construir interfaces grcas de usuario
Esquema de filtro

int alto = getHeight();


int ancho = getWidth();
for(int y = 0; y < alto; y++) {
Color pixel = getPixel(x, y);
// alteramos el valor del pixel
setPixel(x, y, pixel);
}
}

La clase VisorDeImagen
public class VisorDeImagen {
...
private void aplicarOscuro() {
if (imagenActual != null) {
imagenActual.oscuro();
ventana.repaint();
mostrarEstado("Filtro
aplicado: Oscuro");
}
else mostrarEstado("No
hay ninguna imagen
cargada");
179
}
}

Captulo 11:
Construir interfaces grcas de usuario
El filtro oscuro en la clase ImagenOF

public class ImagenOF extends BufferedImage {


private void oscuro() {
int alto = getHeight();
int ancho = getWidth();
for(int y = 0; y < alto; y++)
for(int x = 0; x < ancho; x++)
setPixel(x, y, getPixel(x, y).darker());
}
...
}
180

Captulo 11:
Construir interfaces grcas de usuario
Acerca de
Vamos a mostrar el mensaje de acerca de con una caja de
dilogo.
Si el dilogo es "modal", no se puede hacer nada ms
hasta que se cierre el dilogo
Si no es modal, entonces las dems ventanas de la
aplicacin siguen estando accesibles.
Una buena opcin es usar la clase JOptionPane. Esta clase
sirve para tres tipos estndar de dilogos:
Dilogo de mensaje: Muestra un mensaje y tiene un botn
de OK.
Dilogo de confirmacin: Sirve para preguntar algo y
contestar con botones S, No y Cancelar.
Dilogo de entrada: Una caja de texto para que el usuario
escriba algn texto.

181

Captulo 11:
Construir interfaces grcas de usuario
Acerca de
private void mostrarAcercaDe() {
JOptionPane.showMessageDialog(ventana,
"Visor de imgenes\n" + VERSION,
"Acerca del Visor de imgenes",
JOptionPane.INFORMATION_MESSAGE);
}

Con esto completamos la versin 1.0!


182

Captulo 11:
Construir interfaces grcas de usuario
Visor de imgenes 2.0
Para aadir un nuevo filtro, ahora mismo necesitamos:
1. Agregar un elemento al men
2. Agregar un mtodo que maneje la activacin del men
3. Agregar una implementacin del filtro en ImagenOF
private void aplicarClaro() {
if (imagenActual != null) {
imagenActual.claro();
ventana.repaint();
mostrarEstado("Filtro
}
else mostrarEstado("No
hay ninguna imagen
cargada");
}
}

Se parece mucho a
aplicarOscuro
aplicado:
claro");

183

Captulo 11:
Construir interfaces grcas de usuario
Visor de imgenes 2.0
Vamos a usar la herencia para reutlizar cdigo: Ahora
<<Abstract>>
Filtro

FiltroOscuro

FiltroClaro

FiltroUmbral

184

Captulo 11:
Construir interfaces grcas de usuario
public abstract class Filtro {
private String nombre;
public Filtro(String nombre) {
this.nombre = nombre;
}
public String getNombre() {
return nombre;
}
public abstract void aplicar(
ImagenOF imagen);

public abstract class FiltroOscuro extends


Filtro {
public FiltroOscuro(String nombre) {
super(nombre) };
public voir aplicar(ImagenOF imagen) {
public aplicar(ImagenOF, imagen) {
int alto = imagen.getHeight();
int ancho = imagen.getWidth();
for(int y = 0; y < alto; y++)
for(int x = 0; x <ancho; x++)
imagen.getPixel(x, y,
imagen.getPixel(x,y).darker());
}
...
}
185

Captulo 11:
Construir interfaces grcas de usuario
public class VisorDeImagen {
...
private List<Filtro> filtros;
public VisorDeImagen() {
filtros = crearFiltros();
...
}
private List<Filtro> crearFiltros() {
List<Filtro> listaDeFiltros = new
ArrayList<Filtro>();
listaDeFiltros.add(new FiltroOscuro("Oscuro");
listaDeFiltros.add(new FiltroClaro("Claro");
listaDeFiltros.add(new FiltroUmbral("Umbral");
return listaDeFiltros;
}
...
}

Faltan dos cosas an:


1. Cambiar el cdigo
que crea elementos
del men para que
recorra la lista de
filtros y los aada al
men, usando el
mtodo getNombre
para dar "nombre"
al men.
2. Escribir un mtodo
genrico
aplicarFiltro que
recibe un filtro
como parmetro y
lo aplica a la
imagen actual. 186

Captulo 11:
Construir interfaces grcas de usuario
Visor de imgenes 3.0: Botones

187

Captulo 11:
Construir interfaces grcas de usuario
Visor de imgenes 3.0: Botones
Hasta ahora, estamos usando un BorderLayout con la zona WEST
vaca.
Podemos llenar esa zona, pero slo se puede poner un
componente, y nosotros queremos poner dos (dos botones,
concretamente)
La solucin parece sencilla, poner un JPanel en WEST y despus
aadir los botones
// Crear una barra de herramientas con botones
JPanel barraDeHerramientas = new JPanel();
botonEncoger = new JButton("Encoger");
barraDeHerramientas.add(botonEncoger);
botonAgrandar = new JButton("Agrandar");
barraDeHerramientas.add(botonAgrandar);
panelContenedor.add(barraDeHerramientas, BorderLayout.WEST);

188

Captulo 11:
Construir interfaces grcas de usuario
Visor de imgenes 3.0: Botones
Pero no lo es porque el FlowLayout que usa por defecto JPanel
nos pone los botones uno al lado del otro, y eso no es lo que
queremos.
Podemos arreglarlo cambiando el gestor de disposicin del
JPanel, de forma que sea un GridLayout con una fila y las
columnas que hagan falta:
barraDeHerramientas.setLayout(new GridLayout(0, 1));
O incluso:
JPanel barraDeHerramientas = new JPanel(new GridLayout(0, 1));
189

Captulo 11:
Construir interfaces grcas de usuario
Visor de imgenes 3.0: Botones
Pero ahora los botones son enormes: El BorderLayout ocupa todo
el espacio de las zonas y el GridLayout cambia el tamao de su
componentes hasta que ocupen todos el espacio disponible y por
eso los botones son demasiado grandes.
FlowLayout no cambia el tamao de los componentes para usar
todo el espacio.
La solucin es usar el Border, meter dentro un panel con Flow y
dentro otro panel con Grid
JPanel barraDeHerramientas = new JPanel(new GridLayout(0,1));
botonEncoger = new JButton("Encoger");
Te lo
botonAgrandar = new JButton("Agrandar");
dije J
barraDeHerramientas.add(botonEncoger);
barraDeHerramientas.add(botonAgrandar);
JPanel panelFlow = new JPanel();
190
panelFlow.add(barraDeHerramientas);
panelContenedor.add(panelFlow, BorderLayout.WEST);

Captulo 11:
Construir interfaces grcas de usuario
Visor de imgenes 3.0: Y dale molino
Queremos agregar algunos bordes para dar el toque final:
1. Un poco de espacio alrededor de la parte exterior de la ventana
2. Otro poco entre los componentes de la ventana
3. Y aadir una lnea alrededor de la imagen
JPanel panelContenedor = (JPanel) ventana.getContentPane();
panelContenedor.setBorder(new EmptyBorder(6, 6, 6, 6);
panelContenedor.setLayout(new BorderLayout(6, 6);
panelDeImagen = new PanelDeImagen();
panelDeImagen.setBorder(new EtchedBorder);
panelContenedor.add(panelDeImagen, BorderLayout.CENTER);
191

Captulo 12:
Manejo de errores
Proyecto: Libreta de direcciones
Programacin defensiva: Asumir que el entorno de ejecucin es hostil
y los objetos cliente usan los objetos servidores de forma inadecuada.
Ejemplo: Eliminar una clave vaca en la libreta de direcciones, de quin
es la culpa?
En este caso, el servidor no ha realizado ninguna validacin de los
datos, lo cual no es recomendable.
Otros potenciales problemas:
El mtodo agregarContacto debe controlar que su argumento no sea
null
El mtodo modificarContacto debe controlar que la clave vieja exista
192
El mtodo buscar debe controlar que la clave no sea null

Captulo 12:
Manejo de errores
Informar de errores en la clase servidor
No basta con evitar el error en s (un desbordamiento de un array,
por ejemplo) es conveniente notificar de que sea producido una
situacin anmala. Dicha notificacin se puede hacer:
Al usuario: Mediante System.out (la consola), por ejemplo. Sin
embargo:
Muchas aplicaciones se ejecutan sin control humano y
cualquier mensaje de error ser pasado por alto. Podra no
haber ni un monitor en el que mostrar el error.
Aunque haya usuario, es raro que este est en condiciones
de hacer algo constructivo al respecto.
A la clase cliente:
El servidor puede usar un valor de retorno concreto para
indicar que algo ha ido mal.
El servidor puede lanzar una excepcin.

193

Captulo 12:
Manejo de errores
Excepciones
El mtodo del lanzamiento de excepciones tiene varias ventajas:
No se necesita devolver un valor de retorno especial
De hecho sirve para un mtodo que no devuelve nada (void)
En realidad se puede usar en cualquier sitio
Es difcil que el cliente ignore el error, ya que si lo hace se
detendr la ejecucin del programa.
throw:

throw new TipoDeExcepcion ("cadena opcional");

public DatosDelContacto getContacto(String clave) {


if (clave == null) throw new NullPointerException("clave null
en getContacto");
return libreta.getClave();
}

194

Captulo 12:
Manejo de errores
Tipos de excepciones

Comprobadas (manejables)
Se trata de de errores que hemos previsto que puedan suceder en un
uso normal del programa; el usuario ha introducido datos incorrectos,
hemos guardado un fichero pero el disco estaba lleno, se trata de
situaciones a las que se supone que podemos hacer frente. Podemos
hacer algo til en estos casos
No comprobadas (no manejables)
Normalmente no haya nada que podamos hacer y el programa casca
sin remisin. Puede ser un error de programacin, como si accedemos
a un elemento inexistente de un array, en cuyo caso hay que
reprogramar. O puede ser que necesitemos memoria para seguir y no
quede, qu le vamos a hacer?
195

Captulo 12:
Manejo
de errores
Jerarqua de excepciones
Throwable

Error

MiExcepcionComprobada

Exception

RuntimeExcepcion

Clases estndar
Clases definidas por el usuario

MiExcepcionNoComprobada
196

Captulo 12:
Manejo
de errores
Excepciones no comprobadas
Son unas hijas de RuntimeException
No hay que hacer nada respecto del compilador (comentario idiota
copiado del libro)
Como la idea es que el programa casca, no hay mucho ms que decir
llamado
if (key == null) throw NullPointerException("Clave null en getContacto");
else return libreta.get(clave);
llamador
DatosDelContacto datos = libreta.getContacto(null);
// La siguiente sentencia no ser ejecutada
String telefono = datos.getTelefono();
197

Captulo 12:
Manejo
de errores
Excepciones comprobadas
Son descendientes de Exception, pero no de RuntimeException
El compilador obliga a declarar en la signatura si el mtodo lanza
excepciones comprobadas (opcional en el caso de las no
comprobadas):
public void grabarEnArchivo(String archivoDestino) throws IOException
El mtodo invocador de un mtodo que puede lanzar una excepcin
comprobada debe proporcionar un tratamiento para dicha excepcin:
String nombreDeArchivo = null;
try {
nombreDeArchivo = nombre-que-se-pide-al-usuario
libreta.grabarEnArchivo(nombreDeArchivo);
}
198
catch (IOException e) {
System.out.println("Imposible grabar en " + nombreDeArchivo);
}

Captulo 12:
Manejo de errores
Usar varias excepciones comprobadas

public void procesar() throws EOException, FileNotFoundException


try { ...
ref.procesar();
...
}
catch(EOException e) {
// Tomar las medidas adecuadas
// para el fin de archivo
... }
catch(FileNotFound Exception e) {
// Tomar las medidas adecuadas
// para fichero no encontrado
... };

try { ...
ref.procesar();
...
}
catch(Exception e) {
// Tomar las medidas
adecuadas // para cualquier cosa
... }
199

Captulo 12:
Manejo de errores
Propagar una excepcin

Un mtodo invocador puede no manejar la excepcin y dejar la


maneje el invocador del invocador (y as sucesivamente) . A esto se le
llama propagar la excepcin. Si al final nadie la maneja, el programa
termina.
La clasula finally
La sentencia try puede incluir un tercer componente opcional; la
clasula finally. Dicha clasula incluye cdigo que se debe ejecutar al
final del bloque tanto si se ha lanzado una excepcin como si no.
La combinacin try-finally tambin es posible sin clasula catch
La clasula finally se ejecuta siempre, incluso si se ha hecho un return
dentro del try o del catch.
Si se lanza una excepcin en el bloque try pero no se captura, tambin
200
se ejecuta la clasula finally.

Captulo 12:
Manejo de errores
Definir nuevas clases de excepcin
Si las excepciones estndar no solucionan satisfactoriamente una
situacin, es posible crear nuevas excepciones, comprobadas o no.
Lo nico que hay que hacer es derivarlas de la clase correcta: Las
excepciones comprobadas deben descender de Exception (pero no de
RuntimeException) y las no comprobadas de RuntimeException
Todas las excepciones estndar soportan el uso de una cadena de
texto para diagnstico, pero si se define una nueva excepcin, parece
lgico aadir ms informacin, en particular si queremos resolver el
problema adems de diagnsticarlo.

201

Captulo 12:
Manejo de errores
Definir nuevas clases de excepcin

public class NoCoincideContactoException extends Exception {


// La clave que no tiene coincidencias
private String clave;
public NoCoincideContactoException(String clave) { this.clave = clave };
public String getClave() { return clave; }
public String toString() { return "No se encontraron datos que coincidan
con : " + clave;
}
}
202

203

204

205

Vous aimerez peut-être aussi