从1.5版本开始,Groovy支持“methodMissing(方法缺失)”的概念了,它和“invokeMethod(调用方法)”的区别在于它只能用于方法调用失败时。
以下介绍了这个行为的两个重要方面:
一般来说,当使用methodMissing的时候,代码会检查一遍Groovy的方法调用逻辑,并以某种方式使得下次相同方法的快速调用成为可能。 举一个GORM的动态查找器的例子。这是通过methodMissing实现的。它们是怎样工作的呢?代码类似于这样:
class GORM { def dynamicMethods = [...] // 一个使用正则表达式的动态方法的数组 def methodMissing(String name, args) { def method = dynamicMethods.find { it.match(name) } if(method) { GORM.metaClass."$name" = { Object[] varArgs -> method.invoke(delegate, name, varArgs) } return method.invoke(delegate,name, args) } else throw new MissingMethodException(name, delegate, args) } }
现在注意,如果我们发现一个可调用的方法,我们会在运行中使用ExpandoMetaClass(可扩展元类)动态地注册一个新方法。这就是为什么下次相同方法调用时会如此高效的原因。通过这个方式,methodMissing就不会有invokeMethod的额外开销,也不会在第二次调用中耗费大量开销了。
Groovy也支持propertyMissing,它能尝试对缺失的属性进行处理。你可以用带有一个String参数的propertyMissing定义来实现一个获取器(getter):
class Foo { def propertyMissing(String name) { name } } def f = new Foo() assertEquals "boo", f.boo
你可以添加带有一个value参数的第二个propertyMissing定义来实现一个设置器(setter):
class Foo { def storage = [:] def propertyMissing(String name, value) { storage[name] = value } def propertyMissing(String name) { storage[name] } } def f = new Foo() f.foo = "bar" assertEquals "bar", f.foo
就像使用methodMissing那样,你也许会在运行时动态注册新属性以提升代码的性能。
通过ExpandoMetaClass(可扩展元类),你可以添加methodMissing和propertyMissing来处理静态方法和属性。