Groovy探索之MOP 十一 运行期内覆盖invokeMethod

Groovy探索之MOP 十一 运行期内覆盖invokeMethod

我们很早就会使用Groovy语言的hook,即"invokeMethod"方法和其他的几个方法。我们会在一个类中实现"invokeMethod"方法,用来分派所有的或部分的在运行期内调用的该类实例的方法。这些我们在《Groovy探索之MOP 一 invokeMethod和methodMissing方法》已经详细的谈到过。

现在,我们已经深入的接触到了Groovy语言的MetaClass,更是也到处使用到了ExpandoMetaClass。我们都已经知道,ExpandoMetaClass的灵活性,不是hook能够比拟的。我们就想,既然使用ExpandoMetaClass能够在运行期内给一个类增加方法,那么,我们是否也可以在运行期内增加hook方法呢?

我们可以回答,是。还是先来看一个简单的例子吧!

我们还是有这么一个简单的类:

class Foo

{

def foo()

{

'foo'

}

}

我们现在尝试着在运行期内增加"invokeMethod"方法:

Foo.metaClass.invokeMethod = {

String name,args1 ->

'test'

}

接着,我们来测试这个运行期内增加的"invokeMethod"方法:

def foo = new Foo()

println foo.foo()

println foo.test()

运行结果为:

test

test

可以看出,我们在运行期内增加的"invokeMethod"方法拦截了Foo类的实例的所有的方法。

当然,如果我们想把"invokeMethod"方法拦截的方法中,已经存在于Foo类的方法,如"foo",交给Foo类本身的方法来处理。那么,我们就可以如下实现"invokeMethod"方法:

Foo.metaClass.invokeMethod = {

String name,args1 ->

def m = Foo.metaClass.getMetaMethod(name,args1)

def result

if(m)

result = m.invoke(delegate,args1)

else

result = 'test'

result

}

我们再运行上面的测试代码,就会得到如下的结果:

foo

test

现在,我们来定义几个名词,我们把类本身实现的"invokeMethod"方法称为对象的"invokeMethod"方法,而把在运行期内通过ExpandoMetaClass增加的"invokeMethod"方法称为metaClass的"invokeMethod"方法。

现在的问题是,如果一个对象,同时实行了对象的"invokeMethod"方法和metaClass的"invokeMethod"方法,那么该调用谁?

你肯定会说,这个问题很简单啊,我们来做一个简单的测试不就知道了。好,现在,我们先来看看这个简单的测试。

首先,我们把上面的Foo类增加"invokeMethod"方法:

class Foo

{

def foo()

{

'foo'

}

def invokeMethod(String name,args)

{

'invoke'

}

}

同时,我们在运行期内也增加该方法,然后做测试:

Foo.metaClass.invokeMethod = {

String name,args1 ->

def m = Foo.metaClass.getMetaMethod(name,args1)

def result

if(m)

result = m.invoke(delegate,args1)

else

result = 'test'

result

}

def foo = new Foo()

println foo.foo()

println foo.test()

运行的结果为:

foo

test

从结果可以看出,metaClass的"invokeMethod"方法覆盖了对象的"invokeMethod"方法。即如果存在metaClass的"invokeMethod"方法,则优先调用metaClass的"invokeMethod"方法,而不管对象的"invokeMethod"方法是否存在。

最后,我们还定义一个名词:GroovyInterceptable的"invokeMethod"方法。这个名词其实我们在《Groovy探索之MOP 一 invokeMethod和methodMissing方法》也接触过,就是一个类如果实现了"GroovyInterceptable"接口,那么它的类本身的"invokeMethod"方法,就是GroovyInterceptable的"invokeMethod"方法。如下所示:

class Foo implements GroovyInterceptable{

def foo()

{

'foo'

}

def invokeMethod(String name,args)

{

'invoke'

}

}

现在,我们需要知道,如果一个对象的GroovyInterceptable的"invokeMethod"方法和metaClass的"invokeMethod"方法都存在,那么又是如何调用的?

还是对上面已经实现了"GroovyInterceptable"接口的Foo类如下测试:

Foo.metaClass.invokeMethod = {

String name,args1 ->

def m = Foo.metaClass.getMetaMethod(name,args1)

def result

if(m)

result = m.invoke(delegate,args1)

else

result = 'test'

result

}

def foo = new Foo()

println foo.foo()

println foo.test()

运行结果为:

invoke

invoke

从运行结果可以看出,GroovyInterceptable的"invokeMethod"方法是优先于metaClass的"invokeMethod"方法的调用的;或者说,如果一个对象同时存在GroovyInterceptable的"invokeMethod"方法和metaClass的"invokeMethod"方法,那么系统将调用GroovyInterceptable的"invokeMethod"方法,而不管metaClass的"invokeMethod"方法。

最后,我们来做一个总结吧。对于一个对象的方法调用,如果该对象的类实现了"GroovyInterceptable"接口,那么,系统将调用GroovyInterceptable的"invokeMethod"方法;否则,系统将调用metaClass的"invokeMethod"方法;如果该对象没有实现metaClass的"invokeMethod"方法,那么系统将调用对象的"invokeMethod"方法。

你可能感兴趣的:(groovy)