Groovy闭包和DSL

闭包是Groovy的一个非常重要的特性,可以说他是DSL的基础。闭包不是Groovy的首创,但是它支持这一重要特性,这就使用我们的代码灵活、轻量、可复用,再也不用像Java一样动不动就要搞一个类了,虽然Java后来有了匿名内部类,但是一样冗余不灵活。

初识闭包

前面我们讲过,闭包其实就是一段代码块,下面我们就一步步实现自己的闭包,了解闭包的it变量的由来。集合的each方法我们已经非常熟悉了,我们就以其为例,实现一个类似的闭包功能。

task helloClosure << {    //使用我们自定义的闭包
    customEach {
        println it
    }
}
def customEach(closure){    //模拟一个有10个元素的集合,开始迭代
    for(int i in 1..10){
        closure(i)
    }
}

在上面的例子中我们定义了一个方法customEach,它只有一个参数,用于接收一个闭包(代码块),那么这个闭包如何执行呢?很简单,跟一对括号就是执行了,会JavaScript的朋友是不是觉得很熟悉,把它当做一个方法调用,括号里的参数就是该闭包接收的参数,如果只有一个参数,那么就是我们的it变量了。

向闭包传递参数

上一节我们讲了,当闭包有一个参数时,默认就是it;当有多个参数是,it就不能表示了,我们需要把参数一一列出。

task helloClosure << {    //多个参数
    eachMap {k,v ->
        println "${k} is ${v}"
    }
}
def eachMap(closure){ 
    def map1 = ["name":"张三","age":18]
    map1.each {
        closure(it.key,it.value)
    }
}

从例子中我们可以看到,我们为闭包传递了两个参数,一个key,一个value,便于我们演示。这是我们我们就不能使用it了,必须要显式的声明出来,如例子中的k,v,符号->用于把闭包的参数和主体区分开来。

闭包委托

Groovy闭包的强大之处在于它支持闭包方法的委托。Groovy的闭包有thisObject、owner、delegate三个属性,当你在闭包内调用方法时,由他们来确定使用哪个对象来处理。默认情况下delegate和owner是相等的,但是delegate是可以被修改的,这个功能是非常强大的,Gradle中的很闭包的很多功能都是通过修改delegate实现的。

task helloDelegate << {
   new Delegate().test {
        println "thisObject:${thisObject.getClass()}"
        println "owner:${owner.getClass()}"
        println "delegate:${delegate.getClass()}"
        method1()
        it.method1()
    }
}
def method1(){
    println "Context this:${this.getClass()} in root"
    println "method1 in root"
}
class Delegate {
    def method1(){
        println "Delegate this:${this.getClass()} in Delegate"
        println "method1 in Delegate"
    }
    def test(Closure<Delegate> closure){
        closure(this)
    }
}

运行我们可以看到输出:

thisObject:class build_e27c427w88bo0afju9niqltzf
owner:class build_e27c427w88bo0afju9niqltzf$_run_closure2
delegate:class build_e27c427w88bo0afju9niqltzf$_run_closure2
this:class build_e27c427w88bo0afju9niqltzf in root
method1 in root
this:class Delegate in Delegate
method1 in Delegate

通过上面的例子我们发现,thisObject的优先级最高,默认情况下,优先使用thisObject来处理闭包中调用的方法,如果有则执行。从输出中我们也可以看到这个thisObject其实就是这个构建脚本的上下文,他和脚本中的this对象是相等的。

从例子中也证明了delegate和owner是相等的,他们两个的优先级是owner要比delegate高,所以对于闭包内方法的处理顺序是thisObject>owner>delegate。

在DSL中,比如Gradle,我们一般会指定delegate为当前的it,这样我们在闭包内就可以对该it进行配置,或者调用其方法。

task configClosure << {
    person {
        personName = "张三"
        personAge = 20
        dumpPerson()
    }
}
class Person {
    String personName    int personAge
    def dumpPerson(){
        println "name is ${personName},age is ${personAge}"
    }
}
def person(Closure<Person> closure){
    Person p = new Person();
    closure.delegate = p    //委托模式优先
    closure.setResolveStrategy(Closure.DELEGATE_FIRST);
    closure(p)
}

例子中我们设置了委托对象为当前创建的Person实例,并且设置了委托模式优先,所以我们在试用person方法创建一个Person的实例时,可以在闭包里直接对该Person实例配置,有没有发现和我们在Gradle试用task创建一个Task的用法很像,其实在Gradle中有很多类似的用法,在Gradle也基本上都是使用delegate的方式使用闭包进行配置等操作。

DSL

DSL(Domain Specific Language),领域特定语言,说白了就是专门关注某一领域专门语言,在于专,而不是全,所以才叫领域特定的,而不是像Java这种通用全面的语言。

Gradle就是一门DSL,他是基于Groovy的,专门解决自动化构建的DSL。自动化构建太复杂、太麻烦、太专业,我们理解不了,没问题,专家们就开发了DSL—Gradle,我们作为开发者只要按照Gradle DSL定义的,书写相应的Gradle脚本就可以达到我们自动化构建的目的,这也是DSL的初衷。

DSL涉及的东西还有很多,这里我们简单的提一下概念,让大家有个了解,关于这方便更详细的可以阅读世界级软件开发大师Martin Fowler的《领域特定语言》,这本书介绍的非常详细。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,098评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,213评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,960评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,519评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,512评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,533评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,914评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,574评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,804评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,563评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,644评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,350评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,933评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,908评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,146评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,847评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,361评论 2 342

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,580评论 18 139
  • 努力的人,应该像好色那样好学 做Android开发的同学,对Gradle肯定不陌生,我们用它配置、构建工程,可能还...
    HitenDev阅读 13,346评论 9 50
  • 本文介绍了Groovy闭包的有关内容。闭包可以说是Groovy中最重要的功能了。如果没有闭包,那么Groovy除了...
    乐百川阅读 7,543评论 3 13
  • 这篇文章讲给大家带来gradle打包系列中的高级用法-自己动手编写gradle插件。我们平常在做安卓开发时,都会在...
    呆萌狗和求疵喵阅读 15,969评论 22 80
  • 学习Gradle,前前后后总结了一些内容,然后整理出了一个系列,共计10篇文章,与大家分享: Groovy基本介绍...
    sososeen09阅读 1,806评论 0 7