Groovy "with"

首先看一段Java代码:java

// PrintIndependenceDay.java

import java.util.Calendar;
import java.util.Date;

public class PrintIndependenceDay {

  public static void main(String[] args) {
    Calendar calendar = Calendar.getInstance();
    calendar.clear();
    calendar.set(Calendar.MONTH, Calendar.JULY);
    calendar.set(Calendar.DATE, 4);
    calendar.set(Calendar.YEAR, 1776);
    Date time = calendar.getTime();
    System.out.println(time);
  }
}

这段代码中咱们得到Calendar的实例,而后反复的调用它的方法。是否以为冗余,由于咱们的上下文环境是已知的,在Groovy中咱们利用“with”来简化,上面的代码等价的Groovy代码以下:闭包

// PrintIndependenceDay.groovy

def calendar = Calendar.instance
calendar.with {
  clear()
  set MONTH, JULY
  set DATE, 4
  set YEAR, 1776
  println time
}

是否是很简洁,咱们还有更炫的功能,这要得益于delegate机制,看下面的例子:app

// define a closure
def myClosure = {
  // call a method that does not exist
  append 'Jeff'
  append ' was here.'
}

// assign a delegate to the closure
def sb = new StringBuffer()
myClosure.delegate = sb

// execute the closure
myClosure()

assert 'Jeff was here.' == sb.toString()

经过动态机制,咱们把闭包操做委托给了StringBuffer,咱们要注意的是传递给闭包的只是StringBuffer的一个cloneide

同时咱们还应该注意另一点,首先看下面这个例子:测试

class ResolutionTest {  
      
    def append(arg) {  
        println "you called the append method and passed ${arg}"  
    }  
      
    def doIt() {  
        def myclosure = {  
            append 'Jeff was here.' 
        }  
          
        def buffer = new StringBuffer()  
          
        myclosure.delegate = buffer  
          
        // the append method in this ResolutionTest  
        // will be called because resolveStrategy is  
        // OWNER_FIRST (the default)  
        myclosure()

        println '---------------------------------'  

        // give the delegate first crack at method  
        // calls made inside the closure  
        myclosure.resolveStrategy = Closure.DELEGATE_FIRST  
          
        // the append method on buffer will  
        // be called because the delegate gets  
        // first crack at the call to append()  
        println myclosure()  
    }  
      
    static void main(String[] a) {  
        new ResolutionTest().doIt()  
    }  
}

输出结果:this

you called the append method and passed Jeff was here.
---------------------------------
Jeff was here.

这里咱们要注意闭包一个高级特性:闭包内部有一个策略来决定什么时候把调用发送给委托者,每个Groovy的闭包有一个与之关联的属性:resolveStrategy。它有四个常量取值:OWNER_FIRST, DELEGATE_FIRST, OWNER_ONLY and DELEGATE_ONLY(都定义在groovy.lang.Closure中,默认取值为:OWNER_FIRST)spa

 

Groovy "with"的问题: code

 

首先看一段测试代码:get

class Foo {
    def add(x) {
        println "wrong add: $x"
    }
    def doit(x) {
        def n = [1,2,3]       
        n.with {
          add(x)
          each { println it }
        }

        n.add("after")     
        println n
    }
    def test() {
        doit("before")        
    }
}
new Foo().test()

打印结果为:it

wrong add: before
Foo$_doit_closure1@1979eb
[1, 2, 3, "after"]

      从闭包的解析策略,咱们看到,默认的策略为OWNER_FIRST,这样的话,至关于咱们with中的全部调用都会委托给owner,这样的问题是,若是咱们未来在闭包外增长了一个同名的方法,那么with中的调用将不会按照预期进行,好的解决方法是在with中手动指定策略为DELEGATE_ONLY。

      从上面的分析咱们不难看懂最后的这个例子,由于each操做是Objec的方法,他其实调用的是Object的方法,这样咱们的with中就不能调用全部Object的方法!