終於要談到Groovy語言的MOP特性了,我在前面的章節中零星的談到了它,卻始終沒有系統的來談到它。這是因為Groovy語言的MOP特性實在是太靈活了,比如本章節要談到的“invokeMethod”和“methodMissing”方法,它們的功能有很大的相似之處,而區別卻相當的微妙。但是,不管怎麼樣,Groovy語言的MOP編程都是我們必須掌握的。而這個系列我沒有計劃多少個部分談完,跟《Groovy探索之閉包》系列一樣,探索一部分說一部分。
本節要談到的“invokeMethod”方法,我們在《Groovy探索》系列中已經有一個章節談到過,本節還要談到,主要是要談談它和“methodMissing”的區別。
對於“invokeMethod”方法,大家一定很熟悉了,我們可以用下面一個簡單的例子來看看它的作用:
class InvokeTestor1 {
def hello()
{
'invoke hello directly'
}
def invokeMethod(String name,Object args)
{
return "unknown method $name(${args.join(',')})"
}
static void main(args) {
def it = new InvokeTestor1()
println it.hello()
println it.foo("mark",19)
}
}
運行的結果為:
invoke hello directly
unknown method foo(mark,19)
可以看出,對於一個對象的方法調用來說,如果這個方法能夠被分派出去,如上面的“hello”方法,可以在InvokeTestor1類中找到,就被分派給InvokeTestor1類的“hello”方法;如果不能被分派,如上面的“foo”方法,則調用“invokeMethod”方法。
在Groovy語言中,還有一個方法也可以實現上面的功能,這就是“methodMissing”方法,請看下面的例子:
class MethodTestor1 {
def hello()
{
"invoke hello directly"
}
def methodMissing(String name,args)
{
return "unknown method $name(${args.join(',')})"
}
static void main(args) {
def mt = new MethodTestor1()
println mt.hello()
println mt.foo('mark',19)
}
}
我們還是來看看上面的代碼的運行結果:
invoke hello directly
unknown method foo(mark,19)
可以看到,“methodMissing”方法就像它的名字一樣,如果方法可以在類中找得到,那麼就調用該方法;如果找不到,那麼就是“missing method”,就可以調用“methodMissing”方法了。跟“invokeMethod”功能非常類似。
這點大家都清楚,但實際上,“invokeMethod”在Groovy語言中是用來分派一個對象的所有方法的。要做到這一點,就需要借助於“GroovyInterceptable”接口。請看下面的例子:
class InvokeTestor2 implements GroovyInterceptable{
def hello()
{
"invoke hello directly"
}
def invokeMethod(String name,Object args)
{
return "unknown method $name(${args.join(',')})"
}
static void main(args) {
def it = new InvokeTestor2()
println it.hello()
println it.foo('mark',19)
}
}
運行結果為:
unknown method hello()
unknown method foo(mark,19)
從運行結果可以看出,“invokeMethod”方法的確可以分派所有的方法,只要我們實現“GroovyInterceptable”接口即可。
而“methodMissing”方法呢,即使類實現了“GroovyInterceptable”接口,它也不能使用“methodMissing”方法來分派所有的方法。請看下面的例子:
class MethodTestor2 implements GroovyInterceptable{
def hello()
{
"invoke hello directly"
}
def methodMissing(String name,args)
{
return "unknown method $name(${args.join(',')})"
}
static void main(args) {
def mt = new MethodTestor2()
println mt.hello()
println mt.foo('mark',19)
}
}
它的運行結果為:
invoke hello directly
unknown method foo(mark,19)
通過了上面的比較,我們可以看出“invokeMethod”方法和“methodMissing”方法的微妙區別:即,“invokeMethod”方法可以分派所有的方法,包括一個類已經實現了的和未實現的方法;而它實現上面的功能是通過這個類實現“GroovyInterceptable”接口達到的。而“methodMissing”方法則只能分派一個類未實現的方法,無論它是否實現了“GroovyInterceptable”接口。
這種區別的確很微妙,如果我們想讓一個方法來管理一個類所有方法的調用,那麼我們必須使用“invokeMethod”方法;如果我們只想通過一個方法來管理一個類的所有“missing method”,即不能被分派出去的方法,那麼使用“methodMissing”方法是比較有效的;當然,“invokeMethod”方法也能實現“methodMissing”方法的功能。