关于闭包的使用在官方文档中已经说明的很清楚了,这里再对闭包的委托机制进行说明,该机制对于 Groovy 开发,gradle 脚本编写非常重要!

要理解闭包,那么就必须要了解闭包中的三个属性,该属性仅在闭包中可以使用!

  1. this:该属性指向定义闭包的类的实例对象
  2. owner:该属性和 this 类似,但是闭包中也可以定义闭包的,如果闭包 A 内定义了闭包 B,那么闭包 B 的 owner 指向的是其外部的闭包 A; 顾名思义,owner 指的是改闭包的 owner
  3. delegate:该值初始化时是和 owner 相同的,但是该值可以通过接口将其它对象赋值给 delegate,来实现方法的委托功能,这正是 groovy 精彩之处!

接下来以一组简单的示例了解一下这三个属性,以验证上面的说明

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
//普通类
class Enclosing {
void run() {
def whatIsThisObject = { getThisObject() } //1
assert whatIsThisObject() == this //2
def whatIsThis = { this } //3
assert whatIsThis() == this //4


def whatIsOwnerMethod = { getOwner() } //1
assert whatIsOwnerMethod() == this //2
def whatIsOwner = { owner } //3
assert whatIsOwner() == this //4

}


}


//内部类
class EnclosedInInnerClass {
class Inner {
Closure c_this = { this } //5
Closure c_owner = { owner }
}

void run() {
def inner = new Inner()
assert inner.c_this() == inner //6
assert inner.c_owner() == inner
}
}

//闭包嵌套定义
class NestedClosures {
void run() {
def nestedClosures_this = {
def c_this = { this } //7
c_this()
}
assert nestedClosures_this() == this //8

def nestedClosures_owner = {
def c_owner = { owner } //7
c_owner()
}
//owner 对应闭包,这就是 owner 和 this 的不同!!
assert nestedClosures_owner() == nestedClosures_owner //8
}
}

new Enclosing().run()
new EnclosedInInnerClass().run()
new NestedClosures().run()

通过上边了示例,我们应该对闭包中的这三个属性有了一个大致的了解,并且知道了在不同的情况下,这些属性指向的对象是什么。
之前在理解闭包的时候,看到了讲解都在说你可以把闭包理解成匿名函数 Lambdas,但是如果闭包仅仅是 Lambdas,那么有何必另起一个 Closure 的名称,而不直接叫 Lambdas 呢?
而且 Lambdas 中并不存在 this,owner,delegate 的概念,所以要记住 Closure 并不仅仅是 Lambdas,其还有比 Lambdas 更酷的功能。而这些所谓的酷功能正是由 this,owner,delegate 来实现的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class MyClass {
String myString1 = "111"

def outerClosure = {
def myString2 = "222";
println myString1; // outputs 111

def nestedClosure = {
println myString1; // outputs 111
println myString2; // outputs 222,前面都是用的默认的 this,访问到外部的 111, 这个可以理解,但是 str2 也用的 this 是如何访问到的呢?
}

nestedClosure()
}
}

MyClass myClass = new MyClass()
def closure = new MyClass().outerClosure
closure()

运行上面程序,可以发现,闭包内的 this 指向的定义该闭包的类的实例对象(即:上下文)。在闭包内引用的变量和方法都会绑定到 this,其负责处理任何方法调用,以及对任何属性的访问。如果 this 无法处理,则转向 owner,最后在转给 delegate,如果再找不到,那么就会抛出异常。这就是 groovy 提供的默认的策略 this -> owner -> delegate

当然该顺序也是可以改变的,可以通过闭包的 resolveStrategy 属性,指定不同的策略。

  • Closure.OWNER_FIRST 是默认策略。如果属性或者方法存在于 owner 内,那么他可以被 owner 调用,如果不存在,则会尝试在 delegate 类中查找
  • Closure.DELEGATE_FIRST 颠倒了默认逻辑:delegate 是第一优先级,其次才是 owner
  • Closure.OWNER_ONLY 将仅仅在 owner 查找需要的属性或者方法:delegate 会被忽略
  • Closure.DELEGATE_ONLY 将仅仅在 delegate 查找需要的属性或者方法:owner 会被忽略
  • Closure.TO_SELF 可以被用于当开发人员需要使用先进的元数据编程技术和希望实现一个自定义的选择策略时:这个选择将不是 owner 或者 delegate,而仅仅是 closure 类自己。当我们实现了自己的 Closure 子类时,他才是有意义的。

下面简单介绍一下其使用方法,以及效果

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class Test {
def x = 300
def y = 400

def run() {
def data = [x: 10, y: 20]
def cl = { y = x + y }
cl.delegate = data
cl()
println x
println y
println data
}
}

new Test().run()

结果:

1
2
3
300
700
[x:10, y:20]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class Test {
def x = 300
def y = 400

def run() {
def data = [x: 10, y: 20]
def cl = { y = x + y }
cl.delegate = data
cl.resolveStrategy = Closure.DELEGATE_FIRST
cl()
println x //这里不是在闭包中,访问的 x 当然还是成员变量了
println y
println data // 主要是 data,在闭包中期访问的 x 和 y 均是 data 中,所以其 y 变成了 10+20;
}
}

new Test().run()

结果:

1
2
3
300
400
[x:10, y:30]