Categorías en Groovy
viernes 17/08/2007
El que Groovy sea un lenguaje dinámico hace que sea capaz de hacer cosas que con Java no podríamos ni imaginar. Una de ellas es añadir métodos en tiempo de ejecución a clases de las que no tenemos control, gracias a las Categorías.
Las categorías en Groovy están basadas en las de Objective-C, y nos permiten, por ejemplo, incorporar métodos a la clase String de Java para que haga algo específico que necesitemos, vamos a ver un ejemplo:
Ejemplo1.groovy
class StringCategory {
static String lower(String string) {
return string.toLowerCase()
}
}
use (StringCategory.class) {
assert "test" == "TeSt".lower()
}
Formalmente, una categoría es una clase que contiene métodos estáticos en los que el primer parámetro es un objeto del tipo al que queremos añadir la funcionalidad. En este caso, la categoría que hemos creado tiene un método que opera sobre un String para devolvernos su valor en letras minúsculas.
Para emplear la categoría usamos la palabra reservada use, de manera que cuando escribimos "TeSt".lower() en el ámbito declarado con use(StringCategory.class), le estamos diciendo al entorno de ejecución que el método lower() que debe ejecutar es el que definimos en la categoría StringCategory, y pasar como primer parámetro este objeto String.
En el blog de Joachim Baumann tenemos otro ejemplo muy interesante del uso de categorías para facilitar el trabajo con la clase Timer del JDK:TimerCategory.groovy
class TimerCategory {
static TimerTask run(Timer timer, Map vals, Closure c) {
task = new ClosureTimerTask(c)
if vals.fixed
get val and set fixed
if vals.after or if vals.after or vals.at
get value and set delay
if vals.every
get value and set period
use values to schedule task with timer
return task
}
}(El código completo tiene unas 45 líneas, podéis descargarlo aquí)
Esta categoría, junto con la TimeCategory incorporada en Groovy, nos permite utilizar los Timers con una sintaxis muuy groovy ;-) :
EjemploTimerCategory.groovy
use(TimeCategory, TimerCategory) {
t = new Timer()
t.run(at: new Date(), every: 3.seconds, fixed:true) {
//lo que queramos hacer
}
}
Otras construcciones permitidas:
t.run(at: 3.minutes.from.now)
t.run(in: 5.seconds, every: 3.seconds, fixed:true)
t.run(after: 5.seconds, every: 3.seconds, fixed:true)
t.run(after: 5000, every: 3.seconds)
Como véis, la potencia de las Categorías es enorme, pues nos permite incorporar funcionalidades a cualquier clase en el ámbito de nuestro código para modificar su comportamiento.












