2010-03-15 16 views
16

El siguiente código trataron de sustituir un método existente en una clase maravillosa:¿Es posible reemplazar el método Groovy por un objeto existente?

class A { 
    void abc() { 
    println "original" 
    } 
} 

x= new A() 
x.abc() 
A.metaClass.abc={-> println "new" } 
x.abc() 
A.metaClass.methods.findAll{it.name=="abc"}.each { println "Method $it"} 

new A().abc() 

Y el resultado es el siguiente resultado:

original 
original 
Method [email protected][name: abc params: [] returns: class java.lang.Object owner: class A] 
Method public void A.abc() 
new 

¿Quiere decir esto que cuando modifique la metaclase estableciéndolo en cierre, realmente no lo reemplaza, sino que simplemente agrega otro método que puede llamar, lo que resulta en metaclass que tiene dos métodos? ¿Es posible reemplazar realmente el método para que la segunda línea de salida imprima "nuevo"?

Al tratar de resolverlo, encontré que DelegatingMetaClass podría ayudar - ¿es esa la manera más maravillosa de hacer esto?

Respuesta

10

Puede utilizar la instancia por MetaClass para cambiar el valor en el objeto existente, así:

x= new A() 
x.abc() 
x.metaClass.abc={-> println "new" } 
x.abc() 
x.metaClass.methods.findAll{it.name=="abc"}.each { println "Method $it"} 

Pero, como se ha visto, x tendrá dos métodos asociados a ella (bueno, en realidad, , un método y el cierre que ha añadido

Si cambia la definición de a de modo que el método se convierte en una definición de cierre de este modo:

class A { 
    def abc = { -> 
    println "original" 
    } 
} 

Entonces sólo obtendrá una cierre único en el metaClass y ningún método después de la alteración

+2

Gracias - Estoy tratando de usar esto para anular un método en la clase existente de Groovy, así que estoy tratando de evitar modificar la clase original. –

1

Estoy seguro de que su aún tiene este problema;) pero ... estoy ejecutando la versión 1.8.7 de Groovy en Fedora 17. He encontrado que tiene que hacer esta combinación:

A.metaClass.abc = {-> println it} 
A obj = new A() 
obj.metaClass.abc = {-> println it} 
obj.abc 

A partir de ahí actuará como desee. Cuando nos fijamos en los métodos, todavía tendrá dos:

Method [email protected][name: abc params: [] returns: class java.lang.Object owner: class A] 
Method public void A.abc() 

Pero por lo menos usted no tiene que cambiar su declaración public void.
No estoy seguro si esto es un error o qué.

5

Estoy totalmente de acuerdo con @tim_yates en esto. Sin embargo, hay una forma de evitar, si quieres evitar modificar la clase original uso MethodClosure lugar, como se muestra a continuación:

class A { 
    void abc() { 
    println "original" 
    } 
} 

x = new A() 

//Create a Method Closure or Method pointer 
pointer = x.&abc 

//Replace Original call with Method pointer 
//x.abc() 
pointer() 

//Meta classed 
A.metaClass.abc={-> println "new" } 

//Call method pointer instead of original again 
//x.abc() 
pointer() 

A.metaClass.methods.findAll{it.name=="abc"}.each { println "Method $it"} 

new A().abc() 

Usted debe conseguir lo que se espera:

original 
new 
Method [email protected] 
    [name: abc params: [] returns: class java.lang.Object owner: class A] 
Method public void A.abc() 
new 

Based en Groovy 2.2.1. La pregunta es muy vieja sin embargo.

+0

Luchando por comprender 'MethodClosure' aquí. Usando este enfoque es posible tener dos instancias de A (digamos x e y) cada una tiene sus propios métodos separados 'abc'? – HDave

+0

No. Una vez que haya modificado 'abc' utilizando el metaClass en' Clase A', entonces es aplicable a todas las instancias de A. MethodClosure es solo una representación de Cierre del método subyacente que puede invocarse en cualquier momento. – dmahapatro

+0

ok - por lo que no es posible tener varias instancias de 'Clase A 'cada una con un método diferente' abc'. Gorrón. – HDave

Cuestiones relacionadas