2010-03-15 34 views
16

aşağıdaki kod Groovy sınıfta varolan yöntemi yerine çalıştı:Varolan nesne için groovy yöntemini değiştirmek mümkün mü?

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() 

Ve aşağıdaki çıkışı sonuçlanır:

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

bu anlamına mı geliyor bunu ayarlayarak metaclass değiştirdiğinizde Kapatma, gerçekten yerine geçmez ama sadece arayabileceği başka bir yöntem ekler, böylece iki yönteme sahip metaclass elde edilir? Yöntemi gerçekten değiştirmek mümkün mü, ikinci çıktı satırı "yeni" yazıyor mu? onu anlamaya çalışırken

, ben DelegatingMetaClass yardımcı olabileceğini bulundu - En Groovy yolu budur yapmak o?

cevap

10

Öyle gibi varolan nesne değeri değiştirmek için başına örneğini metaclass kullanabilirsiniz:

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

gördüğünüz gibi, x bununla (kuyu ile ilişkili iki yöntem olacaktır, gerçekte o halde tek bir alacak

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

: böylece, bir yöntem ve bir tanımını değiştirirseniz

eklendi kapatma yöntemi kapatma tanımı şöyle olur Tek Metaclass içinde kapatılması ve

+2

teşekkürler - Groovy sınıfı mevcut bir yöntemi geçersiz kılmak için kullanabilir çalışıyorum, bu yüzden orijinal sınıfını değiştirerek önlemek için çalışıyorum. –

1

Ben senin hala sahip bu konu eminim değişiklik sonrasında hiçbir yöntem;) ama ... Ben bunu buldum Fedora 17. Groovy sürümünü 1.8.7 koşuyorum Bu kombinasyonu yapmak zorunda:

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

Oradan dışarı istediğiniz gibi davranacaktır.

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

Ama en azından senin public void beyanı değiştirmek zorunda değilsiniz: yöntemleri için baktığınızda, yine iki alırsınız.
Bunun bir hata mı, ne olduğu konusunda emin değilsiniz.

5

Bu konuda @tim_yates ile tamamen katılıyorum. Eğer kullanım MethodClosure yerine orijinal sınıfını değiştirerek kaçınmak istiyorsanız aşağıda gösterildiği gibi, bir şekilde, buralarda:

Sen beklenen olsun gerektiğini
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() 

:

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

Tabanlı Groovy 2.2.1 üzerinde. Soru çok eski olsa da.

+0

Burada MethodClosure'ı anlamak için mücadele. Bu yaklaşımı kullanarak, A'nın iki örneğini (x ve y demek) mümkün kılmak, her birinin kendi ayrı yöntemleri vardır abc'? – HDave

+0

Hayır. "A sınıfı" üzerindeki metaClass kullanılarak abc'yi değiştirdikten sonra, tüm A örneklerine uygulanabilir. MethodClosure, yalnızca, herhangi bir zamanda çağrılabilen temel yöntemin bir Kapanış temsili olur. – dmahapatro

+0

tamam - bu yüzden herbiri farklı bir yöntem olan abc '' A 'sınıfı birkaç örneğine sahip olmak mümkün değildir. Aylak. – HDave

İlgili konular