`
flyisland
  • 浏览: 82775 次
  • 性别: Icon_minigender_1
  • 来自: 广州
社区版块
存档分类
最新评论

[groovy]通过builder了解groovy的动态性

阅读更多
Builder是Groovy相当有用的一个特性,样例常常用生成XML来展现Builder所带来的便利性,例如要生成下述的XML文档:
xml 代码
 
  1. <books amount='2'>  
  2.   <description>books to lean groovy<!---->description>  
  3.   <book1 name='Groovy in Action' ISBN='1-932394-84-2' />  
  4.   <book2 name='Getting Started with Grails' ISBN='978-1-4303-0782-2' />  
  5. <!---->books>   

所使用的Groovy代码是:
import  groovy.xml.MarkupBuilder
 
def xml = new MarkupBuilder()
 
xml.books(amount:2) {
 description 'books to lean groovy'
 book1 (name:'Groovy in Action', ISBN:'1-932394-84-2')
 book2 (name:'Getting Started with Grails', ISBN:'978-1-4303-0782-2')
}
 
xml.println()
 
从例子可以看到,在groovy中创建xml是相当的便利,你可以写一个相应功能的java程序来对照。实际上这个groovy代码结构跟所生成的html结果十分相似,从某种意义上来说,这像是在使用创建"BOOK XML"的专用的DSL了。
 
我第一次看到这样代码的时候,心里很是疑惑,这是什么语法,为什么groovy自身的“groovy.xml.MarkupBuilder”类会有books这个方法?慢慢了解其中的机制后,觉得builder真是groovy精华的集大成者,所谓“解脱之味不独饮”,在此与朋友分享。
 
1. groovy中是如何调用方法的?
 
groovy基本上是兼容java语法的,但是为了更加方便开发人员,groovy作了许多便利的改进,比如说方法调用中省略括号
description 'books to lean groovy'
等同于
description('books to lean groovy')
 
所以在java中常用的打印语句
System.out.println("Hello World!");
可以简写为:
println "Hello World!"
 
同时调用方法的时候,传递参数可以加上参数的名字,例如
def method1(String name, int age)
的调用方式可以是:
method1 (age:30, name:"Tom")
 
而groovy方法调用中与我以前所接触语言的最大不同就是Closure作为参数,而为了方便编写代码,一般也是将Closure写在方法调用的最后,因此上述代码的:
xml.books(amount:2) {
...
}
等同于
xml.books(amount:2, {...})
 
这样一来上述代码的字面意思就明白了,是方法调用中包含Closure,Closure中又包含方法调用的混合体,不过用了groovy的特殊写法。
 
(注:关于groovy中方法调用的更详细说明,请参考Groovy Statmements
 
2. 无中生有的方法
 
知道上述语句的字面意思后,但还是不知道为什么这些方法调用会成功呢,因为我们的代码并没有定义这些方法。
 
在groovy中,所有的东西都是对象,而所有的对象都必须实现GroovyObject接口,该接口定义的方法不多,其中一个是:
Object invokeMethod(String name, Object args)。
 
原来在groovy中,编译器会将所有的方法调用转换成对invokeMethod的调用,例如:
xml.books(amount:2) {
...
}
会转换成
xml.invokeMethod("books", list of parameters)
 
groovy会将方法中的参数放入一个列表,作为invokeMethod()方法的第二个参数,invokeMethod()缺省实现将调用对象的同名函数,所以平时你对此是没有察觉。
 
也就是说MarkupBuilder不必事先定义books(), book1()这些方法,它可以假装拥有这些方法,只需要在invokeMethod()的实现中根据name和args的值生成相应的xml代码即可。
 
实际上,在GroovyObject接口背后还有一个更加重要的MetaClass,从而使得groovy对象可以在运行时更改对象和类的行为,在groovy中可以轻易做到的有:
1)假装拥有某些方法,这就是MarkupBuilder干的,我觉得这一点在GPath中发挥的淋漓尽致!
2)在语言级别支持Intercept模式
3)将对自身方法的调用委派给其他对象完成(Delegate模式)
 
3. 更加灵活的方法名
 
注意到invodeMethod()的name参数是String类型,我第一个想法就是是否能够用字符串来做方法名呢,例如:
xml."books"(amount:2) {
...
}
 
实验结果证实这样的写法是OK的,而因为groovy中字符串的特性,上述代码还可以这么写:
import  groovy.xml.MarkupBuilder
 
def xml = new MarkupBuilder()
def names = ['Groovy in Action', 'Getting Started with Grails']
def isbns = ['1-932394-84-2', '978-1-4303-0782-2']
 
xml.books(amount:names.size()) {
 description 'books to lean groovy'
 for(int i in 0..(names.size()-1)){
  def s = "book"+(i+1)
  "$s"(name:names[i],ISBN:isbns[i])
 }
}
 
xml.println()
 
我最近在编写一个数独解题程序,就大大享受到字符变量做方法名的好处。因为在解题中往往要对“行/列”两种情况都做一次,代码结构基本一致,只是多处调用的方法名和属性名不同。在普通Java程序中,要将这样的两段代码合并成一个方法少不了一大堆的if..then语句,而groovy只需要在开头设置好方法名即可,极为方便。
 
4. 创建自己的builder
 
如果你喜欢groovy builder这种模式,也可以创建自己builder,只要你的程序中存在用Builder模式可以解决的问题,groovy必然能帮上大忙,而且十分简便、优雅。
 
创建自己的builder也很简单,只需要继承BuilderSupport类,并实现其中几个抽象方法包括:
1)四种形式的createNode方法,groovy会根据你使用的形式自动调用相应的方法
方法名 参数形式 使用样例
createNode Object name foo()
createNode
Object name, Object value
foo('x')
createNode Object name, Map attributes foo(a:1)
createNode Object name, Map attributes, Object value foo(a:1, 'x')
 
2) void setParent(Object parent, Object child)
设置树状继承层次,当你创建子元素的时候,该方法就会被调用
 
3)void nodeCompleted(Object parent, Object node)
在子元素定义完毕后,该方法也会被自动调用。
 
例如上述生成xml的代码会被转换成以下的调用方式:
import  groovy.xml.MarkupBuilder
 
def xml = new MarkupBuilder()
def names = ['Groovy in Action', 'Getting Started with Grails']
def isbns = ['1-932394-84-2', '978-1-4303-0782-2']
 
def books = xml.createNode('books', [amount:names.size()])
def des = xml.createNode('description', 'books to lean groovy')
xml.setParent(books, des)
xml.nodeCompleted(books, des)
for(int i in 0..(names.size()-1)){
 def s = "book"+(i+1)
 def book = xml.createNode(s, [name:names[i],ISBN:isbns[i]])
 xml.setParent(books, book)
 xml.nodeCompleted(books, book)
}
xml.nodeCompleted(null, books)
 
xml.println()
 
在Groovy中令人感兴趣的Builder还有:
1)SwingBuilderGroovySWT,用于生成Swing/SWT界面,UI界面用Builder模式来产生是再合适不过的了。不过GroovySWT的发展似乎不如SwingBuilder好,在用户邮件列表中常常提到SwingBuilder,而GroovySWT则好长时间没有被人关注了。
 
2)属于Grails项目的Spring Bean Builder,通过Builder来编写Spring的配置文件要比写XML简洁一百倍,而且更重要的是你可以很方便地在运行时动态生成Spring配置。
 
通过这些精彩例子,相信你不难发现groovy builder能够在你程序中大展身手的地方。
 
这篇文章就到这里,希望我所描述的能够引发你去了解groovy的兴趣,groovy的确是个好东西!
 
 
注:
在本文中还有一个关键的地方没有说明,就是Cloure中的方法调用
{
  description 'books to lean groovy'
}  
 
为什么会触发调用xml.createNode()方法?说明这个问题的主要关键有两个:
1)Closure中变量、方法的作用范围,我们在Closure中能够访问到谁的变量、方法,为什么?
2)Closure是如何将对自身方法的访问“委派”给其他对象的?
如果我够勤奋的话,我会在另一篇blog讨论这两个问题 :)
分享到:
评论
4 楼 dennis_zane 2007-10-18  
这些东西可能对没有接触过动态语言的java程序员们觉的新鲜,可Cloure、block等等所谓groovy的特性都是N多动态语言一直在用的东西。
3 楼 geszJava 2007-10-18  
精辟~~~~
2 楼 agile_boy 2007-08-10  
还有,可否将这样的Groovy的主题文章,也发布到Grails/Groovy的圈子里,也让广大Groovy fans来一起受益。
1 楼 agile_boy 2007-08-10  
写的不错啊,看得出,对Groovy研究挺深啊,恭喜啊!

相关推荐

    Java调用Groovy,实时动态加载数据库groovy脚本

    Java调用Groovy,实时动态加载数据库groovy脚本,java读取mongoDB的groovy脚本,加载实时运行,热部署

    java 动态脚本语言 精通 Groovy

    java 动态脚本语言 精通 Groovy

    Groovy EMF Builder-开源

    Groovy EMF Builder可用于使用Groovy Builder语法创建EMF模型。

    groovy 最新 学习 动态

    groovy 敏捷 开发 动态 语言 急速 web 应用 开发

    groovy-loader:在文件目录中动态加载Groovy脚本

    groovy-loader load groovy scripts in file directory dynamically ...spring配置文件使用标签lang:groovy,通过指定script-source来加载指定路径下的groovy脚本,通过refresh-check-delay属性来定时

    apache-groovy-3.0.8.zip apache官网的groovy3.0.8版本

    apache-groovy-3.0.8.zip apache官网的groovy3.0.8版本,希望大家多多下载,apache-groovy-3.0.8.zip apache官网的groovy3.0.8版本,希望大家多多下载,apache-groovy-3.0.8.zip apache官网的groovy3.0.8版本,希望...

    groovy-3.0.9-API文档-中文版.zip

    赠送jar包:groovy-3.0.9.jar; 赠送原API文档:groovy-3.0.9-javadoc.jar; 赠送源代码:groovy-3.0.9-sources.jar; 赠送Maven依赖信息文件:groovy-3.0.9.pom; 包含翻译后的API文档:groovy-3.0.9-javadoc-API...

    JUN SpringBoot API Service 是一个基于SpringBoot+Groovy+SQL动态生成API

    JUN SpringBoot API Service 是一个基于SpringBoot+Groovy+SQL动态生成API并动态发布,且发布后可动态执行groovy脚本及SQL脚本的API服务项目。提供在线执行动态程序脚热加载本及动态生成API并执行的功能。支持动态...

    JVM 动态执行Groovy脚本的方法

    对javax.script包进行讲解,实现支持java动态嵌入执行groovy代码片段

    [Groovy] Making Java Groovy 英文版

    Making Java Groovy is a practical handbook for developers who want to blend Groovy into their day to day work with Java It starts by introducing the key differences between Java and Groovy and how you...

    精通 Groovy--下一代开发语言

    什么是 Groovy?...从学习的角度看,如果知道如何编写 Java 代码,那就已经了解 Groovy 了。Groovy 和 Java 语言的主要区别是:完成同样的任务所需的 Groovy 代码比 Java 代码更少。(有时候会少很多!)

    groovy入门经典,groovyeclipse 插件

    groovy入门经典,groovyeclipse 插件

    apache-groovy-sdk-2.4.11

    本文适合于不熟悉 Groovy,但想快速轻松地了解其基础知识的 Java开发人员。了解 Groovy 对 Java 语法的简化变形,学习 Groovy 的核心功能,例如本地集合、内置正则表达式和闭包。编写第一个 Groovy 类,然后学习如何...

    Groovy入门经典.pdf

     本书是有关Groovy的第一本正式出版物,作者KennethBarclay和JohnSavage介绍了Groovy开发的所有主要领域,并解释了这种创新性的编程语言给Java平台赋予的动态特性。阅读本书只要求具备Java编程的一般性知识。不管你...

    Groovy-3.0.jar

    Groovy jar包 3.0.

    groovy-2.3.6-installer

    groovy-2.3.6-installer windows安装版本

    groovy-loader-v2:在文件目录中动态加载Groovy脚本

    动态加载指定目录下的groovy脚本,并将其注册为groovy bean,放置于ApplicationContext容器中,并使用命名空间进行分类区分(一个namespace对应于一个ApplicationContext)。同时能够动态感知到groovy脚本的新增、修改...

    Groovy.in.Action.2nd.Edition.1935182

    Groovy in Action, Second Edition is the undisputed definitive reference on the Groovy language. Written by core members of the Groovy language team, this book presents Groovy like no other can—from ...

    微服务项目中添加groovy文件技巧.docx

    软件项目的可扩展性和动态维护性是非常重要的,例如在微服务的网关动态过滤器中,要实现过滤器的动态更新而不影响项目的持续运行,就需要借助groovy的动态编译功能,而这个功能是通过 .groovy文件实现的。...

Global site tag (gtag.js) - Google Analytics