La metaprogramació és una tècnica avançada que permet als programes escriure o modificar altres programes (o a si mateixos) en temps d'execució. Groovy, amb la seva naturalesa dinàmica, ofereix potents capacitats de metaprogramació que permeten als desenvolupadors crear codi més flexible i adaptable.

Conceptes Clau de la Metaprogramació en Groovy

  1. MetaClass: Cada classe en Groovy té una MetaClass associada que permet modificar el comportament de les instàncies de la classe.
  2. ExpandoMetaClass: Una extensió de MetaClass que permet afegir mètodes i propietats a les classes de manera dinàmica.
  3. Method Missing: Permet interceptar les crides a mètodes que no existeixen.
  4. Property Missing: Permet interceptar l'accés a propietats que no existeixen.
  5. Categories: Permeten afegir mètodes a les classes de manera temporal dins d'un bloc de codi.

MetaClass

La MetaClass és el mecanisme central de la metaprogramació en Groovy. Permet modificar el comportament de les classes i les seves instàncies.

Exemple: Afegir un Mètode a una Classe

class Persona {
    String nom
}

Persona.metaClass.saluda = { -> "Hola, sóc $nom" }

def persona = new Persona(nom: 'Joan')
println(persona.saluda())  // Sortida: Hola, sóc Joan

Explicació:

  • Persona.metaClass.saluda = { -> "Hola, sóc $nom" }: Afegim un mètode saluda a la classe Persona utilitzant la seva MetaClass.
  • def persona = new Persona(nom: 'Joan'): Creem una instància de Persona.
  • println(persona.saluda()): Cridem el nou mètode saluda que hem afegit dinàmicament.

ExpandoMetaClass

L'ExpandoMetaClass permet afegir mètodes i propietats a les classes de manera dinàmica i és especialment útil per a la metaprogramació.

Exemple: Afegir un Mètode Estàtic

ExpandoMetaClass.enableGlobally()

String.metaClass.static.saluda = { -> "Hola des de la classe String!" }

println(String.saluda())  // Sortida: Hola des de la classe String!

Explicació:

  • ExpandoMetaClass.enableGlobally(): Habilitem l'ExpandoMetaClass globalment.
  • String.metaClass.static.saluda = { -> "Hola des de la classe String!" }: Afegim un mètode estàtic saluda a la classe String.
  • println(String.saluda()): Cridem el mètode estàtic saluda.

Method Missing

El mètode methodMissing permet interceptar les crides a mètodes que no existeixen en una classe.

Exemple: Implementar methodMissing

class DynamicMethods {
    def methodMissing(String name, args) {
        return "El mètode $name no existeix, però ha estat interceptat!"
    }
}

def obj = new DynamicMethods()
println(obj.unMetodeInexistent())  // Sortida: El mètode unMetodeInexistent no existeix, però ha estat interceptat!

Explicació:

  • def methodMissing(String name, args): Definim el mètode methodMissing que intercepta les crides a mètodes inexistents.
  • println(obj.unMetodeInexistent()): Cridem un mètode que no existeix, però és interceptat per methodMissing.

Property Missing

El mètode propertyMissing permet interceptar l'accés a propietats que no existeixen en una classe.

Exemple: Implementar propertyMissing

class DynamicProperties {
    def propertyMissing(String name) {
        return "La propietat $name no existeix, però ha estat interceptada!"
    }
}

def obj = new DynamicProperties()
println(obj.unaPropietatInexistent)  // Sortida: La propietat unaPropietatInexistent no existeix, però ha estat interceptada!

Explicació:

  • def propertyMissing(String name): Definim el mètode propertyMissing que intercepta l'accés a propietats inexistents.
  • println(obj.unaPropietatInexistent): Accedim a una propietat que no existeix, però és interceptada per propertyMissing.

Categories

Les categories permeten afegir mètodes a les classes de manera temporal dins d'un bloc de codi.

Exemple: Utilitzar Categories

class StringCategory {
    static String reverseString(String self) {
        return self.reverse()
    }
}

use(StringCategory) {
    println "Hola".reverseString()  // Sortida: aloH
}

Explicació:

  • class StringCategory: Definim una classe de categoria amb un mètode reverseString.
  • use(StringCategory) { ... }: Utilitzem la categoria StringCategory dins del bloc de codi.
  • println "Hola".reverseString(): Cridem el mètode reverseString afegit temporalment a la classe String.

Exercicis Pràctics

Exercici 1: Afegir un Mètode Dinàmic

Afegiu un mètode dinàmic diHola a la classe Persona que imprimeixi "Hola, sóc [nom]".

Solució:

class Persona {
    String nom
}

Persona.metaClass.diHola = { -> "Hola, sóc $nom" }

def persona = new Persona(nom: 'Maria')
println(persona.diHola())  // Sortida: Hola, sóc Maria

Exercici 2: Interceptar Mètodes Inexistents

Creeu una classe DynamicClass que intercepti les crides a mètodes inexistents i retorni un missatge personalitzat.

Solució:

class DynamicClass {
    def methodMissing(String name, args) {
        return "El mètode $name no existeix, però ha estat interceptat!"
    }
}

def obj = new DynamicClass()
println(obj.metodeInexistent())  // Sortida: El mètode metodeInexistent no existeix, però ha estat interceptat!

Resum

En aquesta secció, hem explorat les capacitats de metaprogramació de Groovy, incloent MetaClass, ExpandoMetaClass, methodMissing, propertyMissing i categories. Aquestes eines permeten als desenvolupadors crear codi més flexible i adaptable, i són especialment útils per a la creació de DSLs i altres aplicacions avançades.

© Copyright 2024. Tots els drets reservats