Secciones

Artículos para tus primeros pasos

Si estás empezando a introducirte en el mundo de Groovy y Grails, no te pierdas nuestros artículos básicos: 

Entrevistas con los expertos
 

Los protagonistas te cuentan de qué van los proyectos más importantes del mundo Groovy:


Un proyecto de:
ImaginaWorks
Campus Escuela de Groovy

Introducción a Groovy, parte 3

lunes 22/10/2007

1. Introducción

En este tercer artículo introductorio a Groovy (parte 1, parte 2) continuaremos con otras características del lenguaje, algunas las encontrarás en otros lenguajes, otras son exclusivas de Groovy.

2. Argumentos variables

La capacidad de definir que un método pueda trabajar con un número variable de argumentos es relativamente reciente en Java (desde Java 5 para ser exactos) y sin embargo es una características que otros lenguajes ya poseín (como JavaScript por mencionar uno). Groovy también permite su uso, pero a diferencia de Java, no se requiere una versión en particular sino mas bien seguir la siguiente convención: si el último argumento es de tipo Object[] entonces todo aquel argumento extra sera asignado al arreglo, veamos un ejemplo de su uso:
Listado 2.1

class Calculadora {
def sumaTodos( Object[] args ){
int total = 0
args.each { total += it }
total
}
}

Calculadora c = new Calculadora()
assert c.sumaTodos(1,2,3,4,5) == 15

Existen mejores maneras de sumar números con Groovy, sin embargo el ejemplo muestra de manera sencilla como trabajar con argumentos variables.

3. Argumentos con nombre

Cuando vimos los POGOs demostré que existe una manera de crear instancias usando una conbinación de nombres y valores para las propiedades del POGO, el truco si recuerdan esta en que Groovy usa un Mapa con cun constructor genérico. Un truco similar puede ser usado en el caso de métodos normales para obtener el mismo resultado, es decir, nombres relacionados con argumentos. Para lograrlo debes declarar un Mapa como argumento y usar dicho mapa dentro de tu implementación
Listado 3.1

class Math {
static calculaPendiente( Map args ){
def b = args.b ? args.b : 0
(args.y - b) / args.x
}
}

assert 1 == Math.calculaPendiente( x: 2, y: 2 )
assert 0.5 == Math.calculaPendiente( x: 2, y: 2, b: 1 )

Si recuerdas las clases de matemáticas en el colegio, la fórmula de una recta es y = mx + b donde m es la pendiente y b es una constante. Al despejar la ecuación podemos encontrar el valor de la pendiente para cualesquiera valores de x, y, b. Esta ténica permite una comunicar de mejor manera que significa cada argumento pero sacrifica al mismo tiempo cualquier posibilidad de descubrir los argumentos que se requieren para ejecutar el método al solo observar la firma del mismo, por lo que el uso de comentarios en el c&pacute;digo que use esta técnica es prácticamente indispensable. Como todo en la vida hay que hacer sacrificios de vez en cuando.

4. Argumentos fijos

El nombre de esta sección resulta un poco extraño, en realidad quiero platicarles un momento de lo que se conoce como "currying". Currying es una técnica que transforma una función en otra al "fijar" uno o m´s argumentos de la primera, es como si definieramos constantes en los argumentos de la segunda función, veamos un ejemplo para despejar dudas
Listado 4.1

def calculaPendiente = { x, y, b = 0 ->
println "x:${x} y:${y} b:${b}"
(y - b) / x
}

assert 1 == calculaPendiente( 2, 2 )
def calculaPendienteX = calculaPendiente.curry(5)
assert 1 == calculaPendienteX(5)
assert 0 == calculaPendienteX(2.5,2.5)
// imprime
// x:2 y:2 b:0
// x:5 y:5 b:0
// x:5 y:2.5 b:2.5

Primero definimos un closure que toma 3 argumentos (con tipos dinámicos) y además el argumento b es asignado el valor 0 por omisión, asi que es posible llamar al closure calculaPendiente con solo 2 argumentos en vez de tres. Despueés de comprobar que la implementació devuelve el valor correcto aplicamos el currying y obtenemos un segundo closure, en este caso fijamos el valor de x a que sea 5, cualquier llamada subsecuente a a calculaPendienteX siempre usará ese valor para x.

5. Revisitando operadores

En la segunda parte de esta serie vimos como Groovy permite la sobrecarga de operadores, en esta ocasión veremos otros operadores que no verás en Java. El primero se le conoce como "spaceship" (nave espacial) puesto que parece un pequeñ OVNI (<=>), es de tipo binario (acepta 2 argumentos) y permite ejecutar una comparación, por lo que lo veras comunmente usado en algoritmos de ordenamiento. Para habilitar el uso del operador en tus clases debes implementar la interface java.util.Comparable, lo cual agrega como efecto secundario que los siguientes operadores se habiliten tambiém: <, <=, =>, >.
Listado 5.1

// Number es Comparable
assert [1,2,3,4,5,6] == [2,4,6,1,5,3].sort {a,b -> a <=> b }

El segundo operador es llamado dispersión (spread en Inglés), tiene dos variantes. La primera variante permite expander el contenido de una lista, la segunda aplica un método a todos los elementos de la lista. Veamoslo en acción:
Listado 5.2
// 1ra variante
def calcula = { a, b, c -> "$a,$b,$c" }
assert "1,2,3" == calcula( *[1,2,3] )

// 2da variante
assert ["01","11","21"] == ["10","11","12"]*.reverse()

EL tercer operador en nuestra lista es Elvis (?:) el cual es una reducción del operador trinario, dado que en caso de que la expresió usada como condición resulte verdadera esta misma ser´ el valor de retorno
Listado 5.3
assert "hola" == "hola" ?: "adios"
assert "adios" == null ?: "adios"

El siguiente operador de la lista traerá recuerdos a aquellos que programaron en lenguage C, puesto que permite obtener una referencia de métodos (en C una referencia a función) y desde Groovy 1.1-beta-3 tambieén es posible hacer lo mismo con propiedades. Esta característica es muy util para "convertir" un método en un closure lo cual permite mezclar comportamiento a tu antojo, por ejemplo veamos de nuevo a la clase Math y curry al mismo tiempo
Listado 5.4
class Math {
static calculaPendiente( x, y, b = 0 ){
(y - b) / x
}
}

// obtenemos una referencia del método estático
def calculaPendiente = Math.&calculaPendiente
assert calculaPendiente instanceof Closure
assert 1 == calculaPendiente( 2, 2 )
def calculaPendienteX = calculaPendiente.curry(5)
assert 1 == calculaPendienteX(5)
assert 0 == calculaPendienteX(2.5,2.5)

El último operador es mas bien la palabra reservada "as", la cula permite la conversión de tipos. En el caso de usar as con un closure o un mapa en conjunto con una interface es posible crear una implementación de la misma, como si fuese una clase interna. Veamos como funciona
Listado 5.5
import java.awt.event.*
import javax.swing.JButton

class Person {
String name
int id
}

def person = [name: 'Duke', id:1] as Person
assert person.class == Person
assert person.name == 'Duke'

def button = new JButton(label:'OK')
button.addActionListener({ event ->
assert 'OK' == event.source.label
} as ActionListener )
button.doClick()

Desde groovy 1.1-beta-3 es posible usar este mecanismo para crear implementaciones de clases abstractas y concretas.

6. Conclusión

Esto es todo por el momento, espero que la lista de características presentadas en las 3 partes de esta serie te resulten útiles al trabajar con Groovy. En artículos posteriores hablaremos de como crear Builders y el MOP (Protocolo Meta-Objeto), otras dos opciones interesantes que Groovy ofrece para hacer la vida mas agradable.

 

 

Andrés es un Programador Java certificado, Desarrollador de Aplicaciones Web certificado, con más de 7 años de experiencia en diseño y desarrollo de aplicaciones. El ha estado involucrado en muchos desarrollos de aplicaciones web y desktop seleccionando el conjunto de herramientas y tecnologías mas apropiadas. También ha sido profesor de cursos de ciencias de la computación en el instituto educativo más prestigioso de México. Sus interese actuales incluyen arquitectura de software, Developer Testing, Groovy, Spring, AOP y Swing.


Más información: http://groovy.org.es

Contenidos relacionados:



0 comentarios:

Tienes que estar registrado para iniciar sesión y poder publicar tus comentarios