`

[1/3]groovy对DSL的语法支持

阅读更多
转自:http://www.cnblogs.com/chenjie0949/p/4755389.html

引子
我们用一段gradle的脚本做引子,理解这一段脚本与一般的groovy代码是怎么联系起来的

buildscript {
    repositories {
        jcenter()
        mavenLocal()
        //或者使用指定的本地maven 库
        maven{
            url "file://D:/repo"
        }
    }
 
    dependencies {
        classpath 'com.android.tools.build:gradle:1.2.3'
    }
}


DSL的定义

DSL(Domain Specific Language)定义:针对某一领域,具有受限表达性的一种计算机程序设计语言。

所谓针对某一领域,其基本思想是“求专不求全”,不像通用目的语言那样目标范围涵盖一切软件问题,而是专门针对某一特定问题的计算机语言。

DSL伴随语义模型出现,语义模型会表现为程序库或者框架,对于构建DSL而言,语义模型不可或缺。DSL只是位于其上的一层而已。定义做什么,而不是用一堆命令语句来描述怎么做,所以它是声明式编程(如SQL),这一点很重要。DSL的受限表达性可以使DSL语言不易出错,即便出错,也易于发现。这是受限表达性的意义。

DSL是通用语言的特定用法。内部DSL通常是一段合法的程序,但是具有特定的风格。而且只用到了语言一部分特性。防止DSL逐渐演变为一种通用语言,要受限表达。目的防止DSL过于复杂,可维护性降低,学习成本提升,偏离方向。不要让DSL读起来向自然语言。它是程序语言,比自然语言更加准确和简洁。语义模型位于语言和DSL之间,为二者解耦。DSL脚本,解析器,语义模型,模型——DSL自上而下几个层次。

Groovy语法对DSL的支持

我们先看一个简单的类和一个奇葩的语法现象:分号省略;默认public省略;有形参的方法调用,括号可以省略;返回的return可以省略,默认最后一行代码的值返回。
import groovy.xml.*
import java.io.*
 
class Task{
    //默认省略public和分号
    String summary
    String description
    Date dueDate
    Map m
     
    static void main(args){
        //默认有set和get方法
        Task task1 = new Task()
        task1.setSummary("this is Task1")
        println task1.getSummary()
        //有形参的方法调用,括号可以省略
        task1.setDescription "this is Task class"
        task1.printDescription ""
        //可以直接传map
        Task task3 = new Task()
        task3.setM (['summary':'this is Task3','description':'Task'])
        println task3.getM()
        //map的分号可以省略
        Task task2= new Task('summary':'this is Task2','description':'Task')
        println task2.getSummary()
        //括号也可以省略
        Task task4 = new Task()
        task4.setM 'summary':'this is Task4'
        println task4.getM()
    }
     
    public void printDescription(def str){
        println "the task description is : $description"
    }
}



看完省略括号的语法现象,下面看另一个重量级的语法现象——闭包

闭包是用{符号括起来的代码块,它可以被单独运行或调用,也可以被命名。类似‘匿名类’或内联函数的概念。

闭包中最常见的应用是对集合进行迭代,下面定义了3个闭包对map进行了迭代:

       map.each({key,value->    //key,value两个参数用于接受每个元素的键/值
       println "$key:$value"})

       map.each{println it}     //it是一个关键字,代表map集合的每个元素

       map.each({ println it.getKey()+"-->"+it.getValue()})

除了用于迭代之外,闭包也可以单独定义:
def say={word->
           println "Hi,$word!"
       }

调用:
say('groovy')
say.call('groovy&grails')

输出:
Hi,groovy!
Hi,groovy&grails!


看起来,闭包类似于方法,需要定义参数和要执行的语句,它也可以通过名称被调用。然而闭包对象(不要奇怪,闭包也是对象)可以作为参数传递(比如前面的闭包作为参数传递给了map的each方法)。而在java中,要做到这一点并不容易(也许C++中的函数指针可以,但不要忘记java中没有指针)。其次,闭包也可以不命名(当然作为代价,只能在定义闭包时执行一次),而方法不可以。


当闭包遇到括号省略,一切都不一样了

Project.groovy
public class Project{
    Date date
 
    void setDateFormat(Closure formatDate){
       println formatDate(date)
    }
}


Main.groovy
public class Main{
 
    public static void main(def args){
       Project p = new Project()
       p.setDate new Date()
       //正常
       p.setDateFormat({
           return it.format('yyyy-MM-dd HH:mm:ss')
       })
 
       //减return
       p.setDateFormat {
           it.format('yyyy-MM-dd HH:mm:ss')
       }
 
       //减括号(是不是很像我们的gradle脚本?) 
       p.setDateFormat {
           it.format 'yyyy-MM-dd HH:mm:ss'
       }
 
    }
 
}



减完之后,像不像下面的脚本?
dependencies {
       classpath 'com.android.tools.build:gradle:1.2.3'
}

唯一的区别是我们需要用对象来引用方法,其实去掉对象也不难,自己调用自己的方法就可以了,看下面的代码:
public class Project{
    Date date
     
    void setDateFormat(Closure formatDate){
        println formatDate(date)
    }
     
    //将format内置
    String format(String f){
        date.format(f)
    }
    //无形参的方法
    void showDate(){
        print date.toString()
    }
     
    void run(){
        //对象去掉,是不是一模一样了?
        setDateFormat{
            println 'this is a scrip'
            format 'yyyy-MM-dd HH:mm:ss'
            //没有形参的话就只能乖乖写括号了
            showDate()
        }
    }
}


DSL的两个关键点,某一领域,gradle只为编译,也只用于编译。受限表达,一般只调用脚本运行上下文环境中的方法,为的就是尽量简单,出错的话,排错方便。伴随而生的语义模型就是那一套编译框架。

Groovy对DSL的支持,表现为可以省略:分号,调用方法的括号,return,默认public等。
分享到:
评论

相关推荐

    vertx-web-groovy-dsl:简单的Groovy DSL声明Vert.x Apex路由

    vertx-web-groovy-dsl Groovy DSL声明Vert.x Web路由 如果您使用Groovy,则本项目旨在提供另一种方法来使用vert-web定义网络路由,这种方式更具Groovy风格。 最有趣的功能是能够使用嵌套闭包以嵌套方式声明路由器...

    groovy-官网翻译.docx

     对OO(面向对象编程)和Ant DSL 支持更好,在语法层面支持编写、编译shell脚本  减少结构性代码。开发web/GUI/Console程序,效率更高  简化单元testing and mocking  与Java无缝集成,互相调用  与Java...

    groovy2.4.3

    支持DSL(Domain Specific Languages领域定义语言)和其它简洁的语法,让你的代码变得易于阅读和维护。 Goovy拥有处理原生类型,面向对象以及一个Ant DSL,使得创建Shell Scripts变的非常简单。 在开发Web,GUI,...

    alioth-groovy2

    Groovy通过几乎零的学习曲线使Java开发人员可以使用现代编程功能,并支持特定领域语言和其他紧凑语法,因此您的代码变得易于阅读和维护。 Groovy凭借其强大的处理原语,OO能力和Ant DSL,使编写Shell和构建脚本变...

    java开源包7

    1. 完全透明的缓存支持,对业务代码零侵入 2. 支持使用Redis和Memcached作为后端缓存。3. 支持缓存数据分区规则的定义 4. 使用redis作缓存时,支持list类型的高级数据结构,更适合论坛帖子列表这种类型的数据 5. ...

    grampa:语法分析器

    因此,无需学习DSL,整个语法定义就在一个地方(Kotlin类),并且可以很容易地更改和维护。 该库受和启发,但是重点放在简单干净的代码上,而没有很多疯狂和复杂的字节码操作。如何添加到您的构建使用Gradle...

    mirage:Web DSL和命令行工具,可轻松编写简单的HTTP服务器

    高性能: Web框架实现基于 ,而DSL语法则基于 。 要求 Java(1.7或更高版本) Maven(如果构建) 下载/安装 make && make install 发行版二进制文件可从。 用法 usage: mirage [-p ] [-c [removed]] [file|dir].....

    matlab代码转java-gradle-study:学习gradle!

    语法上支持动态类型,闭包等新一代语言的特性 无缝集成所有已经存在的Java类库 支持面向对象编程也支持面向过程编程 :memo:正题篇 变量 groovy提供了和java一样的变量类型:int、char、boolean、balabala...........

    java开源包3

    1. 完全透明的缓存支持,对业务代码零侵入 2. 支持使用Redis和Memcached作为后端缓存。3. 支持缓存数据分区规则的定义 4. 使用redis作缓存时,支持list类型的高级数据结构,更适合论坛帖子列表这种类型的数据 5. ...

    java开源包1

    1. 完全透明的缓存支持,对业务代码零侵入 2. 支持使用Redis和Memcached作为后端缓存。3. 支持缓存数据分区规则的定义 4. 使用redis作缓存时,支持list类型的高级数据结构,更适合论坛帖子列表这种类型的数据 5. ...

    org.hl7.fhir.validator-wrapper:CLI,桌面GUI和FHIR验证程序的独立服务器

    验证器包装器 该项目包含CLI,桌面GUI和FHIR验证程序的独立验证服务器 CI状态(主) 网站Docker映像 ... 特别是,我们利用作为传统Groovy DSL的替代语法。 要生成本地包含所有资源的jar: 确保您已Gradle

    gradle-2.3-all

    Gradle 是以 Groovy 语言为基础,面向Java应用为主。基于DSL(领域特定语言)语法的自动化构建工具。这里上传的是gradle-2.3-all,免得要连国外服务器进行下载。

    JAVA上百实例源码以及开源项目源代码

    2个目标文件,FTP的目标是:(1)提高文件的共享性(计算机程序和/或数据),(2)鼓励间接地(通过程序)使用远程计算机,(3)保护用户因主机之间的文件存储系统导致的变化,(4)为了可靠和高效地传输,虽然用户...

    java开源包11

    1. 完全透明的缓存支持,对业务代码零侵入 2. 支持使用Redis和Memcached作为后端缓存。3. 支持缓存数据分区规则的定义 4. 使用redis作缓存时,支持list类型的高级数据结构,更适合论坛帖子列表这种类型的数据 5. ...

    java开源包2

    1. 完全透明的缓存支持,对业务代码零侵入 2. 支持使用Redis和Memcached作为后端缓存。3. 支持缓存数据分区规则的定义 4. 使用redis作缓存时,支持list类型的高级数据结构,更适合论坛帖子列表这种类型的数据 5. ...

    java开源包6

    1. 完全透明的缓存支持,对业务代码零侵入 2. 支持使用Redis和Memcached作为后端缓存。3. 支持缓存数据分区规则的定义 4. 使用redis作缓存时,支持list类型的高级数据结构,更适合论坛帖子列表这种类型的数据 5. ...

    java开源包5

    1. 完全透明的缓存支持,对业务代码零侵入 2. 支持使用Redis和Memcached作为后端缓存。3. 支持缓存数据分区规则的定义 4. 使用redis作缓存时,支持list类型的高级数据结构,更适合论坛帖子列表这种类型的数据 5. ...

    java开源包10

    1. 完全透明的缓存支持,对业务代码零侵入 2. 支持使用Redis和Memcached作为后端缓存。3. 支持缓存数据分区规则的定义 4. 使用redis作缓存时,支持list类型的高级数据结构,更适合论坛帖子列表这种类型的数据 5. ...

    java开源包4

    1. 完全透明的缓存支持,对业务代码零侵入 2. 支持使用Redis和Memcached作为后端缓存。3. 支持缓存数据分区规则的定义 4. 使用redis作缓存时,支持list类型的高级数据结构,更适合论坛帖子列表这种类型的数据 5. ...

    java开源包8

    1. 完全透明的缓存支持,对业务代码零侵入 2. 支持使用Redis和Memcached作为后端缓存。3. 支持缓存数据分区规则的定义 4. 使用redis作缓存时,支持list类型的高级数据结构,更适合论坛帖子列表这种类型的数据 5. ...

Global site tag (gtag.js) - Google Analytics