Groovy探索之方法调用的动态性
在我以前的文字中,我一再强调,Groovy语言的方法也和Java语言的方法一样,是要依赖于类和对象的,因此,方法不能被单独作为对象传递和循环。同时,在《Groovy探索之闭包 八》中,我们提出来一个能让方法进行传递和循环的一个替代方案,这就是使用闭包来代替方法。
其实,Groovy语言的方法虽然也依赖于类和对象,但却并不妨碍Groovy语言的方法调用的动态性,也使得Groovy语言在方法的调用上与Java语言的不同特点,这就是我们这篇文字所要谈到的内容。
当然,Groovy语言的方法调用的动态性要归功于Gstring的动态性。下面试着举出一些简单的例子来说明。
比如说,我们有一只可爱的小狗,它有一些可爱的动作,现模拟如下:
class Dog
{
def bark() {
println 'woof!'
}
def sit() {
println 'sitting!'
}
def jump() {
println 'boing!'
}
}
现在,我们可以让它依次做上述的三个动作了:
def dog = new Dog()
def acts = ['sit','jump','bark']
acts.each{
dog."${it}"()
}
运行的结果为:
sitting!
boing!
woof!
你会说啊,这基本上可以说是实现了命令模式了,不知道它的扩展性怎么样?我们现在可以试着让小狗多会一些动作了:
class Dog1 extends Dog
{
def run()
{
println 'running...'
}
}
看看小狗会了这个动作没有?
def dog = new Dog1()
def actions = ['sit','jump','bark','run']
actions.each{
dog."${it}"()
}
运行结果为:
sitting!
boing!
woof!
running...
不错啊,也有很好的扩展性。方法的动态性还有一个重要的内容就是要传递方法,这在Groovy语言中也可以通过传递对象来实现。请看下面的例子。
还记得我们在《Groovy探索之闭包 八》中对一盏灯的控制吗?我们有一个开灯的动作,如下:
class LightOn
{
def doing()
{
println 'Ligth turning on...'
}
}
当然,我们也有一个关灯的动作:
class LightOff
{
def doing()
{
println 'Ligth turning off...'
}
}
我们有一个开关,要控制这盏灯,它本身不能控制灯,而是由传入的动作决定的,如下:
class Switch
{
def control(action)
{
action."doing"()
}
}
下面,我们就可以把开关灯的一些动作传递给Switch类的方法了:
def sh = new Switch()
sh.control(new LightOn())
运行结果为:
Ligth turning on...
这个实现就跟Java语言对于命令模式的实现很相似了,只是少了接口。原因是我们在Groovy语言中只要约定所有类的方法名都一样,我们就可以在客户端里使用“对象.方法名()”的形式调用该方法。而不同的动作则是通过对象的不同来区分的,这点跟Java语言很相似。只是在Groovy语言中有了“对象.方法名()”形式的方法调用,就可以不使用接口而调用方法了。
通过这样一种方法调用的动态性,我们就可以实现Java语言中的很多中模式了,比如命令模式和策略模式等等。
再次总结一下上面的Groovy语言的方法调用的动态性的实现,在Groovy语言中,我们可以使用两种方式变相实现方法调用的动态性:一是利用Gstring的动态性,固定类和对象,将方法名作为对象进行循环和传递,再利用“对象.方法名()”来实现方法的动态调用;二是固定方法名,以不同的类和对象来代表不同的动作,然后循环和传递对象,利用“对象.方法名()”来实现方法的动态调用。
两者都是最终要通过“对象.方法名()”来实现方法的动态调用的。那么有人要问了,如果我们的方法有参数的话,该怎么使用呢?
下面试着举出一个例子来说明这个问题,同时作为本篇的结束。
class Tools
{
def max(int i1,int i2)
{
Math.max(i1,i2)
}
}
下面,我们来使用这个Tools类:
def arg = [1,2]
def tools = new Tools()
println tools."max"(*arg)
可以看到,我们将参数按照先后顺序放在一个List对象里,然后再将该对象传给如下的这种形式:
对象.方法名(*List对象)
上面代码的运行结果为:
2