`
flyisland
  • 浏览: 83675 次
  • 性别: 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研究挺深啊,恭喜啊!

相关推荐

    Groovy EMF Builder-开源

    2. **动态性与灵活性**:Groovy的动态特性允许在运行时进行代码修改,这对于原型设计和快速迭代开发尤其有利。 3. **集成Eclipse生态**:由于EMF是Eclipse的一部分,Groovy EMF Builder可以无缝地融入Eclipse IDE,...

    groovy+in+action

    - **Builder模式**:Groovy通过Builder模式简化了XML和其他结构化数据的生成。 - **GDK(Groovy Development Kit)**:GDK扩展了Java类库的功能,为常见任务提供了更简洁的API。 - **数据库编程**:Groovy提供了...

    groovy in action 中文版 2017.11

    Groovy提供了大量的动态特性,比如动态类型、闭包、元编程能力等,使得编写脚本或应用程序变得更加高效和愉悦。Groovy是完全兼容Java的,这意味着Java开发人员可以轻松地使用Groovy编写程序,并利用Groovy提供的强大...

    groovy in action.pdf

    这部分内容深入探讨了Groovy如何通过动态类型和元编程支持动态对象导向编程。 ### Groovy库的应用 #### 工作于建造者 Groovy提供了一种名为Builder的模式,用于简化XML和HTML等格式的文本生成,这部分内容介绍了...

    groovy http请求

    Groovy是一种基于Java平台的、动态的、面向对象的编程语言,它被广泛用于脚本编写、自动化任务、测试等领域。在Groovy中发送HTTP请求是开发者经常需要进行的操作,尤其是在进行API测试或者集成第三方服务时。下面...

    Groovy and Grails Recipes(清晰PDF)

    ### Groovy and Grails ...通过这些章节的学习,读者将能够全面了解Groovy编程语言和Grails框架,并掌握如何使用它们来开发高效、可维护的应用程序。无论是新手还是有经验的开发者,都能从中获得宝贵的知识和实践经验。

    Groovy User Guide

    《Groovy User Guide》为开发者提供了一个全面了解 Groovy 的机会,无论是对于初学者还是有经验的开发者都非常有用。通过学习这份文档,开发者可以更好地掌握 Groovy 的特性和功能,并将其应用于实际项目中。此外,...

    groovy编写webservice服务端和客户端(含连接数据并输出JSON数据)

    Groovy是一种基于Java平台的动态语言,它在Java生态系统中常用于快速开发和脚本编写。 1. **Groovy语言基础**: - Groovy是JVM上的一个开源语言,语法简洁,支持面向对象、函数式编程。 - 它兼容Java代码,可以...

    Java 开发 2_0 通过 CouchDB 和 Groovy 的 RESTClient 实现 REST

    Groovy是一种基于JVM的动态编程语言,它简化了Java的语法并增加了许多便利特性。Groovy的RESTClient库是一个强大的工具,用于发送HTTP请求并处理响应,这对于与CouchDB进行交互非常实用。RESTClient库支持GET、POST...

    Groovy in Action

    - **学习目标**: 理解Groovy动态特性的原理,能够利用这些特性来构建更灵活的应用程序。 **第8章: Working with Builders** - **内容概述**: 介绍Groovy中的构建器(builder)机制,这是一种高效的数据结构创建方式...

    yangbuilder:使用Groovy构建器为Yang建模语言生成YANG模型(https:en.wikipedia.orgwikiYANG)

    Groovy是一种面向对象的、动态类型的Java平台语言,它的语法简洁,支持闭包和DSL(领域特定语言)构造,这使得Groovy成为创建自定义构建器的理想选择。`YangBuilder` 就是利用了Groovy的这些特性,让YANG模型的编写...

    shell-2.1.0.Final.zip

    1. 支持Groovy语法,提供动态类型的灵活性。 2. 提供了一个交互式的命令行界面,方便调试和测试。 3. 可以轻松执行Java类库中的方法,便于与现有的Java项目集成。 4. 内置了对脚本控制流、字符串操作和集合处理的...

    SpringOne2GX2010-GuillaumeLaforge.pdf

    根据给定的文件信息,我们可以提炼...通过以上分析,我们可以看到SpringOne2GX2010大会不仅回顾了Groovy的发展历程,还展望了其未来的方向,展示了Groovy作为一种动态语言如何持续进化,以适应不断变化的软件开发需求。

    朋友想爬一个网站的软文,俺顺便做个视频,分享下

    Groovy是一种基于Java平台的动态编程语言,它具有简洁的语法和强大的功能,常用于构建脚本和快速原型开发。在创建网络爬虫时,Groovy可以利用其与Java的互操作性,利用如Jsoup或Apache HttpClient等库来解析HTML和...

    【Java】中常见的URL问题及解决方案Java基础教程.docx

    在Java编程中,URL(Uniform Resource Locator)是用于定位网络资源的重要工具。本文将深入探讨Java中常见的URL...同时,对于Groovy或其他库的使用,了解其对URL处理的方式也非常重要,以确保代码的健壮性和兼容性。

    Android-以最简洁的Api让Retrofit同时支持多个BaseUrl以及动态改变BaseUrl

    本文将详细介绍如何通过一个名为RetrofitUrlManager的库,以最简洁的API实现Retrofit支持多个BaseUrl以及动态改变BaseUrl的功能。 首先,了解RetrofitUrlManager。这是一个由JessYan编写的开源库,专门为Retrofit...

    IBM Project ZERO - OFFICIAL REDBOOK - Java Web Server n PHP to JVM Compiler

    #### 知识点解析 **一、项目概述** **IBM Project ZERO** 是IBM推出的一个全新的企业级应用...通过对本书的学习,开发者不仅可以掌握如何使用Project ZERO进行高效开发,还能了解到最新的Web技术趋势和发展方向。

    图书馆

    Groovy是一种动态、灵活的编程语言,它在Java平台上运行,并与Java紧密集成。这个名为“图书馆”的项目可能是一个使用Groovy...通过Groovy的灵活性和简洁性,开发者可以高效地创建和维护一个功能完备的图书馆管理系统。

Global site tag (gtag.js) - Google Analytics