Groovy探索之invokeMethod方法
我们知道,在Java语言中,所有的Java类都继承了Object对象。通过Object对象,所有的Java类都隐藏的实现了“equals”等方法。同样,在Groovy语言中,所有的Groovy类都隐藏的实现了GroovyObject接口,这样,我们的Groovy类就隐藏的实现了很多的方法,如“isCase”等。
这篇文字要谈谈的就是GroovyObject接口的“
invokeMethod”方法,这个方法对于我们Groovy语言的动态性编程很有帮助,可以帮助我们实现一些很有时代性的功能,比如DSL。本文就是要谈谈“
invokeMethod”方法的基础,通过这个基础,我们才可以通向DSL编程。
首先,我们来看看“
invokeMethod”方法在一个Groovy类中的作用,先来看一个例子:
class
InvokeMethodTestor {
def
test
()
{
println
'hello,function name is test'
}
def
invokeMethod(String name,Object args)
{
println
"the other function, name is ${name}"
}
}
这是一个很简单的
Groovy
类,我们有一个
test
方法,用来向控制台打印一句话;然后我们实现了
invokeMethod
方法,并且把参数“
name
”打印在控制台。
在讲述“
invokeMethod”方法的作用之前,我们先来测试一下上面的类。
def
testor =
new
InvokeMethodTestor()
testor.
test
()
testor.hello()
testor.doSomething()
我们先来看看测试结果:
hello,function name is test
the other function, name is hello
the other function, name is doSomething
通过测试结果,我们可以看出,语句“
testor.
test
()
”调用了“
InvokeMethodTestor
”类的“
test
”方法,而语句“
testor.hello()
”和“
testor.doSomething()
”却都调用了“
InvokeMethodTestor
”类的“
invokeMethod
”方法。
这就告诉我们,对于一个实现了“
invokeMethod
”方法的
Groovy
类的对象,可以执行任意的方法,如果该方法已经在该类中实现,就调用该方法,如“
testor.
test
()
”就调用“
InvokeMethodTestor
”类的“
test
”方法;如果该方法没有在该类中实现,如“
testor.hello()
”和“
testor.doSomething()
”,就调用该类的“
invokeMethod
”方法。
这样说来,“
invokeMethod
”方法其实蛮简单的,一点都不神秘和麻烦。但是它的作用却一点都不能小觑,它给我们的
Groovy
语言编程带来了很大的动态性。
下面试着举一个小小的例子说明。
比如,我们有一个
Student
类,里面放的是学生的成绩,如“语文”、“数学”、“英语”等等,如下:
class
Student {
String no;
String name;
float
chinScore;
float
mathScore;
float
englScore;
float
physScore;
float
chemScore;
float
totalScore;
}
同时,我们有一些学生(已经记录的各科成绩)在一个
List
对象里,如下:
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
)
这些学生在
List
对象里是以学号排序的,我们来看看:
scores.
each
{
println
it.name+
' : '
+it.no
}
结果为:
Tom : 123
Mike : 124
Alice : 125
可以看到的确如此。
下面,我们的语文老师希望以语文成绩排序,而数学老婆希望以数学成绩排序,英语老师则希望以英语成绩排序,
……
,班主任则希望以总分排序。
看到这里,你可以会说,我做一个方法来实现所有老师的愿望,这个方法有两个参数,一个是
List
对象,一个是
type
,
type
参数用来表示语文老师要的语文,数学老师要的数学等等。
这个方法当然是不错的,但不是最酷的。最酷的方法是语文老师调用
sortByChinScore
()方法,而数学老师调用
sortByMathScore
()方法,英语老师调用
sortByEnglScore
()方法,等等。
且慢!这不是要我写六七个方法来实现所有老师的要求?这未免有点无聊吧?像这样的代码写起来也枯燥乏味呀。
当然不用写六七个方法,答案就是“
invokeMethod
”方法。我们来看看是如何实现这样一个想法的:
import
java.util.Collections
import
java.util.Comparator
class
SortHelper{
def
list
public
SortHelper(list)
{
this
.list = list
}
//
所有的以
sort
开头的方法都来调用“
invokeMethod
”,当然,其他方法也有可能
//
来调用它,但我不做处理。
def
invokeMethod(String name,Object args)
{
//
首先判断方法名是否以“
sortBy
”开头,是则处理,否则不处理。
if
(name.indexOf(
'sortBy'
)==
0
)
{
//
取得属性名,如“
ChinScore
”
name = name[
6
..name.length()-
1
]
//
把第一个字母由大写变小写,就取得了属性名
name = name[
0
].toLowerCase()+name[
1
..name.length()-
1
]
//
实现
Comparator
接口,大家可以参考
jdk
文档。
def
comparator = {
node1,node2 ->
return
node1.
"${name}"
.
compareTo
(node2.
"${name}"
)
}
as
Comparator
//
排序
Collections.
sort
(
this
.list,comparator)
}
}
}
真的很简单。下面我们来测试一些这个类:
def
sorter =
new
SortHelper(scores)
sorter.sortByChinScore()
scores.
each
{
println
it.name
}
结果为:
Mike
Tom
Alice
从语文成绩来看,
Mike 88
,
Tom 90
,
Alice 100
。排序是正确的。下面我们以数学成绩排序:
sorter.sortByMathScore()
scores.
each
{
println
it.name
}
结果为:
Alice
Mike
Tom
从数学成绩来看,
Alice 55
,
Mike 90
,
Tom 99
,排序也没有问题。大家可以再测几个看看。
像这样的功能的确够酷,我们今后在
Groovy/Grails
平台会经常遇到;同时,这样一个思想也可以发展成
DSL
的一种实现。