PR18 - Funciones y predicados

Anuncio
FUNDAMENTOS DE PROGRAMACIÓN
PRÁCTICA 18: FUNCIONES Y PREDICADOS
Curso: 2010/11
Versión: 1.0.0
OBJETIVOS
Aprender a generalizar determinados esquemas de tratamiento secuencial mediante
el encapsulamiento de predicados y funciones.
Implementar predicados y funciones.
Utilizar combinaciones de funciones y predicados.
PREPARACIÓN DE LA PRÁCTICA
Descargue el fichero Practica18Alumno.zip de la página de la asignatura y
descomprímalo en su workspace. Ejecute Eclipse e importe el proyecto que acaba de
descomprimir.
EJERCICIO 1: FUNCIONES
1. En este ejercicio vamos a implementar algunos métodos estáticos que trabajan sobre
un array de objetos de tipo Fecha. Observaremos que, en ocasiones, el código que
necesitamos para solucionar distintos problemas es muy parecido. Buscaremos
entonces algún mecanismo que nos permita solucionar problemas parecidos
utilizando siempre el mismo código.
a) Defina un método estático getDias en la clase Fechas que reciba un array de
Fecha como parámetro y devuelva un vector de Integer con la propiedad día de
cada una de las fechas del array.
b) Defina un método estático getMeses que reciba un array de Fecha como
parámetro y devuelva un vector de Integer con la propiedad mes de cada una de
las fechas del array.
c) En el método main de la clase TestFechas, muestre por pantalla los días de las
fechas del array fechas utilizando el método getDias de la clase Fechas. Muestre
también los meses de las fechas utilizando el método getMeses.
2. Si observa el código de los métodos getDias y getMeses observará que son muy
parecidos. Para poder generalizar ambos problemas y resolverlos mediante un sólo
método, necesitamos encapsular el trozo de código que varía entre ambos métodos.
Esto lo haremos utilizando la interfaz Function incluida en la librería Guava.
public interface Function<F,T>{
T apply(F o);
}
Una función dispone de un método apply que permite obtener algún resultado de
tipo T a partir de un objeto de tipo F. En el método getDias, para cada fecha del
array, obteníamos un Integer (los días). Igualmente, en el método getMeses, para
cada fecha del array obteníamos un Integer (los meses). Usando la interfaz Function
podemos generalizar ambos problemas e implementarlos mediante un sólo método.
a) Defina un método estático getFuncion en la clase Fechas que reciba como
parámetro un array de Fecha y una Function<Fecha,Integer> y devuelva un
vector de Integer con los resultados de aplicar la función a cada una de las fechas
del array.
Práctica 18: Funciones y predicados
2
b) En el paquete fecha, defina una clase de nombre FuncionFechaDia que
implemente la interfaz Function<Fecha,Integer>. El método apply debe
devolver la propiedad día de la fecha recibida como parámetro.
c) En el paquete fecha, defina una clase de nombre FuncionFechaMes que
implemente la interfaz Function<Fecha,Integer>. El método apply debe
devolver la propiedad mes de la fecha recibida como parámetro.
d) En el método main de la clase TestFechas, muestre por pantalla los días y los
meses de las fechas del array fechas. Para ello, construya sendos objetos de las
clases FuncionFechaDia y FuncionFechaMes e invoque adecuadamente al
método getFuncion de la clase Fechas.
EJERCICIO 2: PREDICADOS
1. En este ejercicio implementaremos algunos métodos estáticos más que trabajarán
con arrays de fechas. Al igual que hicimos en el ejercicio 1, trataremos de encontrar
algún mecanismo para generalizar problemas parecidos e implementarlos en un solo
método.
a) Defina un método estático existeMes en la clase Fechas que reciba como
parámetro un array de Fecha y un Integer mes y devuelva true si y sólo si existe
en el array alguna fecha con dicho mes.
b) Defina un método estático existeAnterior en la clase Fechas que reciba como
parámetro un array de Fecha y un Integer año y devuelva true si y sólo si existe
en el array alguna fecha anterior a dicho año.
c) En el método main de la clase TestFechas, utilice el método existeMes para
decidir si el array fechas contiene alguna fecha cuyo mes sea enero. Decida
también si el array contiene alguna fecha anterior a 1980, usando el método
existeAnterior.
2. Si observa los métodos existeMes y existeAnterior, verá que ambos tienen la misma
estructura. La única diferencia es la expresión lógica utilizada como condición de la
sentencia if. Para poder generalizar ambos problemas e implementarlos mediante un
único método, vamos a utilizar la interfaz Predicate incluida en la librería Guava.
public interface Predicate<T>{
boolean apply(T o);
}
Un predicado no es más que una función que a partir de un objeto de tipo T
devuelve un valor lógico. Un predicado sirve para encapsular cierta propiedad que
un objeto de tipo T puede cumplir o no. En el método existeMes, se comprueba si
existe alguna fecha que cumpla la propiedad de tener un mes determinado. En el
método existeAnterior, se comprueba si existe alguna fecha que cumpla la propiedad
de ser anterior a un año determinado. Podemos por tanto generalizar ambos métodos
usando la interfaz Predicate.
a) Defina un método estático existePropiedad en la clase Fechas que reciba como
parámetro un array de Fecha y un Predicate<Fecha> y devuelva true si y sólo si
existe alguna fecha en el array que cumpla la propiedad definida por el
predicado.
b) En el paquete fecha, defina una clase de nombre PredicadoFechaMes que
implemente la interfaz Predicate<Fecha>. Incluya un método constructor que
Práctica 18: Funciones y predicados
3
reciba un valor entero y lo almacene en un atributo mes. Defina el método apply,
que debe devolver true si la fecha recibida por parámetro corresponde al mes
almacenado en el atributo mes.
c) En el paquete fecha, defina una clase de nombre PredicadoFechaAnterior que
implemente la interfaz Predicate<Fecha>. Incluya un método constructor que
reciba un valor entero y lo almacene en un atributo año. Defina el método apply,
que debe devolver true si la fecha recibida por parámetro es anterior al año
almacenado en el atributo año.
d) En el método main de la clase TestFechas, utilizando el método
existePropiedad, escriba el código necesario para decidir si existe alguna fecha
en el array fechas cuyo mes sea febrero. Usando el mismo método, decida
también si existe alguna fecha en el array anterior a 2000.
EJERCICIO 3: ACCIONES
1. En algunas ocasiones, el trozo de código que hay que encapsular para conseguir
generalizar problemas parecidos e implementarlos mediante un solo método,
consiste en una o varias sentencias que no devuelven ningún objeto. Por ejemplo,
podríamos tener un método que simplificara todos los racionales contenidos en un
array, o un método que cambiara por un 1 el denominador de dichos racionales. Para
generalizar este tipo de problemas, utilizaremos la misma interfaz del ejercicio 1
Function, haciendo que devuelva un valor de tipo Void.
a) Defina un método aplicaAccion en la clase Personas que reciba como
parámetros un array de Persona y una Function<Persona,Void> e invoque al
método apply de la función sobre cada elemento del array.
b) En el paquete persona, defina una clase de nombre AccionPersonaCumpleanyos
que implemente la interfaz Function<Persona,Void>. Defina el método apply
para que se incremente en uno la edad de la persona recibida como parámetro.
c) En el método main de la clase TestPersonas, escriba el código necesario para
incrementar en un año la edad de todas las personas del array personas,
utilizando el método aplicaAccion de la clase Personas.
2. Ampliemos un poco la funcionalidad del método aplicaAccion:
a) Defina un método aplicaAccion en la clase Personas que reciba, además del
array de Persona y la Function<Persona,Void>, un Predicate<Persona>, de
manera que el método apply será invocado sólo sobre aquellas personas del
array que cumplan el predicado.
b) En el paquete persona, defina una clase de nombre PredicadoPersonaMayorDe
que implemente la interfaz Predicate<Persona>. Incluya un constructor que
reciba un entero y lo almacene en un atributo edad. El método apply devolverá
cierto si la persona recibida es mayor que la edad especificada en el atributo
edad.
c) En el método main de la clase TestPersonas, escriba el código necesario para
hacer cumplir años a aquellas personas del array personas que sean mayores de
21 años.
Práctica 18: Funciones y predicados
4
EJERCICIO 4: COMBINACIÓN DE PREDICADOS
1. A partir de predicados que tengamos implementados, puede resultarnos útil obtener
nuevos predicados como combinación de ellos. En concreto, cuando necesitemos
encapsular una propiedad consistente en la conjunción de otras dos propiedades que
ya tenemos implementadas como predicados, podemos usar el siguiente método
estático de la clase Predicates:
Predicate<T> and(Predicate<? super T> first, Predicate<? super T> second);
Basta invocar al método anterior pasándole como parámetros dos predicados
previamente creados, p1 y p2, para obtener un predicado que sólo será cierto para
aquellos objetos para los que p1 y p2 sean ciertos.
a) En la clase Personas, defina un método getString que reciba un array de
Persona, un Predicate<Persona> y una Function<Persona,String>, y devuelva
un vector de String con el resultado de aplicar la función a aquellas personas del
array que cumplan el predicado.
b) Defina una clase de nombre FuncionPersonaNombre en el paquete persona, que
implemente la interfaz Function<Persona,String>. El método apply debe
devolver el nombre y apellidos de la persona pasada como parámetro.
c) Defina una clase de nombre PredicadoPersonaMenorDe en el paquete persona,
que implemente la interfaz Predicate<Persona>. Incluya un constructor que
reciba un valor entero y lo almacene en un atributo edad. El método apply debe
devolver true si la persona pasada como parámetro es menor que la edad
almacenada en el atributo edad.
d) En el método main de la clase TestPersonas, escriba las sentencias necesarias
para obtener un vector con los nombres y apellidos de aquellas personas del
array personas cuya edad esté comprendida entre los 20 y los 30 años.
2. También podemos combinar predicados de manera disyuntiva, usando el método
Predicates.or(), con un prototipo similar al anterior método. Se obtiene con ello un
predicado que será cierto para aquellos objetos para los que eran cierto alguno de los
predicados combinados.
a) Cree una clase de nombre PredicadoFechaVerano en el paquete fecha, que
implemente la interfaz Predicate<Fecha> y cuyo método apply devuelva true si
la fecha recibida como parámetro está comprendida entre el 21 de junio y el 20
de septiembre.
b) En el método main de la clase TestFechas, escriba las sentencias necesarias para
decidir si existe alguna fecha en el array fechas que corresponda al verano o
cuyo mes sea mayo.
Descargar