web-dev-qa-db-fra.com

Ajouter de manière dynamique une propriété ou une méthode à un objet dans Groovy

Est-il possible d'ajouter une propriété ou une méthode à un objet de manière dynamique dans Groovy? C'est ce que j'ai essayé jusqu'à présent:

class Greet {
  def name
  Greet(who) { name = who[0].toUpperCase() + [1..-1] }
  def salute() { println "Hello $name!" }
}

g = new Greet('world')  // create object
g.salute()              // Output "Hello World!"

g.bye = { println "Goodbye, $name" }
g.bye()

Mais je reçois l'exception suivante:

Hello World!
Caught: groovy.lang.MissingPropertyException: No such property: bye for class: Greet
Possible solutions: name
    at test.run(greet.groovy:11)
38
Alex Spurling

Si vous souhaitez simplement ajouter la méthode bye() à l'instance unique g de la classe Greet, vous devez faire:

g.metaClass.bye = { println "Goodbye, $name" }
g.bye()

Sinon, ajouter bye() à toutes les instances de Greet (à partir de maintenant), appelez

Greet.metaClass.bye = { println "Goodbye, $name" }

Mais vous auriez besoin de le faire avant de créer une instance de la classe Greet

Voici une page sur la métaclasse par instance

et voici la page sur les métaclasses en général


En outre, il y a un bogue dans votre constructeur. Vous manquez who de l'infonte de votre [1..-1] Et si le constructeur est passé un String de moins de 2 caractères, il lancera une exception

Une meilleure version pourrait être:

Greet( String who ) { 
  name = who.inject( '' ) { String s, String c ->
    s += s ? c.toLowerCase() : c.toUpperCase()
  }
}

Comme métimisée dans les commentaires,

Greet( String who ) { 
  name = who.capitalize()
}

est la bonne façon

62
tim_yates