Groovy探索之MOP 十五 方法名的动态性(2)
List scores = [new Student(no:'123',name:'Tom',chinScore:90,mathScore:99,englScore:60,physScore:88,chemScore:96)]
scores<<new Student(no:'124',name:'Mike',chinScore:88,mathScore:90,englScore:90,physScore:98,chemScore:87)
scores<<new Student(no:'125',name:'Alice',chinScore:100,mathScore:55,englScore:98,physScore:67,chemScore:56)
def sorter = new SortHelper(scores)
sorter.sortByChinScore()
scores.each{
println it.name
}
运行结果为:
Mike
Tom
Alice
我们都记得我们的初中数学里学过的对数的概念:对数里面有一个底的概念,比如我们在程序里把以2为底的对数写成如下的样子:
log2(8)
即以2为底8的对数,这样,我们可以以任何一个自然数为底,但我们最常用的是以10为底的对数,即:
log10(100)
以10为底的对数,我们通常写成:
lg(100)
问题为:我们在某种情况下,可能会计算以1到100之间的任何一个数为底的对数。按照上面的分析,其实,就是我们需要给某个工具类100个计算对数的方法。
这就是方法名的动态性的使用了。
我们还是先给出这个工具类来:
class Util
{
}
这个工具类什么也都没有实现,留给我们在运行期内动态添加方法,如下:
(1..101).each{
int base->
Util.metaClass.'static'."log$base" = {
int n -> Math.log(n) / Math.log(base)
}
}
它是把1到100进行遍历,产生了一百个方法,至于如何计算各个底的对数的方法,那是数学公式的问题,我们在这里不再详述。
有了上面的代码,我们现在就可以写测试代码了:
println Util.log20(400)
println Util.log100(100)
运行结果为:
2.0
1.0
现在,我们可以看到,我们的这些对数方法是不是写得很漂亮?
在Groovy语言中,动态委派技术永远是我们最感兴趣的技术。而这种动态委派技术的实现,其实也需要用到我们使用ExpandoMetaClass类来实现的动态方法名。
下面就来说一说如何实现动态委派技术。
这是一个简单的委派类:
class Delegator {
private targetClass
private delegate
Delegator(targetClass, delegate) {
this.targetClass = targetClass
this.delegate = delegate
}
def delegate(String methodName) {
delegate(methodName, methodName)
}
def delegate(String methodName, String asMethodName) {
targetClass.metaClass."$asMethodName" = delegate.&"$methodName"
}
}
这个类十分的简单,可以明显的看到“delegate(String methodName, String asMethodName)”方法就是使用的ExpandoMetaClass类实现的动态方法名,如下:
targetClass.metaClass."$asMethodName" = delegate.&"$methodName"
现在,我们就来使用这个动态委派技术。
下面,我们有一个A类:
public class A{
def a()
{
println 'invoke a function...'
}
}
它就是我们需要委派的原始类。下面是一个简单的B类,没有任何的方法:
public class B{
}
下面就可以写测试代码了:
def a = new A()
def delegator = new Delegator(B,a)
delegator.delegate 'a'
delegator.delegate 'a','b'
delegator.delegate 'a','c'
def b = new B()
b.a()
b.b()
b.c()
在上面的代码中,我们分别把A类的“a”方法委派给了B类的三个方法:“a”、“b”和“c”方法。
最后,我们在B类对象中调用这三个方法。运行结果为:
invoke a function...
invoke a function...
invoke a function...
这充分的体现了使用的ExpandoMetaClass类实现的方法名的动态性的特点。
值得注意的是,上面的动态委派技术的实现,需要在我们的Groovy1.5及以上的版本中才能正常编译。可以确定的是,Groovy1.0版本是不能编译的。
同时需要说明的是,我的所有文字,除非注明需要Groovy1.5及以上版本,否则都可以在Groovy1.0版本及以上编译运行。
谢谢!