【问题标题】:On closures and groovy builder pattern关于闭包和 groovy builder 模式
【发布时间】:2026-02-14 01:35:05
【问题描述】:

开始掌握一般的闭包和一些常规功能。

给定以下代码:

class Mailer {
    void to(final String to) { println "to $to" }
    void from(final String from) { println "from $from" }

    static void send(Closure configuration) {
        Mailer mailer = new Mailer()
        mailer.with configuration
    }  
}

class MailSender {
    static void sendMessage() {
        Mailer.send {
            to 'them'
            from 'me'
        }
    }
}

MailSender.sendMessage()

当您将闭包传递给Mailer.send 方法时,幕后会发生什么?

tofrom 是否从闭包的角度作为参数传递? Closure 映射了哪些类型?

然后在Mailer.send方法内部,此时Mailer对象调用mailer.with接收configuration对象,对象将它们映射成方法调用。 Groovy 通过反射来做到这一点?

【问题讨论】:

    标签: groovy


    【解决方案1】:

    Groovy 可以动态地 define the delegate 的闭包,甚至是 this 对象。

    with 正在设置委托并执行闭包。这是实现相同目的的详细方法:

    def math = {
        given 4
        sum 5
        print
    }
    
    
    class PrintMath {
        def initial
        def given(val) {
            initial = val
        }
    
        def sum(val) {
            initial += val
        }
    
        def getPrint() {
            println initial
            return initial
        }
    }
    
    math.delegate = new PrintMath()
    math.resolveStrategy = Closure.DELEGATE_ONLY
    
    assert math() == 9
    

    当您将闭包传递给 Mailer.send 方法时,幕后会发生什么?

    它接收到一个尚未执行的代码块。

    从闭包的角度来看,to 和 from 是否作为参数传递?

    不,最好将它们视为 java 中的匿名类/lambda,或者 javascript 中的 function(){}

    闭包映射了哪些类型?

    没有,它们是等待执行的方法调用。不过,它们可以委托给不同的对象。

    然后在Mailer对象调用mailer.send的那一刻Mailer.send方法内部接收到配置对象,对象将它们映射成方法调用。 Groovy 通过反射来做到这一点?

    您可以decompile a Groovy class file 看看发生了什么。 IIRC,Groovy 目前使用“反射器”策略(带有arrayOfCallSite 缓存)来更快地进行调用,或者它可以使用invokedynamic

    上面代码中的闭包math会产生这个类:

    // .. a lot of techno-babble
    
    public Object doCall(Object it) {
        CallSite[] arrayOfCallSite = $getCallSiteArray();
        arrayOfCallSite[0].callCurrent(this, Integer.valueOf(4));
        arrayOfCallSite[1].callCurrent(this, Integer.valueOf(5));
        return arrayOfCallSite[2].callGroovyObjectGetProperty(this);
        return null;
    }
    

    【讨论】: