﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>BlogJava-JafeLee-文章分类-Groovy</title><link>http://www.blogjava.net/JafeLee/category/23891.html</link><description /><language>zh-cn</language><lastBuildDate>Fri, 06 Jul 2007 18:18:43 GMT</lastBuildDate><pubDate>Fri, 06 Jul 2007 18:18:43 GMT</pubDate><ttl>60</ttl><item><title>alt.lang.jre: 感受 Groovy</title><link>http://www.blogjava.net/JafeLee/articles/128683.html</link><dc:creator>Jafe</dc:creator><author>Jafe</author><pubDate>Fri, 06 Jul 2007 13:35:00 GMT</pubDate><guid>http://www.blogjava.net/JafeLee/articles/128683.html</guid><wfw:comment>http://www.blogjava.net/JafeLee/comments/128683.html</wfw:comment><comments>http://www.blogjava.net/JafeLee/articles/128683.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/JafeLee/comments/commentRss/128683.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/JafeLee/services/trackbacks/128683.html</trackback:ping><description><![CDATA[
		<p>
				<a href="http://www.ibm.com/developerworks/cn/java/j-alj08034/#author">Andrew Glover</a>, CTO, Vanward Technologies<br /></p>
		<p>2004 年  8 月  03 日</p>
		<blockquote>虽然 Java 语言因其严密性和扩展性的承诺而在整整一代程序员中胜出，但是 Groovy 预示了 Java 平台上的一个编程新时代，这种语言是以方便性、适宜性和敏捷性为出发点定义的。在新的
      <i>alt.lang.jre</i>专栏的第二期文章中，Andrew Glover 对提议添加到 Java 平台的标准编程语言作了非正式的介绍。
    </blockquote>
		<!--START RESERVED FOR FUTURE USE INCLUDE FILES-->
		<!-- include java script once we verify teams wants to use this and it will work on dbcs and cyrillic characters -->
		<!--END RESERVED FOR FUTURE USE INCLUDE FILES-->
		<p>如果您在使用
Java 平台（block），不管时间长短，您都有可能听说过 Groovy。Groovy 是超级明星开发人员 James Strachan 和
Bob McWhirter 发明的，它是一种敏捷开发语言，完全以 Java 编程 API 为基础。Groovy 当前正处于 Java
Specification Request 的开始阶段，它于 2004 年 3 月底获得批准。Groovy
还是一种脚本语言，有些人说它会永久性地改变您看待和使用 Java 平台的方式。</p>
		<p>在其对 JSR 241 （请参阅
        <a href="http://www.ibm.com/developerworks/cn/java/j-alj08034/#resources">参考资料</a>）的开放评论中，Groovy 的共同规范领导者 Richard Monson-Haefel 说他对 Groovy 的支持是建立在总有一天 Java 平台要包括一种敏捷开发语言这一信念上。与许多移植到 Java 平台的脚本语言不同，Groovy 是
        <i>为</i>JRE 而写的。在规范请求中（参阅
        <a href="http://www.ibm.com/developerworks/cn/java/j-alj08034/#resources">参考资料</a>），Groovy 的制造者提出了“Java 不仅是一种编程语言，更是一个健壮的平台，可以有多种语言在上面运行和共存”（Monson-Haefel 语）的思想。
      </p>
		<p>新
        <i>alt.lang.jre</i>专栏的这第二期文章的目的是让读者了解 Groovy。我首先回答关于这种新语言的一些最显然的问题（为什么需要它？），然后以代码为基础概述 Groovy 最令人兴奋的功能。
      </p>
		<p>
				<a name="N10062">
						<span class="atitle">为什么需要另一种语言？</span>
				</a>
		</p>
		<p>正如在
        <a href="http://www.ibm.com/developerworks/cn/java/j-alj07064/">上个月的专栏</a>中
介绍的，Groovy 不是与 JRE 兼容的惟一脚本语言。Python、Ruby 和 Smalltalk 就是成功地移植到 Java
平台上的三种脚本语言。对于一些开发人员，这带来了问题：为什么要另一种语言？毕竟，我们许多人已经将 Java 代码与 Jython 或者
JRuby 结合来快速开发应用程序，为什么还要学习另一种语言？回答是 <i>您不一定要学习一种新语言以用 Groovy 编码</i>。Groovy 与其他 JRE 兼容脚本语言的不同在于它的语法以及重用 Java 库。Jython 和 JRuby 共享它们前身（分别是 Python 和 Ruby）的外观，Groovy 让人觉得就像是 Java 语言，不过限制要少得多。
      </p>
		<table align="right" border="0" cellpadding="0" cellspacing="0" width="40%">
				<tbody>
						<tr>
								<td width="10">
										<img alt="" src="http://www.ibm.com/i/c.gif" height="1" width="10" />
								</td>
								<td>
										<table border="1" cellpadding="5" cellspacing="0" width="100%">
												<tbody>
														<tr>
																<td bgcolor="#eeeeee">
																		<a name="N10075">
																				<b>关于本系列</b>
																		</a>
																		<br />
																		<p>虽
然本系列的大多数读者熟悉 Java 语言以及它是如何在跨平台虚拟机上运行的，但是只有少数人知道 Java Runtime
Environment 可以承载 Java 语言之外的语言。本系列文章对 JRE
的多种替代语言进行了综述。这里讨论的大多数语言是开放源代码的，许多是免费使用的，有少数是商业产品，必须购买。在 <a href="http://www.ibm.com/developerworks/views/java/articles.jsp?sort_order=desc&amp;expand=&amp;sort_by=Date&amp;show_abstract=true&amp;view_by=Search&amp;search_by=alt.lang.jre"><i>alt.lang.jre</i></a>系列中介绍的所有语言都得到了 JRE 支持，并且作者相信它们增强了 Java 平台的动态性和灵活性特征。
        </p>
																</td>
														</tr>
												</tbody>
										</table>
								</td>
						</tr>
				</tbody>
		</table>
		<p>像 Jython 这样的语言是在它们的父语言库上建立的，而 Groovy 使用了 Java 开发人员最熟悉的功能和库
        <i>—— 但是将它们放到了一个敏捷开发框架中</i>。敏捷开发的基本宗旨是代码应该很好地适合范围广泛的任务，并可以不同的方式应用。Groovy 通过以下方式落实了这些宗旨：
      </p>
		<ul>
				<li>使开发人员不用编译。</li>
				<li>允许动态类型。</li>
				<li>使合成结构容易。</li>
				<li>使其脚本可以在普通 Java 应用程序中使用。</li>
				<li>提供一个 shell 解析器。</li>
		</ul>
		<p>这些特性使 Groovy 成为一种特别容易学习和使用的语言，不管您是有经验的 Java 开发人员还是刚接触 Java 平台。在下面几节中，我将详细讨论上述特性。
</p>
		<br />
		<table border="0" cellpadding="0" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td>
										<img src="http://www.ibm.com/i/v14/rules/blue_rule.gif" alt="" height="1" width="100%" />
										<br />
										<img alt="" src="http://www.ibm.com/i/c.gif" border="0" height="6" width="8" />
								</td>
						</tr>
				</tbody>
		</table>
		<table class="no-print" align="right" cellpadding="0" cellspacing="0">
				<tbody>
						<tr align="right">
								<td>
										<img src="http://www.ibm.com/i/c.gif" alt="" height="4" width="100%" />
										<br />
										<table border="0" cellpadding="0" cellspacing="0">
												<tbody>
														<tr>
																<td valign="middle">
																		<img src="http://www.ibm.com/i/v14/icons/u_bold.gif" alt="" border="0" height="16" width="16" />
																		<br />
																</td>
																<td align="right" valign="top">
																		<a href="http://www.ibm.com/developerworks/cn/java/j-alj08034/#main" class="fbox">
																				<b>回页首</b>
																		</a>
																</td>
														</tr>
												</tbody>
										</table>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<br />
		<p>
				<a name="N100A1">
						<span class="atitle">看呀，没有 javac！</span>
				</a>
		</p>
		<p>像许多脚本语言一样，Groovy 不用为运行时编译。这意味着 Groovy 脚本是
        <i>在它们运行时</i>解
释的，就像 JavaScript 是在观看 Web
页时由浏览器解释的一样。运行时判断会有执行速度的代价，这有可能使脚本语言不能用于对性能有要求的项目，但是无编译的代码在构建-运行周期中可以提供很
多好处。运行时编译使 Groovy 成为快速原型设计、构建不同的实用程序和测试框架的理想平台。 </p>
		<table align="right" border="0" cellpadding="0" cellspacing="0" width="40%">
				<tbody>
						<tr>
								<td width="10">
										<img alt="" src="http://www.ibm.com/i/c.gif" height="1" width="10" />
								</td>
								<td>
										<table border="1" cellpadding="5" cellspacing="0" width="100%">
												<tbody>
														<tr>
																<td bgcolor="#eeeeee">
																		<a name="N100B0">
																				<b>脚本的能力</b>
																		</a>
																		<br />
																		<p>脚
本语言很流行，因为它们容易学习并且为开发人员设置的限制较少。脚本语言通常使用简单的、相当简洁的语法，这使开发人员可以用比大多数编程语言所需要的更
少的代码创建真实世界的应用程序。像 Perl、Python、Ruby 和现在的
Groovy，用其敏捷方式编写代码而使编程工作达到一个新的效率水平。这种提高的敏捷性通常会使开发人员的效率提高。脚本语言的成功表明脚本不是一种小
范围内使用的技术或者黑客的娱乐工具，而是一种由像 Google、Yahoo 和 IBM 这样的世界级公司所使用的切实可行的技术。</p>
																</td>
														</tr>
												</tbody>
										</table>
								</td>
						</tr>
				</tbody>
		</table>
		<p>例如，运行脚本 Emailer.groovyin Groovy 就是在命令行键入 
        <code>groovy Emailer.groovy</code> 这么容易。如果希望运行同样的 Java 文件（Emailer.java），显然必须键入额外的命令： 
        <code>javac Emailer.java</code> ，然后是 
        <code>java Emailer</code> 。虽然这看起来可能有些微不足道，但是可以容易设想运行时编译在应用程序开发的更大上下文中的好处。 
      </p>
		<p>可以在稍后看到，Groovy 还允许脚本放弃 main 方法以静态地运行一个关联的应用程序。</p>
		<br />
		<br />
		<br />
		<br />
		<br />
		<br />
		<br />
		<br />
		<br />
		<br />
		<table border="0" cellpadding="0" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td>
										<img src="http://www.ibm.com/i/v14/rules/blue_rule.gif" alt="" height="1" width="100%" />
										<br />
										<img alt="" src="http://www.ibm.com/i/c.gif" border="0" height="6" width="8" />
								</td>
						</tr>
				</tbody>
		</table>
		<table class="no-print" align="right" cellpadding="0" cellspacing="0">
				<tbody>
						<tr align="right">
								<td>
										<img src="http://www.ibm.com/i/c.gif" alt="" height="4" width="100%" />
										<br />
										<br />
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<br />
		<p>
				<a name="N100CC">
						<span class="atitle">动态 dynamo</span>
				</a>
		</p>
		<p>像其他主流脚本语言一样，Groovy 不需要像 C++ 和 Java 语言这样的正式语言的显式类型。在 Groovy 中，一个对象的类型是在运行时动态发现的，这极大地减少了要编写的代码数量。首先可以通过分析清单 1 和 2 中的简单例子看到这一点。</p>
		<p>清单 1 显示了在 Java 语言中如何将一个本地变量声明为 
        <code>String</code> 。注意必须声明类型、名和值。
      </p>
		<br />
		<a name="code1">
				<b>清单 1. Java 静态类型</b>
		</a>
		<br />
		<table bgcolor="#eeeeee" border="1" cellpadding="5" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td>
										<pre>
												<code class="section">
														<br />String myStr = "Hello World";<br /></code>
										</pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>在清单 2 中，您看到同样的声明，但是不需要声明变量类型。
</p>
		<br />
		<a name="code2">
				<b>清单 2. Groovy 动态类型</b>
		</a>
		<br />
		<table bgcolor="#eeeeee" border="1" cellpadding="5" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td>
										<pre>
												<code class="section">
														<br />myStr = "Hello World"<br /></code>
										</pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>您可能还注意到了，在清单 2 中我可以去掉声明中的分号。在定义方法及其相关的参数时动态类型有戏剧性的后果：多态具有了全新的意义！事实上，使用动态类型，
        <i>不使用</i>继承就可以得到多态的全部能力。在清单 3 中，可以真正开始看到动态类型在 Groovy 的灵活性方面所起的作用。
      </p>
		<br />
		<a name="code3">
				<b>清单 3. 更多 Groovy 动态类型</b>
		</a>
		<br />
		<table bgcolor="#eeeeee" border="1" cellpadding="5" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td>
										<pre>
												<code class="section">
														<br />class Song{<br />  length<br />  name<br />}<br /><br />class Book{<br />  name<br />  author<br />}<br /><br />def doSomething(thing){<br />  println "going to do something with a thing named = " + thing.name<br />}<br /></code>
										</pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>这里，我定义了两个 Groovy 类， 
        <code>Song</code> 和 
        <code>Book</code> ，我将在后面对它们进一步讨论。这两个类都包含一个 
        <code>name</code> 属性。我还定义了一个函数 
        <code>doSomething</code> ，它以一个 
        <code>thing</code> 为参数，并试图打印这个对象的 
        <code>name</code> 属性。 
      </p>
		<p>因为 
        <code>doSomething</code> 函数没有定义其输入参数的类型，只要对象包含一个 
        <code>name</code> 属性，那么它就可以工作。因此，在清单 4 中，可以看到在使用 
        <code>Song</code> 和 
        <code>Book</code> 的实例作为 
        <code>doSomething</code> 的输入时会有什么现象。 
      </p>
		<br />
		<a name="code4">
				<b>清单 4. 试验动态类型</b>
		</a>
		<br />
		<table bgcolor="#eeeeee" border="1" cellpadding="5" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td>
										<pre>
												<code class="section">
														<br />mySong = new Song(length:90, name:"Burning Down the House")<br />myBook = new Book(name:"One Duck Stuck", author:"Phyllis Root")<br /><br />doSomething(mySong) //prints Burning Down the House<br />doSomething(myBook) //prints One Duck Stuck<br /><br />anotherSomething = doSomething<br /><br />anotherSomething(myBook) //prints One Duck Stuck<br /></code>
										</pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>除了展示 Groovy 中的动态类型，清单 4 的最后两行还揭示了创建对一个函数的引用有多容易。这是因为在 Groovy 中
        <i>所有东西</i>都是对象，包括函数。
      </p>
		<p>关于 Groovy 的动态类型声明最后要注意的是，它会导致更少的 
        <code>import</code> 语句。尽管 Groovy 需要 import 以显式使用类型，但是这些 import 可以使用别名以提供更短的名字。 
      </p>
		<p>
				<a name="N1014C">
						<span class="smalltitle">动态类型综述</span>
				</a>
		</p>
		<p>下面两个例子将到目前为止讨论过的 Groovy 中的动态类型的内容放到一起。下面的 Java 代码组和 Groovy 代码组利用了 Freemarker（参阅
        <a href="http://www.ibm.com/developerworks/cn/java/j-alj08034/#resources">参考资料</a>），这是一个开放源代码模板引擎。这两组代码都只是简单地用一个目录和文件名创建一个 
        <code>Template</code> 对象，然后将相应对象的内容打印到标准输出，当然，不同之处是每一组代码处理这项任务所需要的代码量。 
      </p>
		<br />
		<a name="code5">
				<b>清单 5. 简单的 TemplateReader Java 类</b>
		</a>
		<br />
		<table bgcolor="#eeeeee" border="1" cellpadding="5" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td>
										<pre>
												<code class="section">
														<br />import java.io.File;<br />import java.io.IOException;<br /><br />import freemarker.template.Configuration;<br />import freemarker.template.Template;<br /><br />public class TemplateReader {<br /><br />  public static void main(String[] args) {<br />    try{<br />	  Configuration cfg = Configuration.getDefaultConfiguration();<br />	  cfg.setDirectoryForTemplateLoading(<br />	       new File("C:\\dev\\projects\\http-tester\\src\\conf"));<br /><br />	  Template temp = cfg.getTemplate("vendor-request.tmpl");<br /><br />  	  System.out.println(temp.toString());<br />      }catch(IOException e){<br />        e.printStackTrace();<br />      }<br />  }<br />}<br /></code>
										</pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>初看之下，清单 5 中的 Java 代码相当简单 —— 特别是如果以前从来没见过脚本代码时。幸运的是，有清单 6 中的 Groovy 作为对比。现在这段代码很简单！</p>
		<br />
		<a name="code6">
				<b>清单 6. 用 Groovy 编写的更简单的 TemplateReader</b>
		</a>
		<br />
		<table bgcolor="#eeeeee" border="1" cellpadding="5" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td>
										<pre>
												<code class="section">
														<br />import freemarker.template.Configuration as tconf<br />import java.io.File<br /><br />cfg = tconf.getDefaultConfiguration()<br /><br />cfg.setDirectoryForTemplateLoading(<br />  new File("C:\\dev\\projects\\http-tester\\src\\conf"))<br /><br />temp = cfg.getTemplate("vendor-request.tmpl")<br /><br />println temp.toString()<br /></code>
										</pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>Groovy 代码只有 Java 代码的一半那么长，下面是原因：</p>
		<ul>
				<li>Groovy 代码只需要一半的 
          <code>import</code> 语句。还要注意， 
          <code>freemarker.template.Configuration</code> 使用了别名 
          <code>tconf</code> ，使得语法更短。 
          <br /><br /></li>
				<li>Groovy 允许类型为 
          <code>Template</code> 的变量 
          <code>tmpl</code> 不声明其类型。
          <br /><br /></li>
				<li>Groovy 不需要 
          <code>class</code> 声明或者 
          <code>main</code> 方法。 
          <br /><br /></li>
				<li>Groovy 不关心任何相应异常，使您可以不用导入 Java 代码中需要的 
          <code>IOException</code> 。
        </li>
		</ul>
		<p>现在，在继续之前，想一下您所编写的最后一个 Java 类。您可能不得不编写很多 import 并声明类型，并在后面加上同样数量的分号。考虑用 Groovy 编写同样的代码会是什么情况。可以使用简练得多的语法，不需要遵守这么多的规则，并且得到完全相同的行为。</p>
		<p>想一下，如果您正好是刚刚开始……</p>
		<br />
		<table border="0" cellpadding="0" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td>
										<img src="http://www.ibm.com/i/v14/rules/blue_rule.gif" alt="" height="1" width="100%" />
										<br />
										<img alt="" src="http://www.ibm.com/i/c.gif" border="0" height="6" width="8" />
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<br />
		<p>
				<a name="N101B8">
						<span class="atitle">特别灵活的语法</span>
				</a>
		</p>
		<p>谈
到语法，灵活性是更有效地开发代码的主要因素。很像其有影响的对手（Python、Ruby 和 Smalltalk），Groovy
极大地简化了核心库的使用和它所模拟的语言（在这里是 Java 语言）的构造。为了让您对 Groovy
语法的灵活性有一个大体概念，我将展示它的一些主要结构，即类、函数（通过 <code>def</code> 关键词）、闭包、集合、范围、映射和迭代器。 
      </p>
		<p>
				<a name="N101C5">
						<span class="smalltitle">类</span>
				</a>
		</p>
		<p>在字节码水平，Groovy 类是真正的 Java 类。不同之处在于 Groovy 将类中定义的所有内容都默认为 
        <code>public</code> ，除非定义了特定的访问修饰符。而且，动态类型应用到字段和方法，不需要 
        <code>return</code> 语句。 
      </p>
		<p>在清单 7 中可以看到 Groovy 中类定义的例子，其中类 
        <code>Dog</code> 有一个 
        <code>getFullName</code> 方法，它实际上返回一个表示 
        <code>Dog</code> 的全名的 
        <code>String</code> 。并且所有方法都隐式地为 
        <code>public</code> 。 
      </p>
		<br />
		<a name="code7">
				<b>清单 7. 示例 Groovy 类：Dog</b>
		</a>
		<br />
		<table bgcolor="#eeeeee" border="1" cellpadding="5" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td>
										<pre>
												<code class="section">
														<br />class Dog{<br />  name<br /><br />  bark(){<br />    println "RUFF! RUFF!"<br />  }<br /><br />  getFullName(master){<br />    name + " " + master.lname<br />  }<br /><br />  obeyMaster(){<br />    println "I hear you and will not obey."<br />  }<br />}<br /></code>
										</pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p> 在清单 8 中，推广到有两个属性 —— 
        <code>fname</code> 和 
        <code>lname</code> —— 的类 
        <code>DogOwner</code> ，就是这么简单！

      </p>
		<br />
		<a name="code8">
				<b>清单 8. 示例 Groovy 类：DogOwner</b>
		</a>
		<br />
		<table bgcolor="#eeeeee" border="1" cellpadding="5" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td>
										<pre>
												<code class="section">
														<br />class DogOwner{<br />  fname<br />  lname<br /><br />  trainPet(pet){<br />    pet.obeyMaster()<br />  }<br /><br />}<br /></code>
										</pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>在清单 9 中，用 Groovy 设置属性并对 
        <code>Dog</code> 和 
        <code>DogOwner</code> 实例调用方法。现在很明显，使用 Groovy 类比 Java 类要容易得多。虽然需要 
        <code>new</code> 关键词，但是类型是可选的，且设置属性（它隐式为 public）是相当轻松的。 
      </p>
		<br />
		<a name="code9">
				<b>清单 9. 使用 Groovy 类</b>
		</a>
		<br />
		<table bgcolor="#eeeeee" border="1" cellpadding="5" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td>
										<pre>
												<code class="section">
														<br />
														<br />myDog = new Dog()<br />myDog.name = "Mollie"<br /><br />myDog.bark()<br />myDog.obeyMaster() <br /><br />me = new DogOwner()<br />me.fname = "Ralf"<br />me.lname = "Waldo"<br /><br />me.trainPet(myDog)<br /><br />str = myDog.getFullName(me)<br />println str  // prints Mollie Waldo<br /><br /></code>
										</pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>注意在 
        <code>Dog</code> 类中定义的 
        <code>getFullName</code> 方法返回一个 
        <code>String</code> 对象，在这里它是 “ 
        <code>Mollie Waldo</code> ”。

      </p>
		<table align="right" border="0" cellpadding="0" cellspacing="0" width="40%">
				<tbody>
						<tr>
								<td width="10">
										<img alt="" src="http://www.ibm.com/i/c.gif" height="1" width="10" />
								</td>
								<td>
										<table border="1" cellpadding="5" cellspacing="0" width="100%">
												<tbody>
														<tr>
																<td bgcolor="#eeeeee">
																		<a name="N1023F">
																				<b>第一类对象</b>
																		</a>
																		<br />
																		<p>
																				<i>第一类对象</i> 是可以在运行时用数据创建并使用的对象。第一类对象还可以传递给函数和由函数输出、作为变量存储、由其他对象返回。Java 语言自带的基本数据类型，如 
          <code>int</code> 和 
          <code>boolean</code> ，不认为是第一类对象。许多面向对象纯粹论者哀叹这个小细节，一些人据此提出 Java 语言是否是真正的面向对象语言。Groovy 通过将所有内容声明为对象而解决了这一问题。 
        </p>
																</td>
														</tr>
												</tbody>
										</table>
								</td>
						</tr>
				</tbody>
		</table>
		<p>
				<a name="N10254">
						<span class="smalltitle">Def</span>
				</a>
		</p>
		<p>除了像许多脚本语言那样将所有对象指定为第一类对象（见侧栏），Groovy 还让您创建
        <i>第一类函数</i>，它本身实质上就是对象。它们是用 
        <code>def</code> 关键词定义的并在类定义之外。您实际上在 
        <a href="http://www.ibm.com/developerworks/cn/java/j-alj08034/#code3">清单 3</a> 中已经看到了如何用 
        <code>def</code> 关键词定义第一类函数，并在 
        <a href="http://www.ibm.com/developerworks/cn/java/j-alj08034/#code4">清单 4</a>中看到使用了一个函数。Groovy 的第一类函数定义简单脚本时特别有用。
      </p>
		<p>
				<a name="N10270">
						<span class="smalltitle">闭包</span>
				</a>
		</p>
		<p>Groovy 中最令人兴奋和最强大的功能是支持闭包。
        <i>闭包（Closure）</i>是
第一类对象，它类似于 Java
语言中的匿名内部类。闭包和匿名内部类都是可执行的一段代码，不过这两者之间有一些细微的不同。状态是自动传入传出闭包的。闭包可以有名字。它们可以重复
使用。而且，最重要且对 Groovy 同样成立的是，闭包远比匿名内部类要灵活得多！ </p>
		<p>清单 10 展示了闭包的强大。清单中新的和改进的 
        <code>Dog</code> 类包括一个 
        <code>train</code> 方法，它实际上执行创建了 
        <code>Dog</code> 实例的闭包。 
      </p>
		<br />
		<a name="code10">
				<b>清单 10. 使用闭包</b>
		</a>
		<br />
		<table bgcolor="#eeeeee" border="1" cellpadding="5" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td>
										<pre>
												<code class="section">
														<br />class Dog{  <br />  action<br /><br />  train(){<br />    action.call()<br />  }<br />}<br /><br />sit = { println "Sit, Sit! Sit! Good dog"}<br />down = { println "Down! DOWN!" }<br /><br /><br />myDog = new Dog(action:sit)<br />myDog.train()  // prints Sit, Sit! Sit! Good dog<br /><br />mollie = new Dog(action:down)<br />mollie.train() // prints Down! DOWN!<br /></code>
										</pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>而且，闭包还可以接收参数。如清单 11 所示， 
        <code>postRequest</code> 闭包接收两个参数（ 
        <code>location</code> 和 
        <code>xml</code> ），并使用 Jakarta Commons HttpClient 库（参阅 
        <a href="http://www.ibm.com/developerworks/cn/java/j-alj08034/#resources">参考资料</a>）将一个 XML 文档发送给指定位置。然后这个闭包返回一个表示响应的 
        <code>String</code> 。闭包定义下面是一个使用闭包的例子。事实上，调用闭包就像调用函数一样。 
      </p>
		<br />
		<a name="code11">
				<b>清单 11. 使用带参数的闭包</b>
		</a>
		<br />
		<table bgcolor="#eeeeee" border="1" cellpadding="5" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td>
										<pre>
												<code class="section">
														<br />import org.apache.commons.httpclient.HttpClient<br />import org.apache.commons.httpclient.methods.PostMethod<br /><br />postRequest = { location, xml |<br /><br />  clint = new HttpClient()<br />  mthd = new PostMethod(location)  	<br />  mthd.setRequestBody(xml)<br />  mthd.setRequestContentLength(xml.length())<br />  mthd.setRequestHeader("Content-type", <br />     "text/xml; charset=ISO-8859-1")<br /><br />  statusCode = clint.executeMethod(mthd)<br />  responseBody = mthd.getResponseBody()<br />  mthd.releaseConnection()	<br />  return new String(responseBody)	  <br />}<br /><br />loc = "http://localhost:8080/simulator/AcceptServlet/"<br />vxml = "&lt;test&gt;&lt;data&gt;blah blah blah&lt;/data&gt;&lt;/test&gt;"<br /><br />str = postRequest(loc, vxml)<br />println str<br /></code>
										</pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<table align="right" border="0" cellpadding="0" cellspacing="0" width="40%">
				<tbody>
						<tr>
								<td width="10">
										<img alt="" src="http://www.ibm.com/i/c.gif" height="1" width="10" />
								</td>
								<td>
										<table border="1" cellpadding="5" cellspacing="0" width="100%">
												<tbody>
														<tr>
																<td bgcolor="#eeeeee">
																		<a name="N102B9">
																				<b>自动装箱</b>
																		</a>
																		<br />
																		<p>自动装箱或者装箱转换是一个自动将像 
          <code>int</code> 、 
          <code>double</code> 和 
          <code>boolean</code> 这样的基本数据类型自动转换为可以在 
          <code>java.lang</code> 包中找到的它们的相应包装类型的过程。这一功能出现在 J2SE 1.5 中，使开发人员不必在源代码中手工编写转换代码。 
        </p>
																</td>
														</tr>
												</tbody>
										</table>
								</td>
						</tr>
				</tbody>
		</table>
		<p>
				<a name="N102D3">
						<span class="smalltitle">集合</span>
				</a>
		</p>
		<p>
将对象组织到像列表和映射这样的数据结构中是一项基本的编码任务，是我们大多数人每天要做的工作。像大多数语言一样，Groovy
定义了一个丰富的库以管理这些类型的集合。如果曾经涉足 Python 或者 Ruby，那么应该熟悉 Groovy 的集合语法。如清单 12
所示，创建一个列表与在 Java 语言中创建一个数组很类似。（注意，列表的第二项自动装箱为一个 <code>Integer</code> 类型。) 
      </p>
		<br />
		<a name="code12">
				<b>清单 12. 使用集合</b>
		</a>
		<br />
		<table bgcolor="#eeeeee" border="1" cellpadding="5" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td>
										<pre>
												<code class="section">
														<br />collect = ['groovy', 29, 'here', 'groovy']<br /></code>
										</pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p> 除了使列表更容易处理，Groovy 还为集合增加了几个新方法。这些方法使得，如 
        <code>统计</code> 值出现的次数、将整个列表 
        <code>结合</code> 到一起、对列表 
        <code>排序</code> 变得非常容易。可以在清单 13 中看到这些集合方法的使用。 
      </p>
		<br />
		<a name="code13">
				<b>清单 13. 使用 Groovy 集合</b>
		</a>
		<br />
		<table bgcolor="#eeeeee" border="1" cellpadding="5" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td>
										<pre>
												<code class="section">
														<br />aCollect = [5, 9, 2, 2, 4, 5, 6] <br /><br />println aCollect.join(' - ')  // prints 5 - 9 - 2 - 2 - 4 - 5 - 6<br />println aCollect.count(2)     // prints 2<br />println aCollect.sort()       // prints [2, 2, 4, 5, 5, 6, 9]<br /></code>
										</pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>
				<b>Maps</b>
				<br />
				<br />
像列表一样，映射也是一种在 Groovy 中非常容易处理的数据结构。清单 14 中的映射包含两个对象，键是 
        <code>name</code> 和 
        <code>date</code> 。注意可以用不同的方式取得值。

      </p>
		<br />
		<a name="code14">
				<b>清单 14. 处理映射</b>
		</a>
		<br />
		<table bgcolor="#eeeeee" border="1" cellpadding="5" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td>
										<pre>
												<code class="section">
														<br />myMap = ["name" : "Groovy", "date" : new Date()]<br /><br />println myMap["date"]<br /><br />println myMap.date<br /></code>
										</pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>
				<b>范围</b>
				<br />
				<br />
在处理集合时，很可能会大量使用 
        <code>范围（Range）</code> 。 
        <code>范围</code> 实际上是一个很直观的概念，并且容易理解，利用它可以包含地或者排除地创建一组有序值。使用两个点 （ 
        <code>..</code> ） 声明一个包含范围，用三个点 （ 
        <code>...</code> ） 声明一个排除范围，如清单 15 所示。 
      </p>
		<br />
		<a name="code15">
				<b>清单 15. 处理范围</b>
		</a>
		<br />
		<table bgcolor="#eeeeee" border="1" cellpadding="5" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td>
										<pre>
												<code class="section">
														<br />myRange = 29...32<br />myInclusiveRange = 2..5<br /><br />println myRange.size() // prints 3<br />println myRange[0]   // prints 29<br />println myRange.contains(32) //prints false<br /><br />println myInclusiveRange.contains(5) //prints true<br /></code>
										</pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>
				<b>用范围实现循环</b>
				<br />
				<br />
在循环结构中，范围可以实现相当巧妙的想法。在清单 16 中，将 
        <code>aRange</code> 定义为一个排除范围，循环打印 a、b、c 和 d。

      </p>
		<br />
		<a name="code16">
				<b>清单 16. 用范围实现循环</b>
		</a>
		<br />
		<table bgcolor="#eeeeee" border="1" cellpadding="5" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td>
										<pre>
												<code class="section">
														<br />aRange = 'a'...'e'<br /><br />for (i in aRange){<br />  println i<br />}<br /></code>
										</pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>
				<b>集合的其他功能</b>
				<br />
				<br />
如果不熟悉 Python 和其他脚本语言，那么您在 Groovy 集合中发现的一些其他功能会让您印象深刻。例如，创建了集合后，可以用负数在列表中反向计数，如清单 17 所示。

      </p>
		<br />
		<a name="code17">
				<b>清单 17. 负索引</b>
		</a>
		<br />
		<table bgcolor="#eeeeee" border="1" cellpadding="5" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td>
										<pre>
												<code class="section">
														<br />aList = ['python', 'ruby', 'groovy']<br /><br />println aList[-1] // prints groovy<br />println aList[-3] // prints python<br /></code>
										</pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p> Groovy 还让您可以用范围分割列表。分割可获得列表的准确子集，如清单 18 所示。
</p>
		<br />
		<a name="code18">
				<b>清单 18. 用范围分割</b>
		</a>
		<br />
		<table bgcolor="#eeeeee" border="1" cellpadding="5" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td>
										<pre>
												<code class="section">
														<br />fullName = "Andrew James Glover"<br /><br />mName = fullName[7...13]<br /><br />print "middle name: " + mName // prints James<br /></code>
										</pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>
				<b>集合类似于 Ruby</b>
				<br />
				<br />
如果愿意的话，还可以将 Groovy 集合作为 Ruby 集合。可以用类似 Ruby 的语法，以 
        <code>&lt;&lt;</code> 语法附加元素、用 
        <code>+</code> 串接和用 
        <code>-</code> 对集合取差，甚至还可以用 
        <code>*</code> 语法处理集合的重复，如清单 19 所示。
注意，还可以用 
        <code>==</code> 比较集合。

      </p>
		<br />
		<a name="code19">
				<b>清单 19. Ruby 风格的集合</b>
		</a>
		<br />
		<table bgcolor="#eeeeee" border="1" cellpadding="5" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td>
										<pre>
												<code class="section">
														<br />collec = [1, 2, 3, 4, 5]<br />collec &lt;&lt; 6 //appended 6 to collec<br /><br />acol = ['a','b','c'] * 3 //acol now has 9 elements<br /><br />coll =  [10, 11]<br />coll2 = [12, 13]<br /><br />coll3 = coll + coll2 //10,11,12,13<br /><br />difCol = [1,2,3] - [1,2] //difCol is 3<br /><br />assert [1, 2, 3] == [1, 2, 3] //true<br /></code>
										</pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>
				<a name="N103A4">
						<span class="smalltitle">迭代器</span>
				</a>
		</p>
		<p>在 Groovy 中，迭代任何序列都相当容易。迭代字符序列所需要的就是一个简单的 
        <code>for</code> 循环，如清单 20 所示。（正如您现在可能注意到的，Groovy 提供了比 Java  1.5 以前的传统语法更自然的 
        <code>for</code> 循环语法。） 
      </p>
		<br />
		<a name="code20">
				<b>清单 20. 迭代器示例</b>
		</a>
		<br />
		<table bgcolor="#eeeeee" border="1" cellpadding="5" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td>
										<pre>
												<code class="section">
														<br />str = "uncle man, uncle man"<br /><br />for (ch in str){<br />  println ch<br />}<br /></code>
										</pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>Groovy 中的大多数对象具有像 
        <code>each</code> 和 
        <code>find</code> 这样的以闭包为参数的方法。用闭包来迭代对象会产生几种令人兴奋的可能性，如清单 21 所示。
      </p>
		<br />
		<a name="code21">
				<b>清单 21. 带有迭代器的闭包</b>
		</a>
		<br />
		<table bgcolor="#eeeeee" border="1" cellpadding="5" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td>
										<pre>
												<code class="section">
														<br />[1, 2, 3].each {  <br />  val = it <br />  val += val<br />  println val<br />}<br /><br />[2, 4, 6, 8, 3].find { x |<br />     if (x == 3){<br />       println x<br />     }<br />}<br /></code>
										</pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>在清单 21 中，方法 
        <code>each</code> 作为迭代器。在这里，闭包添加元素的值，完成时 
        <code>val</code> 的值为 6。 
        <code>find</code> 方法也是相当简单的。每一次迭代传递进元素。在这里，只是测试值是否为 3。
      </p>
		<br />
		<table border="0" cellpadding="0" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td>
										<img src="http://www.ibm.com/i/v14/rules/blue_rule.gif" alt="" height="1" width="100%" />
										<br />
										<img alt="" src="http://www.ibm.com/i/c.gif" border="0" height="6" width="8" />
								</td>
						</tr>
				</tbody>
		</table>
		<table class="no-print" align="right" cellpadding="0" cellspacing="0">
				<tbody>
						<tr align="right">
								<td>
										<img src="http://www.ibm.com/i/c.gif" alt="" height="4" width="100%" />
										<br />
										<br />
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<br />
		<p>
				<a name="N103E3">
						<span class="atitle">Groovy 的高级内容</span>
				</a>
		</p>
		<p>到目前为止，我着重讲述的都是使用 Groovy 的基本方面，但是这种语言有比基本内容多得多的内容！我将以分析 Groovy 提供的一些高级开发功能作为结束，包括 Groovy 样式的 JavaBeans 组件、文件 IO、正则表达式和用 
        <code>groovyc</code> 编译。
      </p>
		<p>
				<a name="N103F0">
						<span class="smalltitle">GroovyBean！</span>
				</a>
		</p>
		<p>永
远不变的是，应用程序最后要使用类似 struct 的对象表示真实世界的实体。在 Java 平台上，称这些对象为 JavaBean
组件，它们通常用于表示订单、客户、资源等的业务对象。Groovy 由于其方便的简写语法，以及在定义了所需 bean
的属性后自动提供构造函数，而简化了 JavaBean 组件的编写。结果自然就是极大地减少了代码，正如您可以自己从清单 22 和 23 中看到的。</p>
		<p>在清单 22 中，可看到一个简单的 JavaBean 组件，它是用 Java 语言定义的。</p>
		<br />
		<a name="code22">
				<b>清单 22. 一个简单的 JavaBean 组件</b>
		</a>
		<br />
		<table bgcolor="#eeeeee" border="1" cellpadding="5" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td>
										<pre>
												<code class="section">
														<br />public class LavaLamp {<br />  private Long model;<br />  private String baseColor;<br />  private String liquidColor;<br />  private String lavaColor;<br /><br />  public String getBaseColor() {<br />    return baseColor;<br />  }<br /><br />  public void setBaseColor(String baseColor) {<br />    this.baseColor = baseColor;<br />  }<br /><br />  public String getLavaColor() {<br />    return lavaColor;<br />  }<br /><br />  public void setLavaColor(String lavaColor) {<br />    this.lavaColor = lavaColor;<br />  }<br /><br />  public String getLiquidColor() {<br />    return liquidColor;<br />  }<br /><br />  public void setLiquidColor(String liquidColor) {<br />    this.liquidColor = liquidColor;<br />  }<br /><br />  public Long getModel() {<br />    return model;<br />  }<br /><br />  public void setModel(Long model) {<br />    this.model = model;<br />  }<br />}<br /></code>
										</pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p> 在清单 23 中，可以看到用 Groovy 写这个 bean 时所发生的事。所要做的就是定义属性，Groovy 会自动给您一个很好的构造函数以供使用。Groovy 还使您在操纵 
        <code>LavaLamp</code> 的实例时有相当大的灵活性。例如，我们可以使用 Groovy 的简写语法
        <i>或者</i>传统的冗长的 Java 语言语法操纵 bean 的属性。
      </p>
		<br />
		<a name="code23">
				<b>清单 23. 用 Groovy 编写的 JavaBeans 组件</b>
		</a>
		<br />
		<table bgcolor="#eeeeee" border="1" cellpadding="5" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td>
										<pre>
												<code class="section">
														<br />class LavaLamp{<br />  model<br />  baseColor<br />  liquidColor<br />  lavaColor<br />}<br /><br />llamp = new LavaLamp(model:1341, baseColor:"Black", <br />  liquidColor:"Clear", lavaColor:"Green")<br /><br />println llamp.baseColor<br />println "Lava Lamp model ${llamp.model}"<br /><br />myLamp = new LavaLamp()<br />myLamp.baseColor = "Silver"<br />myLamp.setLavaColor("Red")<br /><br />println "My Lamp has a ${myLamp.baseColor} base"<br />println "My Lava is " + myLamp.getLavaColor()<br /></code>
										</pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>
				<a name="N1041A">
						<span class="smalltitle">轻松的 IO</span>
				</a>
		</p>
		<p> Groovy IO 操作很轻松，特别是与迭代器和闭包结合时。Groovy 使用标准 Java 对象如 
        <code>File</code> 、 
        <code>Reader</code> 和 
        <code>Writer</code> ，并用接收闭包作参数的额外方法增强了它们。如在清单 24 中，可以看到传统的 
        <code>java.io.File</code> ，但是带有额外的、方便的 
        <code>eachLine</code> 方法。 
      </p>
		<br />
		<a name="code24">
				<b>清单 24. Groovy IO</b>
		</a>
		<br />
		<table bgcolor="#eeeeee" border="1" cellpadding="5" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td>
										<pre>
												<code class="section">
														<br />import java.io.File<br /><br />new File("File-IO-Example.txt").eachLine{ line |<br /> println "read the following line -&gt; " + line<br />}<br /></code>
										</pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>因为文件实质上是一系列行、字符等，所以可以相当简单地迭代它们。 
        <code>eachLine</code> 方法接收一个闭包并迭代文件的每一行，在这里是 
        <code>File-IO-Example.txt</code> 。 以这种方式使用闭包是相当强大的，因为 Groovy 保证所有文件资源都是关闭的，不考虑任何异常。这意味着无需大量 
        <code>try</code> / 
        <code>catch</code> / 
        <code>finally</code> 子句就可以进行文件 IO！ 
      </p>
		<p>
				<a name="N10458">
						<span class="smalltitle">高级编译</span>
				</a>
		</p>
		<p>Groovy 脚本实际上是字节码级别的 Java 类。因此，可以容易地用 
        <code>groovyc</code> 编译 Groovy 脚本。可以通过命令行或者 
        <code>Ant</code> 使用 
        <code>groovyc</code> 以生成脚本的类文件。这些类可以用普通 
        <code>java</code> 命令运行，只要 classpath 包括 
        <code>groovy.jar</code> 和 
        <code>asm.jar</code> ，这是 ObjectWeb 的字节码操纵框架。要了解更多编译 Groovy 的内容，请参阅 
        <a href="http://www.ibm.com/developerworks/cn/java/j-alj08034/#resources">参考资料</a>。
      </p>
		<p>
				<a name="N1047D">
						<span class="smalltitle">最大 RegEx</span>
				</a>
		</p>
		<p> 如果一种语言没有正则表达式处理，则它是没价值的。Groovy 使用 Java 平台的 
        <code>java.util.regex</code> 库 —— 但是做了少量基本的改变。例如，Groovy 使您可以用 
        <code>~</code> 表达式创建 
        <code>Pattern</code> 对象，用 
        <code>=~</code> 表达式创建 
        <code>Matcher</code> 对象，如清单 25 所示。 
      </p>
		<br />
		<a name="code25">
				<b>清单 25. Groovy RegEx</b>
		</a>
		<br />
		<table bgcolor="#eeeeee" border="1" cellpadding="5" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td>
										<pre>
												<code class="section">
														<br />str =  "Water, water, every where,<br />        And all the boards did shrink;<br />        Water, water, every where,<br />        Nor any drop to drink."<br /><br />if (str =~ 'water'){<br />  println 'found a match'<br />}<br /><br />ptrn = ~"every where"<br /><br />nStr = (str =~ 'every where').replaceAll('nowhere')<br /><br />println nStr<br /></code>
										</pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>您可能已经注意到了，可以在上述清单中定义 
        <code>String</code> 、 
        <code>str</code> ，而无需为每一新行添加结束引号和 
        <code>+</code> 。这是因为 Groovy 放松了要求字符串串接的普通 Java 约束。运行这段 Groovy 脚本会对匹配 
        <code>water</code> 的情况打印出 
        <code>true</code> ，然后打印出一节诗，其中所有出现 “ 
        <code>every where</code> ”的地方都替换为 “ 
        <code>nowhere</code> ”。 
      </p>
		<table align="right" border="0" cellpadding="0" cellspacing="0" width="40%">
				<tbody>
						<tr>
								<td width="10">
										<img alt="" src="http://www.ibm.com/i/c.gif" height="1" width="10" />
								</td>
								<td>
										<table border="1" cellpadding="5" cellspacing="0" width="100%">
												<tbody>
														<tr>
																<td bgcolor="#eeeeee">
																		<a name="N104C6">
																				<b>关于 （band）shell</b>
																		</a>
																		<br />
																		<p>Groovy 提供了两种不同的解释器，使所有有效的 Groovy 表达式可以交互地执行。这些 shell 是特别强大的机制，可以用它们迅速学习 Groovy。</p>
																</td>
														</tr>
												</tbody>
										</table>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<br />
		<br />
		<br />
		<br />
		<br />
		<br />
		<br />
		<table border="0" cellpadding="0" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td>
										<img src="http://www.ibm.com/i/v14/rules/blue_rule.gif" alt="" height="1" width="100%" />
										<br />
										<img alt="" src="http://www.ibm.com/i/c.gif" border="0" height="6" width="8" />
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<br />
		<p>
				<a name="N104D0">
						<span class="atitle">结束语</span>
				</a>
		</p>
		<p>像
所有婴儿期的项目一样，Groovy 是正在发展的语言。习惯于使用 Ruby 和 Python （或者 Jython）的开发人员可能会怀念
mixins、脚本导入（尽管可以将所需要的可导入脚本编译为相应的 Java 类）和方法调用的命名参数等这些功能的方便性。 但是 Groovy
绝对是一种发展中的语言。随着其开发人员数量的增加，它很有可能结合这些功能及更多功能。</p>
		<p>同时，Groovy
有很多优点。它很好地融合了 Ruby、Python 和 Smalltalk 的一些最有用的功能，同时保留了基于 Java
语言的核心语法。对于熟悉 Java 平台的开发人员，Groovy 提供了更简单的替代语言，且几乎不需要学习时间。对于刚接触 Java
平台的开发人员，它可以作为有更复杂语法和要求的 Java 语言的一个容易的入口点。</p>
		<p>像在本系统讨论的其他语言一样，Groovy 不是要替代 Java 语言，而是作为它的另一种选择。与这里讨论的其他语言不一样，Groovy 遵循 Java 规范，这意味着它有可能与 Java 平台上的 Java 语言具有同等重要的作用。</p>
		<p>在本月这一期
        <i>alt.lang.jre</i>文章中，介绍了 Groovy 的基本框架和语法，以及它的一些高级编程功能。下个月将介绍在 Java 开发人员中最受欢迎的脚本语言： JRuby。
      </p>
<img src ="http://www.blogjava.net/JafeLee/aggbug/128683.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/JafeLee/" target="_blank">Jafe</a> 2007-07-06 21:35 <a href="http://www.blogjava.net/JafeLee/articles/128683.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>终于贴完了实战Groovy这个系列了</title><link>http://www.blogjava.net/JafeLee/articles/128682.html</link><dc:creator>Jafe</dc:creator><author>Jafe</author><pubDate>Fri, 06 Jul 2007 13:21:00 GMT</pubDate><guid>http://www.blogjava.net/JafeLee/articles/128682.html</guid><wfw:comment>http://www.blogjava.net/JafeLee/comments/128682.html</wfw:comment><comments>http://www.blogjava.net/JafeLee/articles/128682.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/JafeLee/comments/commentRss/128682.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/JafeLee/services/trackbacks/128682.html</trackback:ping><description><![CDATA[原文链接：<a href="http://www.ibm.com/developerworks/cn/views/java/articles.jsp?view_by=search&amp;search_by=Groovy">http://www.ibm.com/developerworks/cn/views/java/articles.jsp?view_by=search&amp;search_by=Groovy</a><br /><br /><p><a name="author"><span class="atitle">关于作者</span></a></p><table border="0" cellpadding="0" cellspacing="0" width="100%"><tbody><tr><td colspan="3"><img alt="" src="http://www.ibm.com/i/c.gif" height="5" width="100%" /></td></tr><tr align="left" valign="top"><td><p><img alt="" name="Photo of Andrew Glover" src="http://www-106.ibm.com/developerworks/i/p-aglover.jpg" align="left" border="0" /></p></td><td><img alt="" src="http://www.ibm.com/i/c.gif" height="5" width="4" /></td><td width="100%"><p>		Andrew Glover 是 <a href="http://www.stelligent.com/">Stelligent Incorporated</a> 公司的 President，该公司位于华盛顿特区大都会地区，公司的专业领域是自动测试框架的构造，自动测试框架可以降低软件 bug 数量，减少集成和测试的时间，提高整体的代码稳定性。他还是 <a href="http://www.wiley.com/WileyCDA/WileyTitle/productCd-047144846X,descCd-authorInfo.html">Java Testing Patterns</a> （Wiley，2004 年 9 月）的合著者。</p></td></tr></tbody></table><br /><br />ms是 Groovy in Action 的作者~~<br /><img src ="http://www.blogjava.net/JafeLee/aggbug/128682.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/JafeLee/" target="_blank">Jafe</a> 2007-07-06 21:21 <a href="http://www.blogjava.net/JafeLee/articles/128682.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>实战 Groovy: 用 Groovy 减少代码冗余</title><link>http://www.blogjava.net/JafeLee/articles/128681.html</link><dc:creator>Jafe</dc:creator><author>Jafe</author><pubDate>Fri, 06 Jul 2007 13:17:00 GMT</pubDate><guid>http://www.blogjava.net/JafeLee/articles/128681.html</guid><wfw:comment>http://www.blogjava.net/JafeLee/comments/128681.html</wfw:comment><comments>http://www.blogjava.net/JafeLee/articles/128681.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/JafeLee/comments/commentRss/128681.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/JafeLee/services/trackbacks/128681.html</trackback:ping><description><![CDATA[
		<p>
				<a href="http://www.ibm.com/developerworks/cn/java/j-pg09196.html#author">Scott Hickey</a> (<a href="mailto:shickey@bass-inc.com?subject=%E7%94%A8%20Groovy%20%E5%87%8F%E5%B0%91%E4%BB%A3%E7%A0%81%E5%86%97%E4%BD%99">shickey@bass-inc.com</a>), 顾问, Bass and Associates, Inc.<br /></p>
		<p>2006 年  10 月  17 日</p>
		<blockquote>Groovy 简洁的语法将开发人员从那种需要进行代码编译但却无助于表达 <i>什么</i> 是程序真正想要实现的典型的 Java™ 结构中解放了出来。在<i>实战 Groovy</i> 系列的这一复兴篇中，Groovy 开发人员兼特约专栏作家 J. Scott Hickey 带您进行一系列对常规 Java 代码和 Groovy 代码的比较，展示这门令人兴奋的语言如何将您解放出来，让您能够专注于编码的重要方面。</blockquote>
		<!--START RESERVED FOR FUTURE USE INCLUDE FILES-->
		<!-- include java script once we verify teams wants to use this and it will work on dbcs and cyrillic characters -->
		<!--END RESERVED FOR FUTURE USE INCLUDE FILES-->
		<p>
通常，程序员们转而选择诸如 Groovy 之类的编程语言，是为了构建快速的实用程序，快速编写测试代码，甚至创建构成大型的 Java
应用程序的组件，而 Groovy 先天具有这样一种能力，它能够减少传统的基于 Java 系统所固有的许多冗余并降低其复杂度。Groovy
简洁而灵活的语法将开发人员从那种需要进行代码编译却无助于表达<i>什么</i> 是程序真正想要实现的典型的 Java 结构中解放出来。不仅如此，Groovy 轻松的类型通过减少一些接口和超类使代码不再复杂，这些接口和超类都是常规 Java 应用程序用以支持不同具体类型间的通用行为所需的。 
</p>
		<p>
为了举例说明 Groovy 如何减少 Java 应用程序所涉及的无用数据，我将使用 Bruce Tate 和 Justin Ghetland 的 <i>Spring: A Developer's Notebook</i>（参见 <a href="http://www.ibm.com/developerworks/cn/java/j-pg09196.html#resources">参考资料</a>）
中的样例代码，该书介绍了如何使用 Spring 进行控制反转。每当回顾一个 Java 样例，我都会将其与实现相同功能的相应的 Groovy
源代码进行比较，您将很快发现 Groovy 通过减少 Java
编程的不同方面（冗余且不必要地传递了应用程序的行为）而使应用程序代码变得多么地清晰。
</p>
		<p>
				<a name="introduction">
						<span class="atitle">Groovy 之声</span>
				</a>
		</p>
		<p>在 Bruce 和 Justin 这本书的第一章中，创建了一个简单的自行车商店应用程序，其中包含有四个类。首先，我将向您展示一个简单的名为 <code>Bike</code> 的 JavaBean 类，该类代表了一辆库存的自行车。然后，我会考查自行车商店的类型，名为 <code>RentABike</code>。它包含了一个 <code>Bike</code> 集。还有一个命名为 <code>CommandLineView</code> 的用于显示自行车列表的类，该类依赖于 <code>RentABike</code> 类型。最后，有一个用于集成这些部分以创建工作应用程序的类，该类利用 Spring 来传递完整地配置了 <code>RentABike</code> 类型的 <code>CommandLineView</code> 类 —— 免去了复杂的硬编码。 
</p>
		<p>
				<a name="quietingdown">
						<span class="smalltitle">停用 JavaBean！</span>
				</a>
		</p>
		<p>  
清单 1 中一个代表自行车的类在常规 Java 代码中被实现为一个简单的 JavaBean，它是 Java 开发人员可能已经编写好的成百上千的类的一个典型。通常来说，JavaBean 并没有什么特殊之处 —— 其属性被声明为 <code>private</code>，且可通过 <code>public</code> getter 和 setter 对其进行访问。
</p>
		<br />
		<a name="listing1">
				<b>清单 1. Java 代码中的 Bike JavaBean</b>
		</a>
		<br />
		<table border="0" cellpadding="0" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td class="code-outline">
										<pre class="displaycode">
												<br />import java.math.BigDecimal;<br /><br />public class Bike {<br />   private String manufacturer;<br />   private String model;<br />   private int frame;<br />   private String serialNo;<br />   private double weight;<br />   private String status;<br />   private BigDecimal cost;<br /><br />   public Bike(String manufacturer, String model, int frame, <br />     String serialNo, double weight, String status) {<br />      this.manufacturer = manufacturer;<br />      this.model = model;<br />      this.frame = frame;<br />      this.serialNo = serialNo;<br />      this.weight = weight;<br />      this.status = status;<br />   }<br /><br />   public String toString() {<br />      return "com.springbook.Bike : " +<br />            "manufacturer -- " + manufacturer +<br />            "\n: model -- " + model +<br />            "\n: frame -- " + frame +<br />            "\n: serialNo -- " + serialNo +<br />            "\n: weight -- " + weight +<br />            "\n: status -- " + status +<br />            ".\n"; }<br /><br />   public String getManufacturer() { return manufacturer; }<br /><br />   public void setManufacturer(String manufacturer) {<br />      this.manufacturer = manufacturer;<br />   }<br /><br />   public String getModel() { return model; }<br /><br />   public void setModel(String model) { this.model = model; }<br /><br />   public int getFrame() { return frame; }<br /><br />   public void setFrame(int frame) { this.frame = frame; }<br /><br />   public String getSerialNo() { return serialNo; }<br /><br />   public void setSerialNo(String serialNo) { this.serialNo = serialNo; }<br /><br />   public double getWeight() { return weight; }<br /><br />   public void setWeight(double weight) { this.weight = weight; }<br /><br />   public String getStatus() { return status; }<br /><br />   public void setStatus(String status) { this.status = status; }<br /><br />   public BigDecimal getCost() { return cost; }<br /><br />   public void setCost(BigDecimal cost) {<br />     this.cost = cost.setScale(3,BigDecimal.ROUND_HALF_UP);<br />   }<br /><br />}  <br /></pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>
清单 1 是一个只有一个构造方法和六个属性的小例子，但其代码却填满了浏览器的整个页面！清单 2 显示了在 Groovy 中定义的相同的 JavaBean： 
</p>
		<br />
		<a name="listing2">
				<b>清单 2. Bike GroovyBean</b>
		</a>
		<br />
		<table border="0" cellpadding="0" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td class="code-outline">
										<pre class="displaycode">
												<br />class Bike {<br /><br />  String manufacturer<br />  String model<br />  Integer frame<br />  String serialNo<br />  Double weight<br />  String status<br />  BigDecimal cost<br /><br />  public void setCost(BigDecimal newCost) {<br />    cost = newCost.setScale(3, BigDecimal.ROUND_HALF_UP)<br />  }<br /><br /><br />  public String toString() {<br />    return """Bike:<br />         manufacturer --  ${manufacturer} <br />         model -- ${model}<br />         frame -- ${frame} <br />         serialNo -- ${serialNo}  <br />      """<br />  }<br />}<br /></pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>您认为哪一个没那么多冗余呢？</p>
		<p>
Groovy 版的代码要少很多很多，这是因为 Groovy 的默认属性语义用 <code>public</code> 访问器和存取器自动定义了 <code>private</code> 域。例如，上述 <code>model</code> 属性现在有了自动定义的 <code>getModel()</code> 方法和 <code>setModel()</code> 方法。可以看到，这项技术的好处是，不必在一种类型中按照属性手工定义两个方法！这也解释了 Groovy 中的一条反复强调的定律：<i>使普通的编码规则变得简单</i>。
 </p>
		<table align="right" border="0" cellpadding="0" cellspacing="0" width="40%">
				<tbody>
						<tr>
								<td width="10">
										<img alt="" src="http://www.ibm.com/i/c.gif" height="1" width="10" />
								</td>
								<td>
										<table border="1" cellpadding="5" cellspacing="0" width="100%">
												<tbody>
														<tr>
																<td bgcolor="#eeeeee">
																		<a name="N100E8">
																				<b>Groovy 更新了的属性语法</b>
																		</a>
																		<br />
        最新版的 Groovy, JSR-06 简化了 Groovy 的属性语法。在此版本之前，属性要在变量声明前跟一个特定的 <code>@Property</code> 符号。但这个符号现在已经不再需要。在 JSR-06 中，只需指定一个类型和一个变量名，就会自动生成一个有着 <code>public</code> getter 和 setter 的 <code>private</code> 属性。也可以使用 <code>def</code> 关键字来代替特定的类型。</td>
														</tr>
												</tbody>
										</table>
								</td>
						</tr>
				</tbody>
		</table>
		<p>
        另外，在 Groovy 中，类的默认函数表达得更为简洁，而在常规 Java 代码（如 <a href="http://www.ibm.com/developerworks/cn/java/j-pg09196.html#listing1">清单 1</a>）中该函数必须显式编码。当需要用构造函数或 getter 或 setter 来完成一些特殊任务时，Groovy 真的很出色，因为<i>只需瞥一眼代码</i>，其精彩的行为就会立即变得十分明显。例如，在 <a href="http://www.ibm.com/developerworks/cn/java/j-pg09196.html#listing2">清单 2</a> 中很容易看出，<code>setCost()</code> 方法会将 <code>cost</code> 属性换算为三个十进制的位。
        </p>
		<p>
		将这段不太显眼的 Groovy 代码同 <a href="http://www.ibm.com/developerworks/cn/java/j-pg09196.html#listing1">清单 1</a> 中的 Java 源代码进行比较。第一次阅读这段代码时，您注意到 <code>setCost()</code> 方法中嵌入了特殊的函数了吗？除非仔细观察，否则太容易看漏了！
      </p>
		<p>
				<a name="quietingdown">
						<span class="smalltitle">Groovy 测试</span>
				</a>
		</p>
		<p>
清单 3 中 <code>Bike</code> 类的测试用例展示了如何使用自动生成的访问器。同时，出于进一步简化通用编程任务的考虑，测试用例也使用了更为简便的 Groovy <i>点属性名</i> 标记来访问属性。相应地，能够通过 <code>getModel()</code> 方法或更为简洁的 <code>b.model</code> 形式来引用 <code>model</code> 属性。
</p>
		<br />
		<a name="listing3">
				<b>清单 3. Groovy 中的 Bike 测试用例</b>
		</a>
		<br />
		<table border="0" cellpadding="0" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td class="code-outline">
										<pre class="displaycode">
												<br />class BikeTest extends GroovyTestCase {<br />  void testBike() {<br />    // Groovy way to initialize a new object<br />    def b = new Bike(manufacturer:"Shimano", model:"Roadmaster")<br /><br />    // explicitly call the default accessors<br />    assert b.getManufacturer() == "Shimano"<br />    assert b.getModel() == "Roadmaster"<br /><br />    // Groovier way to invoke accessors<br />    assert b.model == "Roadmaster"<br />    assert b.manufacturer == "Shimano"<br />  }<br />}<br /></pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>
也注意到在上述 Groovy 例子中，不必定义一个如 <a href="http://www.ibm.com/developerworks/cn/java/j-pg09196.html#listing1">清单 1</a> 中定义的 Java 构造函数那样的能够接受全部六个属性的构造函数。同时，也不必要创建<i>另一个</i> 只含两个参数的构造函数来支持测试用例 —— 在对象创建过程中设置对象属性的 Groovy 的语义不需要这种冗余、烦人的构造函数（它们综合有多个参数但其作用却只是初始化变量）。
</p>
		<table align="right" border="0" cellpadding="0" cellspacing="0" width="40%">
				<tbody>
						<tr>
								<td width="10">
										<img alt="" src="http://www.ibm.com/i/c.gif" height="1" width="10" />
								</td>
								<td>
										<table border="1" cellpadding="5" cellspacing="0" width="100%">
												<tbody>
														<tr>
																<td bgcolor="#eeeeee">
																		<a name="N10151">
																				<b>Groovy 和 IDE</b>
																		</a>
																		<br />
        像 Eclipse 那样的 IDE 使得自动创建 getter 和 setter 变得十分简单。这些工具也便利了从具体类中提取接口以利于对其进行重构。但我敢说，读那段代码的次数要比写它的次数<i>多很多</i>。
不幸的是，开发人员仍需要通过已经生成的代码和源文件来费力地分辨程序真正在实现什么。用这个高质量的 Java 工具究竟能不能节省创建
Groovy 源代码的敲键次数尚有争议，但一看即明的是 Groovy
代码更为简洁、更易于解释，且没那么复杂。在实际的有着数百个类和数千行代码的应用程序，这种优势就更为突出。 </td>
														</tr>
												</tbody>
										</table>
								</td>
						</tr>
				</tbody>
		</table>
		<p>
				<a name="removingcomplexity">
						<span class="atitle">降低的复杂性</span>
				</a>
		</p>
		<p>
在前面的部分中，<code>Bike</code> GroovyBean 利用了 Groovy 的属性和构造语义以减少源代码中的冗余。在这一部分中，Groovy 版的自行车商店也将受益于额外的冗余减少特性，如针对多态的 duck-typing、集合类的改进及操作符重载。
</p>
		<p>
				<a name="removingcomplexity">
						<span class="smalltitle">Grooving 中使用多态</span>
				</a>
		</p>
		<p>
在 Java 自行车应用程序中，名为 <code>RentABike</code> 的接口是用来定义由自行车商店支持的 <code>public</code> 方法的。正如在清单 4 中说明的那样，<code>RentABike</code> 定义了一些简单的方法，这些方法用来返回商店中单个的 <code>Bike</code> 或所有 <code>Bike</code> 的列表。
</p>
		<br />
		<a name="listing4">
				<b>清单 4. 由 Java 定义的 RentABike 接口</b>
		</a>
		<br />
		<table border="0" cellpadding="0" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td class="code-outline">
										<pre class="displaycode">
												<br />import java.util.List;<br /><br />public interface RentABike {<br />   List getBikes();<br />   Bike getBike(String serialNo);<br />   void setStoreName(String name);<br />   String getStoreName();<br />}<br /></pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>
此接口允许多态行为并在下面两种重要情况下提供了灵活性。其一，如果要决定将实现由 <code>ArrayList</code> 转变为数据库形式，余下的应用程序与该变化是隔绝的。其二，使用接口为单元测试提供灵活性。例如，如果要决定为应用程序使用数据库，可以轻易地创建一个该类型的模拟实现，而且它不依赖于实时数据库。
</p>
		<p>
清单 5 是 <code>RentABike</code> 接口的 Java 实现，它使用 <code>ArrayList</code> 来存储多个 <code>Bike</code> 类：
</p>
		<br />
		<a name="listing5">
				<b>清单 5. RentABike 接口的 Java 实现</b>
		</a>
		<br />
		<table border="0" cellpadding="0" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td class="code-outline">
										<pre class="displaycode">
												<br />import java.util.List;<br />import java.util.ArrayList;<br />import java.util.Iterator;<br /><br />public class ArrayListRentABike implements RentABike {<br />   private String storeName;<br />   final List bikes = new ArrayList();<br /><br />   public void setStoreName(String name) {<br />      this.storeName = name;<br />   }<br /><br />   public String getStoreName() {<br />      return storeName;<br />   }<br /><br />   public ArrayListRentABike(String storeName) {<br />      this.storeName = storeName;<br />      bikes.add(new Bike("Shimano", "Roadmaster", 20, "11111", 15, "Fair"));<br />      bikes.add(new Bike("Cannondale", "F2000 XTR", 18, "22222",12, "Excellent"));<br />      bikes.add(new Bike("Trek","6000", 19, "33333", 12.4,"Fair"));<br />   }<br /><br />   public String toString() { return "com.springbook.RentABike: " + storeName; }<br /><br />   public List getBikes() { return bikes; }<br /><br />   public Bike getBike(String serialNo) {<br />      Iterator iter = bikes.iterator();<br />      while(iter.hasNext()) {<br />         Bike bike = (Bike)iter.next();<br />         if(serialNo.equals(bike.getSerialNo())) return bike;<br /><br />      }<br />      return null;<br />   }<br />}<br /></pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>现在将 <a href="http://www.ibm.com/developerworks/cn/java/j-pg09196.html#listing4">清单 4</a> 和 <a href="http://www.ibm.com/developerworks/cn/java/j-pg09196.html#listing5">5</a> 中的 Java 代码同 <a href="http://www.ibm.com/developerworks/cn/java/j-pg09196.html#listing6">清单 6</a> 中的 Groovy 代码进行比较。Groovy 版的代码很灵巧地避免了对 <code>RentABike</code> 接口的需求。
		</p>
		<br />
		<a name="listing6">
				<b>清单 6. Groovy 的 ArrayListRentABike 实现</b>
		</a>
		<br />
		<table border="0" cellpadding="0" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td class="code-outline">
										<pre class="displaycode">
												<br />public class ArrayListRentABike {<br />  String storeName<br />  List bikes = []<br />  public ArrayListRentABike(){		<br />    // add new instances of Bike using Groovy's initializer syntax<br />    bikes &lt;&lt; new Bike(manufacturer:"Shimano", model:"Roadmaster",<br />      frame: 20, serialNo:"11111", weight:15,	status:"Fair")<br />    bikes &lt;&lt; new Bike(manufacturer:"Cannondale", model:"F2000",<br />      frame: 18, serialNo:"22222", weight:12,	status:"Excellent")<br />    bikes &lt;&lt; new Bike(manufacturer:"Trek", model:"6000",<br />      frame: 19, serialNo:"33333", weight:12.4,	status:"Fair")<br />  }<br /><br />  // Groovy returns the last value if no return statement is specified<br />  public String toString() { "Store Name:=" + storeName }<br /><br />  // Find a bike by the serial number<br />  def getBike(serialNo) { bikes.find{it.serialNo == serialNo} }<br /><br />}<br /></pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>
		Groovy 像其他动态语言（如 Smalltalk 或 Ruby）一样支持具有 “duck typing” 的多态 —— 在运行时，如果一个对象<i>表现得像个 duck </i>，它就会<i>被视为 duck </i>，从而支持<i>无</i> 接口的多态。有了 Groovy <code>ArrayListRentABike</code> 实现，不但减少了成行的代码，而且由于少创建和维护一个模块，复杂性也降低了。那是非常重要的冗余减少！</p>
		<p>除了 duck typing，<a href="http://www.ibm.com/developerworks/cn/java/j-pg09196.html#listing6">清单 6</a> 中的默认属性语法还简单地定义了两个普通属性，<code>storeName</code> 和 <code>bikes</code>，如同拥有了 getter 和 setter 一样。这样做的好处和在 <a href="http://www.ibm.com/developerworks/cn/java/j-pg09196.html#listing1">清单 1</a> 和 <a href="http://www.ibm.com/developerworks/cn/java/j-pg09196.html#listing2">2</a> 中比较 JavaBean-GroovyBean 时所说明的好处是一样的。尤其是，<a href="http://www.ibm.com/developerworks/cn/java/j-pg09196.html#listing6">清单 6</a> 还阐明了另一个用以减少代码冗余的 Groovy 特性 —— 操作符重载。请注意如何使用 <code>&lt;&lt;</code> 操作符来<i>代替</i><code>add()</code> 方法。通过减少一层嵌套的括号使代码的可读性得以改善。这也是 Groovy 众多通过减少冗余而改善代码可读性的特性中的一种。</p>
		<table align="right" border="0" cellpadding="0" cellspacing="0" width="40%">
				<tbody>
						<tr>
								<td width="10">
										<img alt="" src="http://www.ibm.com/i/c.gif" height="1" width="10" />
								</td>
								<td>
										<table border="1" cellpadding="5" cellspacing="0" width="100%">
												<tbody>
														<tr>
																<td bgcolor="#eeeeee">
																		<a name="N10202">
																				<b>Groovy 方式下的和谐集合</b>
																		</a>
																		<br />
用诸如 <code>each</code> 和 <code>find</code> 的方法来使用闭包简化了最常见的任务集，如循环和查找。将 <a href="http://www.ibm.com/developerworks/cn/java/j-pg09196.html#listing5">清单 5</a> 中 Java 版本的 <code>getBike()</code> 同 <a href="http://www.ibm.com/developerworks/cn/java/j-pg09196.html#listing6">清单 6</a> 中 Groovy 版的进行比较。在 Groovy 中，很明显是通过其序列号来寻找 <code>Bike</code>。而在 Java 版中，定义了一个 <code>Iterator</code> 并计算列表中下一个条目，这很多余，且不利于理解该应用程序真正要实现的功能，即寻找一辆自行车。 
</td>
														</tr>
												</tbody>
										</table>
								</td>
						</tr>
				</tbody>
		</table>
		<p>
				<a name="simplerview">
						<span class="smalltitle">透明的代码</span>
				</a>
		</p>
		<p>Groovy 中的 duck-typing 和属性语义通过减少代码行数来减少冗余；然而，也可以通过增加透明度来减少冗余。在 <a href="http://www.ibm.com/developerworks/cn/java/j-pg09196.html#Listing6">清单 6</a> 中，请注意在 <code>ArrayListRentABike</code> 构造函数中创建新 <code>Bike</code> 对象的方式。Groovy 名称和值的初始化语法比 Java 版的略微详细，但这些额外的代码却使整个代码更为透明 —— 将这一点与 <a href="http://www.ibm.com/developerworks/cn/java/j-pg09196.html#listing5">清单 5</a> 中 Java 版的进行比较，哪个属性被初始化为哪个值会<i>立即明显</i> 起来。不回过头来看 <code>Bike</code> JavaBean 源代码，您能记起哪个参数是 <code>frame</code>，哪个是 <code>new Bike("Shimano"、 "Roadmaster"、20、 "11111"、15、 "Fair")</code> 的 <code>weight</code> 吗？尽管我刚写过，但我还是记不起来！</p>
		<br />
		<table border="0" cellpadding="0" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td>
										<img src="http://www.ibm.com/i/v14/rules/blue_rule.gif" alt="" height="1" width="100%" />
										<br />
										<img alt="" src="http://www.ibm.com/i/c.gif" border="0" height="6" width="8" />
								</td>
						</tr>
				</tbody>
		</table>
		<table class="no-print" align="right" cellpadding="0" cellspacing="0">
				<tbody>
						<tr align="right">
								<td>
										<img src="http://www.ibm.com/i/c.gif" alt="" height="4" width="100%" />
										<br />
										<br />
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<br />
		<p>
				<a name="simplerview">
						<span class="atitle">一个更小的、更加 Groovy 化的自行车商店视图</span>
				</a>
		</p>
		<p>到目前为止，我将 <code>Bike</code> 和自行车商店类型在 Java 和 Groovy 下进行了比较。现在，到了更近距离地看一下自行车商店的<i>视图</i> 的时候了。在清单 7 中，该视图类具有一个 <code>rentaBike</code> 属性，该属性引用 <code>RentABike</code> 接口并在行动上说明 Java 版的多态。由于 Java 要求所有类属性都必须是声明过的类型，而不是针对某个特定的实现进行编码，我向一个接口编程，该接口使这个类跟 <code>RentABike</code> 实现的改变分隔开来。这是很好的、扎实的 Java 编程实践。
        </p>
		<br />
		<a name="listing7">
				<b>清单 7. Java 版的自行车商店视图</b>
		</a>
		<br />
		<table border="0" cellpadding="0" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td class="code-outline">
										<pre class="displaycode">
												<br />public class CommandLineView {<br />   private RentABike rentaBike;<br /><br />   public CommandLineView() {}<br /><br />   public void setRentaBike(RentABike rentaBike) {<br />      this.rentaBike = rentaBike;<br />   }<br /><br />   public RentABike getRentaBike() { return this.rentaBike; }<br /><br />   public void printAllBikes() {<br />      System.out.println(rentaBike.toString());<br />      Iterator iter = rentaBike.getBikes().iterator();<br />      while(iter.hasNext()) {<br />         Bike bike = (Bike)iter.next();<br />         System.out.println(bike.toString());<br />      }<br />   }<br />}<br /></pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>将清单 7 中的 Java 视图与清单 8 中的 Groovy 视图进行比较，请注意我声明了带  <code>def</code> 关键字的 <code>rentaBike</code>。这是 duck-typing 的实践，与 Java 版的很像。我正在实践好的软件设计，这是因为我还没有将视图和特定的实现耦合起来。但我也能够<i>不</i> 定义接口就实现解耦。</p>
		<br />
		<a name="listing8">
				<b>清单 8. Groovy 的 CommandLineView</b>
		</a>
		<br />
		<table border="0" cellpadding="0" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td class="code-outline">
										<pre class="displaycode">
												<br />public class CommandLineView {<br />  def rentaBike  // no interface or concrete type required, duck typing in action<br /><br />  def printAllBikes() {<br />    println rentaBike<br />    rentaBike.bikes.each{ println it}  // no iterators or casting<br />  }<br />}<br /></pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>与 <code>Bike</code> 和自行车商店类型一样，Groovy 的 <code>CommandLineView</code> 没有了为 <code>RentABike</code> 属性所显式编写 的 getter 或 setter 的冗余。同样，在 <code>printAllBikes()</code> 方法中，通过使用 <code>each</code> 来打印在集合里找到的每辆自行车，我再一次利用了 Groovy 强大的集合功能的改进。 </p>
		<br />
		<table border="0" cellpadding="0" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td>
										<img src="http://www.ibm.com/i/v14/rules/blue_rule.gif" alt="" height="1" width="100%" />
										<br />
										<img alt="" src="http://www.ibm.com/i/c.gif" border="0" height="6" width="8" />
								</td>
						</tr>
				</tbody>
		</table>
		<table class="no-print" align="right" cellpadding="0" cellspacing="0">
				<tbody>
						<tr align="right">
								<td>
										<img src="http://www.ibm.com/i/c.gif" alt="" height="4" width="100%" />
										<br />
										<br />
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<br />
		<p>
				<a name="nointefaces">
						<span class="atitle">使用 Spring 进行组装</span>
				</a>
		</p>
		<p>在前面的部分中，已经介绍了 Groovy 相比 Java 是如何定义自行车、自行车商店和自行车商店视图的。现在该介绍如何将整个应用程序组装起来并在命令行视图中使用 Spring 来显示库存自行车列表了。
		</p>
		<p>
				<a name="nointefaces">
						<span class="smalltitle">工厂的工厂</span>
				</a>
		</p>
		<p>
在 Java 编程中，一旦定义了一个接口，就可以使用工厂模式将创建真实的实现类的责任委派给一个对象工厂。使用 Spring
作为一个工厂极大地减少了冗余，并在 Groovy 和 Java 中都能够使用，在最终的代码样例中，Spring 负责在 Java 和
Groovy 中创建一个 <code>CommandLineView</code> 类型的实例。</p>
		<p>在清单 9 中，配置 Spring 是为了在返回一个 <code>CommandLineView</code> 实例前，创建并将自行车商店的 <code>ArrayList</code> 实现注入 <code>CommandLineView</code> 中。这意味着，不需要引用在 <a href="http://www.ibm.com/developerworks/cn/java/j-pg09196.html#listing7">清单 7</a> 和 <a href="http://www.ibm.com/developerworks/cn/java/j-pg09196.html#listing8">8</a> 的 Java 或是 Groovy 版的命令行视图中的 <code>ArrayList</code> 实现。在 Java 版中，被注入的类通常都会引用一个接口而不是实现。在 Groovy 中，由于使用 <code>def</code> 关键字，而允许利用 duck-typing。无论在哪个实例中，配置 Spring 的目的都是为了将自行车商店视图的实例和自行车商店类型的实例<i>完整地配置起来</i>！
      </p>
		<br />
		<a name="listing9">
				<b>清单 9. Spring 配置文件</b>
		</a>
		<br />
		<table border="0" cellpadding="0" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td class="code-outline">
										<pre class="displaycode">
												<br />&lt;beans&gt;<br />    &lt;bean id="rentaBike" class="ArrayListRentABike"&gt;<br />        &lt;property name="storeName"&gt;&lt;value&gt;"Bruce's Bikes (spring bean)"&lt;/value&gt;&lt;/property&gt;<br />    &lt;/bean&gt;<br />    &lt;bean id="commandLineView" class="CommandLineView"&gt;<br />        &lt;property name="rentaBike"&gt;&lt;ref bean="rentaBike"/&gt;&lt;/property&gt;<br />    &lt;/bean&gt;<br />&lt;/beans&gt;<br /></pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>在清单 10 和 11 中，自行车商店组装类型用清单 9 中的配置文件创建了一个 Spring 的 <code>ClassPathXmlApplicationContext</code> 实例，然后，请求自行车商店视图的实例：
      </p>
		<br />
		<a name="listing10">
				<b>清单 10. Java 版本下调用 Spring 创建自行车商店视图</b>
		</a>
		<br />
		<table border="0" cellpadding="0" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td class="code-outline">
										<pre class="displaycode">
												<br />import org.springframework.context.support.ClassPathXmlApplicationContext;<br /><br />public class RentABikeAssembler {<br />   public static final void main(String[] args) {<br />      // Create a Spring application context object<br />      ClassPathXmlApplicationContext ctx = <br />        new ClassPathXmlApplicationContext("RentABike-context.xml");<br /><br />      // retrieve an object from Spring and cast to a specific type<br />      CommandLineView clv = (CommandLineView)ctx.getBean("commandLineView");<br /><br />      clv.printAllBikes();<br />   }<br />}<br /></pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>请注意Java 版的清单 10 中，用以请求一个命令行视图实例的对 Spring 的调用要求向一个支持 <code>printAllBikes()</code> 方法的对象类型强制转换。在本例中，由 Spring 导出的对象将被强制转换为 <code>CommandLineView</code>。
		</p>
		<p>
		有了 Groovy 及其对 duck-typing 的支持，将不再需要强制转换。只需确保由 Spring 返回的类能够对合适的方法调用（<code>printAllBikes()</code>）作出响应。</p>
		<br />
		<a name="listing11">
				<b>清单 11. Groovy 版的 Spring 组合件</b>
		</a>
		<br />
		<table border="0" cellpadding="0" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td class="code-outline">
										<pre class="displaycode">
												<br />import org.springframework.context.support.ClassPathXmlApplicationContext<br /><br />class RentABikeAssembler {<br />  public static final void main(String[] args) {<br />    // Create a Spring application context object<br />    def ctx = new ClassPathXmlApplicationContext("RentABike-context.xml")<br /><br />    //Ask Spring for an instance of CommandLineView, with a <br />    //Bike store implementation set by Spring<br />    def clv = ctx.getBean("commandLineView")<br /><br />    //duck typing again<br />    clv.printAllBikes()<br />  }<br />}<br /></pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>
  正如在清单 11 中看到的那样，在 Groovy 中，duck-typing 对减少冗余的贡献不仅体现在无需声明接口即可支持由 Spring 自动配置对象，其贡献还体现在简化了对完全配置的 bean 的使用（一旦它从 Spring 容器中返回）。</p>
		<br />
		<table border="0" cellpadding="0" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td>
										<img src="http://www.ibm.com/i/v14/rules/blue_rule.gif" alt="" height="1" width="100%" />
										<br />
										<img alt="" src="http://www.ibm.com/i/c.gif" border="0" height="6" width="8" />
								</td>
						</tr>
				</tbody>
		</table>
		<table class="no-print" align="right" cellpadding="0" cellspacing="0">
				<tbody>
						<tr align="right">
								<td>
										<img src="http://www.ibm.com/i/c.gif" alt="" height="4" width="100%" />
										<br />
										<br />
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<br />
		<p>
				<a name="conclusion">
						<span class="atitle">与 Groovy 相协调</span>
				</a>
		</p>
		<p>
至此，希望我已经阐明了 Groovy 的强大功能及其如何能如此深远地改变源代码的性质。与上述 Java 样例相比，Groovy
代码更简短也更易理解。任何人，无论是经验丰富的 Java 架构师还是非 Java 程序员，都能轻易地掌握 Groovy
代码的意图。Groovy 及其对动态类型的支持减少了要管理的文件。总之，使用 Groovy 减少了在典型的 Java
程序中所常见的大量冗余。这实在是福音啊！
</p>
<img src ="http://www.blogjava.net/JafeLee/aggbug/128681.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/JafeLee/" target="_blank">Jafe</a> 2007-07-06 21:17 <a href="http://www.blogjava.net/JafeLee/articles/128681.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>实战 Groovy: 美妙的操作符</title><link>http://www.blogjava.net/JafeLee/articles/128680.html</link><dc:creator>Jafe</dc:creator><author>Jafe</author><pubDate>Fri, 06 Jul 2007 13:16:00 GMT</pubDate><guid>http://www.blogjava.net/JafeLee/articles/128680.html</guid><wfw:comment>http://www.blogjava.net/JafeLee/comments/128680.html</wfw:comment><comments>http://www.blogjava.net/JafeLee/articles/128680.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/JafeLee/comments/commentRss/128680.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/JafeLee/services/trackbacks/128680.html</trackback:ping><description><![CDATA[
		<a href="http://www.ibm.com/developerworks/cn/java/j-pg10255.html#author">ndrew Glover</a>, CTO, Vanward Technologies<br /><p>2005 年  11 月  30 日</p><blockquote>Java™ 取消了操作符重载，但是新兴的 Groovy 又使之浮出水面。在<i>实战 Groovy </i> 定期连载的“Groovy 每日应用”的最后一期中，请随着 Andrew Glover 介绍的三类可重载操作符，重新寻回自己多年来失去的东西。</blockquote><!--START RESERVED FOR FUTURE USE INCLUDE FILES--><!-- include java script once we verify teams wants to use this and it will work on dbcs and cyrillic characters --><!--END RESERVED FOR FUTURE USE INCLUDE FILES--><p>许多以前使用 C++ 的开发人员会怀念操作符重载，例如 <code>+</code> 和 <code>-</code>。虽然它们很方便，但是被覆盖的操作符的多态实质会造成混淆，所以操作符重载在 Java 语言中被取消了。这个限制的好处是清晰：Java 开发人员不必猜想两个对象上的 <code>+</code> 是把它们加在一起还是把一个对象附加到另一个对象上。不好的地方则是丧失了一个有价值的简写形式。</p><table align="right" border="0" cellpadding="0" cellspacing="0" width="40%"><tbody><tr><td width="10"><img alt="" src="http://www.ibm.com/i/c.gif" height="1" width="10" /></td><td><br /></td></tr></tbody></table><p>现在，期望<i>放任自由的</i> Groovy 把这个简写形式带回来！在 <i>实战 Groovy</i> 的这一期中，我将介绍 Groovy 对<i>操作符即时多态</i>（也称为操作符重载）的支持。正如 C++ 开发人员会告诉您的，这个东西既方便又有趣，虽然必须小心谨慎才能接近。</p><p><a name="N10093"><span class="atitle">三类可重载操作符</span></a></p><p>我把 Groovy 的可重载操作符分成三个逻辑组： 比较操作符、算术类操作符和数组类操作符。这几组只涵盖了普通 Java 编程中可用操作符的一个子集。例如，像 <code>&amp;</code> 和 <code>^</code> 这样的逻辑操作符目前在 Groovy 中不可用。 </p><p>表 1 显示了 Groovy 中可用的三组可重载操作符：</p><br /><br /><a name="N100A7"><b>表 1. Groovy 的可重载操作符</b></a><br /><table class="data-table-1" summary="Table 1. Groovy's overloadable operators" border="0" cellpadding="0" cellspacing="0" width="100%"><tbody><tr><td class="tb-row">1.</td><td>比较操作符对应着普通的 Java <code>equals</code> 和 <code>compareTo</code> 实现 </td></tr><tr class="alt-row"><td class="tb-row">2.</td><td>Java 的算术类操作符，例如 <code>+</code>、<code>-</code> 和 <code>*</code></td></tr><tr><td class="tb-row">3.</td><td>数组存取类操作符 <code>[]</code></td></tr></tbody></table><br /><table border="0" cellpadding="0" cellspacing="0" width="100%"><tbody><tr><td><img src="http://www.ibm.com/i/v14/rules/blue_rule.gif" alt="" height="1" width="100%" /><br /><img alt="" src="http://www.ibm.com/i/c.gif" border="0" height="6" width="8" /></td></tr></tbody></table><table class="no-print" align="right" cellpadding="0" cellspacing="0"><tbody><tr align="right"><td><img src="http://www.ibm.com/i/c.gif" alt="" height="4" width="100%" /><br /><br /></td></tr></tbody></table><br /><br /><p><a name="N100EE"><span class="atitle">比较操作符</span></a></p><p>比较操作符对应着 Java 语言中的 <code>equals</code> 和 <code>compareTo</code> 实现，通常用作集合中排序的快捷方式。表 2 显示了 Groovy 的两个比较操作符：</p><br /><br /><a name="N100FF"><b>表 2. 比较操作符</b></a><br /><table class="data-table-1" summary="Table using a caption tag, alternating color rows" border="0" cellpadding="0" cellspacing="0" width="100%"><caption><em></em><br /></caption><tbody><tr><th>操作符</th><th>方法</th></tr><tr class="alt-row"><td class="tb-row">a == b</td><td><code>a.equals(b)</code></td></tr><tr><td class="tb-row"> a &lt;=&gt; b</td><td><code>a.compareTo(b) </code></td></tr></tbody></table><p>操作符 <code>==</code> 是 Java 语言中表示对象相等的简写形式，但是不代表对象引用的相等。换句话说，放在两个对象之间的 Groovy 的 <code>==</code> 意味着它们相同，因为它们的属性是相等的，虽然每个对象指向独立的引用。</p><p>根据 Javadoc，Java 语言的 <code>compareTo()</code> 方法返回负整数、0 或正整数，代表对象小于、等于或大于指定对象。因为这个方法能够返回三个值，所以 Groovy 用四个附加值扩充了 <code>&lt;=&gt;</code> 语法，如表 3 所示：</p><br /><br /><a name="N10150"><b>表 3. 四个附加的值</b></a><br /><table class="data-table-1" summary="Table using a caption tag, alternating color rows" border="0" cellpadding="0" cellspacing="0" width="100%"><caption><em></em><br /></caption><tbody><tr><th>操作符</th><th>含义</th></tr><tr class="alt-row"><td class="tb-row"> a &gt; b</td><td>如果 <code>a.compareTo(b) </code> 返回的值大于 0，那么这个条件为 <code>true</code></td></tr><tr><td class="tb-row">  a &gt;= b</td><td> 如果 <code>a.compareTo(b)</code> 返回的值大于等于 0，那么这个条件为 <code>true</code></td></tr><tr class="alt-row"><td class="tb-row"> a &lt; b</td><td>如果 <code>a.compareTo(b)</code> 小于 0，那么这个条件为 <code>true</code></td></tr><tr><td class="tb-row">  a &lt;= b</td><td>如果 <code>a.compareTo(b)</code> 小于等于 0，那么这个条件为 <code>true</code></td></tr></tbody></table><p><a name="N101B8"><span class="smalltitle">比较购物</span></a></p><p>还记得我最初在“<a href="http://www.ibm.com/developerworks/cn/java/j-alj08034/">感受 Groovy</a>”一文中定义的磁盘友好的 <code>LavaLamp</code> 类么，它还在“<a href="http://www.ibm.com/developerworks/cn/java/j-pg07195.html">实战 Groovy: Groovy 的腾飞</a>”一文中充当迁移到新的 JSR 语法的示例，我要再次使用这个类来演示使用比较操作符的一些漂亮的技巧。</p><p>在清单 1 中，我通过实现普通 Java 的 <code>equals()</code> 方法（以及它的可恶伙伴 <code>hashCode</code>）增强了 <code>LavaLamp</code> 类。另外，我让 <code>LavaLamp</code> 实现了 Java 语言的 <code>Comparable</code> 接口并创建了 <code>compareTo()</code> 方法的实现：</p><br /><br /><a name="code1"><b>清单 1. LavaLamp 归来！</b></a><br /><table border="0" cellpadding="0" cellspacing="0" width="100%"><tbody><tr><td class="code-outline"><pre class="displaycode">package com.vanward.groovy<br />import org.apache.commons.lang.builder.CompareToBuilder<br />import org.apache.commons.lang.builder.EqualsBuilder<br />import org.apache.commons.lang.builder.HashCodeBuilder<br />import org.apache.commons.lang.builder.ToStringBuilder<br />class LavaLamp implements Comparable{<br /> @Property model<br /> @Property baseColor<br /> @Property liquidColor<br /> @Property lavaColor<br /><br />  def String toString() {<br />    return new ToStringBuilder(this).<br />        append(this.model).<br />	    append(this.baseColor).<br />	    append(this.liquidColor).<br />	    append(this.lavaColor).<br />	    toString()<br />  } <br /><br />  def boolean equals(obj) {<br />      if (!(obj instanceof LavaLamp)) {<br />         return false<br />      }<br />      LavaLamp rhs = (LavaLamp) obj<br />         return new EqualsBuilder().<br />             append(this.model, rhs.model).<br />             append(this.baseColor, rhs.baseColor).<br />             append(this.liquidColor, rhs.liquidColor).<br />             append(this.lavaColor, rhs.lavaColor).  	    <br />             isEquals()<br />   }<br />   def int hashCode() {<br />      return new HashCodeBuilder(17, 37).  <br />           append(this.model).<br />           append(this.baseColor).<br />           append(this.liquidColor).          <br />           append(this.lavaColor).<br />           toHashCode()<br />   }<br />   def int compareTo(obj) {<br />      LavaLamp lmp = (LavaLamp)obj<br />         return new CompareToBuilder().<br />             append(lmp.model, this.model).          <br />             append(lmp.lavaColor, this.lavaColor).<br />             append(lmp.baseColor, this.baseColor).<br />             append(lmp.liquidColor, this.liquidColor).<br />             toComparison()<br />   }	<br />}<br /></pre></td></tr></tbody></table><br /><p><b>注：</b><i>因为我是重用狂，所以我的这些实现严重依赖 Jakarta 的 Commons Lang 项目（甚至 </i><code>toString()</code><i> 方法也是如此！）如果您还在自己编写 </i><code>equals()</code><i> 方法，那么您可能想花一分钟来签出这个库。（请参阅 </i><a href="http://www.ibm.com/developerworks/cn/java/j-pg10255.html#resources">参考资料</a><i>。）</i></p><p>在清单 2 中，可以看到我在清单 1 中设置的操作符重载的效果。我创建了五个 <code>LavaLamp</code> 实例（没错，我们在开 party！）并用 Groovy 的比较操作符来区分它们：</p><br /><br /><a name="code2"><b>清单 2. 比较操作符的效果</b></a><br /><table border="0" cellpadding="0" cellspacing="0" width="100%"><tbody><tr><td class="code-outline"><pre class="displaycode">lamp1 = new LavaLamp(model:"1341", baseColor:"Black", <br />         liquidColor:"Clear", lavaColor:"Red")<br />lamp2 = new LavaLamp(model:"1341", baseColor:"Blue", <br />         liquidColor:"Clear", lavaColor:"Red")<br />lamp3 = new LavaLamp(model:"1341", baseColor:"Black", <br />         liquidColor:"Clear", lavaColor:"Blue")<br />lamp4 = new LavaLamp(model:"1342", baseColor:"Blue", <br />         liquidColor:"Clear", lavaColor:"DarkGreen")<br />lamp5 = new LavaLamp(model:"1342", baseColor:"Blue", <br />         liquidColor:"Clear", lavaColor:"DarkGreen")<br /><br />println lamp1 &lt;=&gt; lamp2  //  1<br />println lamp1 &lt;=&gt; lamp3  // -1<br />println lamp1 &lt; lamp3    //  true<br />println lamp4 &lt;=&gt; lamp5  //  0<br />assert lamp4 == lamp5<br />assert lamp3 != lamp4<br /></pre></td></tr></tbody></table><br /><p>注意 <code>lamp4</code> 和 <code>lamp5</code> 是如何相同的，以及其他对象之间具有什么样的细微差异。因为 <code>lamp1</code> 的 <code>baseColor</code> 是 <code>Black</code> 而<code>lamp2</code> 的
<code>baseColor</code> 是 <code>Blue</code>，所以
<code>&lt;=&gt;</code> 返回 <code>1</code>（black 中的 <i>a</i> 比 blue 中的 <i>u</i> 靠前）。类似地，<code>lamp3</code> 的 <code>lavaColor</code> 是 <code>Blue</code>，而 <code>lamp1</code> 的是 <code>Red</code>。因为条件 <code>lamp1 &lt;=&gt; lamp3</code> 返回 <code>-1</code>，所以语句 <code>lamp1 &lt;
lamp3</code> 返回 <code>true</code>。<code>llamp4</code> 和 <code>llamp5</code> 是相等的，所以 <code>&lt;=&gt;</code> 返回 <code>0</code>。</p><p>而且，可以看到 <code>==</code> 也适用于对象相等。<code>lamp4</code> 和 <code>lamp5</code> 是同一对象。当然，我应当用 <code>assert lamp4.equals(lamp5)</code> 证实这一点，但是 <code>==</code> 更快捷！ </p><p><a name="N1029F"><span class="smalltitle">我想要我的引用相等</span></a></p><p>现在，如果真的想测试对象引用相等该怎么办？显然，我不能用 <code>==</code>，但是 Groovy 为这类事情提供了 <code>is()</code> 方法，如清单 3 所示：</p><br /><br /><a name="code3"><b>清单 3. is() 的作用！</b></a><br /><table border="0" cellpadding="0" cellspacing="0" width="100%"><tbody><tr><td class="code-outline"><pre class="displaycode">lamp6 = new LavaLamp(model:"1344", baseColor:"Black", <br />             liquidColor:"Clear", lavaColor:"Purple")<br />lamp7 = lamp6<br />assert lamp7.is(lamp6)<br /></pre></td></tr></tbody></table><br /><p>在清单 3 中可以看出，<code>lamp6</code> 和 <code>lamp7</code> 是相同的引用，所以 <code>is</code> 返回 <code>true</code>。</p><p>顺便说一句，如果感觉迷糊，不要惊讶：使用重载操作符差不多让 Groovy 语言退步了。但是我认为是有趣的。</p><br /><table border="0" cellpadding="0" cellspacing="0" width="100%"><tbody><tr><td><img src="http://www.ibm.com/i/v14/rules/blue_rule.gif" alt="" height="1" width="100%" /><br /><img alt="" src="http://www.ibm.com/i/c.gif" border="0" height="6" width="8" /></td></tr></tbody></table><table class="no-print" align="right" cellpadding="0" cellspacing="0"><tbody><tr align="right"><td><img src="http://www.ibm.com/i/c.gif" alt="" height="4" width="100%" /><br /><br /></td></tr></tbody></table><br /><br /><p><a name="N102D1"><span class="atitle">算术类操作符</span></a></p><p>Groovy 支持以下算术类操作符的重载：</p><br /><br /><a name="table3"><b>表 3. Groovy 的算术类操作符</b></a><br /><table class="data-table-1" summary="Table using a caption tag, alternating color rows" border="0" cellpadding="0" cellspacing="0" width="100%"><caption><em></em><br /></caption><tbody><tr><th>操作符</th><th>方法</th></tr><tr class="alt-row"><td class="tb-row">a + b</td><td><code> a.plus(b)</code></td></tr><tr><td class="tb-row"> a - b</td><td><code> a.minus(b) </code></td></tr><tr class="alt-row"><td class="tb-row">a * b</td><td><code> a.multiply(b)</code></td></tr><tr><td class="tb-row"> a / b</td><td><code> a.divide(b) </code></td></tr><tr class="alt-row"><td class="tb-row">a++ or ++a</td><td><code> a.next()</code></td></tr><tr><td class="tb-row">a-- or --a</td><td><code> a.previous() </code></td></tr><tr class="alt-row"><td class="tb-row">a &lt;&lt; b</td><td><code> a.leftShift(b)</code></td></tr></tbody></table><p> 您可能已经注意到 Groovy 中的 <code>+</code> 操作符已经在几个不同的领域重载了，特别是在用于集合的时候。您是否想过，这怎么可能？或者至少想过对自己的类能否这么做？现在我们来看答案。</p><p><a name="N10365"><span class="smalltitle">添加操作符</span></a></p><p>还记得“<a href="http://www.ibm.com/developerworks/cn/java/j-pg05245/">在 Java 应用程序中加一些 Groovy 进来</a>”一文中的  <code>Song</code> 类么？我们来看看当我创建一个 JukeBox 对象来播放 <code>Song</code> 时，发生了什么。在清单 4 中，我将忽略实际播放 MP3 的细节，把重点放在从 <code>JukeBox</code> 添加和减去 <code>Song</code> 上：</p><br /><br /><a name="code4"><b>清单 4. Jukebox</b></a><br /><table border="0" cellpadding="0" cellspacing="0" width="100%"><tbody><tr><td class="code-outline"><pre class="displaycode">package com.vanward.groovy<br />import com.vanward.groovy.Song<br />class JukeBox {<br /><br />  def songs  <br />  JukeBox(){   <br />    songs = []      <br />  }<br />  def plus(song){<br />    this.songs &lt;&lt; song<br />  }<br />  def minus(song){    <br />    def val = this.songs.lastIndexOf(song)<br />    this.songs.remove(val)<br />  }<br /><br />  def printPlayList(){<br />     songs.each{ song -&gt; println "${song.getTitle()}" }<br />  }<br />}<br /></pre></td></tr></tbody></table><br /><p>通过实现 <code>plus()</code> 和 <code>minus()</code> 方法，我重载了 <code>+</code> 和 <code>-</code>，现在可以把它们用在脚本中了。清单 5 演示了它们从播放列表添加和减少歌曲的行为：</p><br /><br /><a name="code5"><b>清单 5. 播放音乐</b></a><br /><table border="0" cellpadding="0" cellspacing="0" width="100%"><tbody><tr><td class="code-outline"><pre class="displaycode">sng1 = new Song("SpanishEyes.mp3")<br />sng2 = new Song("RaceWithDevilSpanishHighway.mp3")<br />sng3 = new Song("Nena.mp3")<br />jbox = new JukeBox()<br />jbox + sng1<br />jbox + sng2<br />jbox + sng3<br />jbox.printPlayList() //prints Spanish Eyes, Race with the Devil.., Nena<br />jbox - sng2<br />jbox.printPlayList() //prints Spanish Eyes, Nena<br /></pre></td></tr></tbody></table><br /><p><a name="N103AB"><span class="smalltitle">重载，重载的，重载器</span></a></p><p>继续进行这个<i>重载的</i> 主题，您可能注意到，在表 3 中有一个可以重载的算术类操作符 <code>&lt;&lt;</code>，它恰好也为 Groovy 的集合重载。在集合的情况下，<code>&lt;&lt;</code> 覆盖后的作用像普通的 Java <code>add()</code> 方法一样，把值添加到集合的尾部（这与 Ruby 也很相似）。在清单 6 中，可以看到当我模拟这个行为，允许 <code>JukeBox</code> 的用户通过 <code>&lt;&lt;</code> 操作符以及 <code>+</code> 操作符添加 <code>Song</code> 时发生的情况：</p><br /><br /><a name="code6"><b>清单 6. 左移音乐</b></a><br /><table border="0" cellpadding="0" cellspacing="0" width="100%"><tbody><tr><td class="code-outline"><pre class="displaycode">def leftShift(song){<br />   this.plus(song)<br />}<br /></pre></td></tr></tbody></table><br /><p>在清单 6 中，我实现了 <code>leftShift</code> 方法，它调用 <code>plus</code> 方法添加 <code>Song</code> 到播放列表。清单 7 显示了 <code>&lt;&lt;</code> 操作符的效果：</p><br /><br /><a name="code7"><b>清单 7. 比赛进行中</b></a><br /><table border="0" cellpadding="0" cellspacing="0" width="100%"><tbody><tr><td class="code-outline"><pre class="displaycode">jbox &lt;&lt; sng2 //re-adds Race with the Devil...<br /></pre></td></tr></tbody></table><br /><p>可以看出，Groovy 的算术类重载操作符不仅能<i>负重</i>，而且能做得很快！</p><br /><table border="0" cellpadding="0" cellspacing="0" width="100%"><tbody><tr><td><img src="http://www.ibm.com/i/v14/rules/blue_rule.gif" alt="" height="1" width="100%" /><br /><img alt="" src="http://www.ibm.com/i/c.gif" border="0" height="6" width="8" /></td></tr></tbody></table><table class="no-print" align="right" cellpadding="0" cellspacing="0"><tbody><tr align="right"><td><img src="http://www.ibm.com/i/c.gif" alt="" height="4" width="100%" /><br /><br /></td></tr></tbody></table><br /><br /><p><a name="N10402"><span class="atitle">数组类操作符</span></a></p><p>Groovy 支持重载标准的 Java 数组存取语法 <code>[]</code>，如表 4 所示：</p><br /><br /><a name="table4"><b>表 4. 数组操作符</b></a><br /><table class="data-table-1" summary="Table using a caption tag, alternating color rows" border="0" cellpadding="0" cellspacing="0" width="100%"><caption><em></em><br /></caption><tbody><tr><th>操作符</th><th>方法</th></tr><tr class="alt-row"><td class="tb-row">a[b]</td><td><code> a.getAt(b)</code></td></tr><tr><td class="tb-row"> a[b] = c </td><td><code> a.putAt(b, c) </code></td></tr></tbody></table><p>数组存取语法很好地映射到集合，所以我在清单 8 中更新了 <code>JukeBox</code> 类，把两种情况都做了重载：</p><br /><br /><a name="code8"><b>清单 8. Music 重载</b></a><br /><table border="0" cellpadding="0" cellspacing="0" width="100%"><tbody><tr><td class="code-outline"><pre class="displaycode">def getAt(position){    <br />  return songs[position]<br />}<br />def putAt(position, song){<br />  songs[position] = song<br />}<br /></pre></td></tr></tbody></table><br /><p>现在我实现了 <code>getAt</code> 和 <code>putAt</code>，我可以使用 <code>[]</code> 语法了，如清单 9 所示：</p><br /><br /><a name="code9"><b>清单 9. 还能比这更快么？</b></a><br /><table border="0" cellpadding="0" cellspacing="0" width="100%"><tbody><tr><td class="code-outline"><pre class="displaycode">println jbox[0] //prints Spanish Eyes<br />jbox[0] = sng2  //placed Race w/the Devil in first slot<br />println jbox[0] //prints Race w/the Devil<br /></pre></td></tr></tbody></table><br /><br /><table border="0" cellpadding="0" cellspacing="0" width="100%"><tbody><tr><td><img src="http://www.ibm.com/i/v14/rules/blue_rule.gif" alt="" height="1" width="100%" /><br /><img alt="" src="http://www.ibm.com/i/c.gif" border="0" height="6" width="8" /></td></tr></tbody></table><table class="no-print" align="right" cellpadding="0" cellspacing="0"><tbody><tr align="right"><td><img src="http://www.ibm.com/i/c.gif" alt="" height="4" width="100%" /><br /><br /></td></tr></tbody></table><br /><br /><p><a name="N10476"><span class="atitle">更 Groovy 化的 JDK 方法</span></a></p><p>一旦掌握了操作符重载的概念和它在 Groovy 中的实现，就可以看到许多日常的 Java 对象<i>已经</i> 被 Groovy 的作者做了改进。</p><p>例如，<code>Character</code> 类支持 <code>compareTo()</code>，如清单 10 所示：
</p><br /><br /><a name="code10"><b>清单 10. 比较字符</b></a><br /><table border="0" cellpadding="0" cellspacing="0" width="100%"><tbody><tr><td class="code-outline"><pre class="displaycode">def a = Character.valueOf('a' as char)<br />def b = Character.valueOf('b' as char)<br />def c = Character.valueOf('c' as char)<br />def g = Character.valueOf('g' as char)<br />println a &lt; b  //prints true<br />println g &lt; c  //prints false<br /></pre></td></tr></tbody></table><br /><p>同样，<code>StringBuffer</code> 可以用 <code>&lt;&lt;</code> 操作符进行添加，如清单 11 所示：
</p><br /><br /><a name="code11"><b>清单 11. 缓冲区中的字符串</b></a><br /><table border="0" cellpadding="0" cellspacing="0" width="100%"><tbody><tr><td class="code-outline"><pre class="displaycode">def strbuf = new StringBuffer()<br />strbuf.append("Error message: ")<br />strbuf &lt;&lt; "NullPointerException on line ..."<br />println strbuf.toString() //prints Error message: NullPointerException on line ...<br /></pre></td></tr></tbody></table><br /><p>最后，清单 12 表示 <code>Date</code> 可以通过 <code>+</code> 和 <code>-</code> 来操纵。</p><br /><br /><a name="code12"><b>清单 12. 是哪一天？</b></a><br /><table border="0" cellpadding="0" cellspacing="0" width="100%"><tbody><tr><td class="code-outline"><pre class="displaycode">def today = new Date()<br />println today   //prints Tue Oct 11 21:15:21 EDT 2005<br />println "tomorrow: " + (today + 1)  //Wed Oct 12 21:15:21 EDT 2005<br />println "yesterday: " + (today - 1) //Mon Oct 10 21:15:21 EDT 2005<br /></pre></td></tr></tbody></table><br /><br /><table border="0" cellpadding="0" cellspacing="0" width="100%"><tbody><tr><td><img src="http://www.ibm.com/i/v14/rules/blue_rule.gif" alt="" height="1" width="100%" /><br /><img alt="" src="http://www.ibm.com/i/c.gif" border="0" height="6" width="8" /></td></tr></tbody></table><table class="no-print" align="right" cellpadding="0" cellspacing="0"><tbody><tr align="right"><td><img src="http://www.ibm.com/i/c.gif" alt="" height="4" width="100%" /><br /><br /></td></tr></tbody></table><br /><br /><p><a name="N104C8"><span class="atitle">结束语</span></a></p><p>可
以看到，操作符的即时多态，或操作符重载，对于我们来说，如果小心使用和记录，会非常强大。但是，要当心不要滥用这个特性。如果决定覆盖一个操作符去做一
些非常规的事情，请一定要清楚地记录下您的工作。对 Groovy
类进行改进，支持重载非常简单。小心应对并记录所做的工作，对于由此而来的方便的简写形式来说，代价非常公道。</p><img src ="http://www.blogjava.net/JafeLee/aggbug/128680.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/JafeLee/" target="_blank">Jafe</a> 2007-07-06 21:16 <a href="http://www.blogjava.net/JafeLee/articles/128680.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>实战 Groovy: 关于 MOP 和迷你语言</title><link>http://www.blogjava.net/JafeLee/articles/128679.html</link><dc:creator>Jafe</dc:creator><author>Jafe</author><pubDate>Fri, 06 Jul 2007 13:15:00 GMT</pubDate><guid>http://www.blogjava.net/JafeLee/articles/128679.html</guid><wfw:comment>http://www.blogjava.net/JafeLee/comments/128679.html</wfw:comment><comments>http://www.blogjava.net/JafeLee/articles/128679.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/JafeLee/comments/commentRss/128679.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/JafeLee/services/trackbacks/128679.html</trackback:ping><description><![CDATA[
		<p>
				<a href="http://www.ibm.com/developerworks/cn/java/j-pg09205/#author">Andrew Glover</a>, CTO, Vanward Technologies<br /></p>
		<p>2005 年  10 月  17 日</p>
		<blockquote>将耳朵贴到地上仔细听 —— MOP 正在前进！了解一下元对象协议（Meta Object Protocol，MOP）吧，这是一种将应用程序、语言和应用程序构建<i>为</i> 语言的翻新方法。</blockquote>
		<!--START RESERVED FOR FUTURE USE INCLUDE FILES-->
		<!-- include java script once we verify teams wants to use this and it will work on dbcs and cyrillic characters -->
		<!--END RESERVED FOR FUTURE USE INCLUDE FILES-->
		<p>在最近的一次采访中，Groovy 项目经理 Guillaume Laforge 
提到，他最喜欢的 Groovy 特性是它实现了<i>元对象协议（Meta Object Protocol）</i> 或称 MOP。在运行时向一个对象传递方法，或者<i>消息</i> 时，这个协议使对象可以作出影响它自己的状态或者行为的特定选择。正如在 PARC Software Design Area 项目主页上所描述的（请参阅 <a href="http://www.ibm.com/developerworks/cn/java/j-pg09205/#resources">参考资料</a>）：</p>
		<blockquote>元对象协议方法……基于这样一种想法，即人们可以并且应当使语言开放，使用户可以根据他们的特定需要调整设计和实现。换句话说，鼓励用户参与语言设计过程。</blockquote>
		<p>显然，这种大胆的思路提出了构建更智能的应用程序、甚至<i>语言</i> 的令人激动的可能性。在本月的专栏中，我将展示 Groovy 是如何实现 MOP 的，然后用一个实际的例子介绍它最令人激动的实际应用：作为一种迷你语言的字典！</p>
		<p>在 <a href="http://www.ibm.com/developerworks/cn/java/j-pg09205/#download">下载</a> 一节中提供了字典应用程序示例的源代码。下面的例子中需要下载 DbUnit，请参阅 <a href="http://www.ibm.com/developerworks/cn/java/j-pg09205/#resources">参考资料</a>。</p>
		<table align="right" border="0" cellpadding="0" cellspacing="0" width="40%">
				<tbody>
						<tr>
								<td width="10">
										<img alt="" src="http://www.ibm.com/i/c.gif" height="1" width="10" />
								</td>
								<td>
										<br />
								</td>
						</tr>
				</tbody>
		</table>
		<p>
				<a name="N10098">
						<span class="atitle">魔术般的 MOP</span>
				</a>
		</p>
		<p>元对象协议不是 Groovy 独有的，它也不是由 Groovy 发明者发明的。事实上，它的身世可追溯到 LISP 和 AOP 背后的一些人。考虑到这种身世，MOP 受到 Groovy 的见多识广的创造者们的欢迎就毫不奇怪了。 </p>
		<p>在 Groovy 中可以实现 MOP 是因为，在 <i>Groovyland</i> 中每一个对象都隐式地实现 <code>groovy.lang.GroovyObject</code>，它定义了 <code>invokeMethod()</code> 和 <code>getProperty()</code> 两个方法。在运行时，如果向一个对象传递消息，而这个对象不是作为类或者其子类中定义的属性或者方法存在，那么就调用 <code>getProperty()</code> 或者 <code>invokeMethod()</code> 方法。 </p>
		<p>在清单 1 中，我定义了 Groovy 类 <code>MOPHandler</code>，它实现了 <code>invokeMethod()</code> 和 <code>getProperty()</code>。当创建了 <code>MOPHandler</code> 的一个实例后，可以调用任意数量的方法或者属性，并看到它打印出说明调用了什么的消息。</p>
		<br />
		<br />
		<a name="code1">
				<b>清单 1. MOP 得到调用的句柄</b>
		</a>
		<br />
		<table border="0" cellpadding="0" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td class="code-outline">
										<pre class="displaycode">class MOPHandler {	<br /><br />  def invokeMethod(String method, Object params) { 	<br />    println "MOPHandler was asked to invoke ${method}"<br />    if(params != null){<br />	 params.each{ println "\twith parameter ${it}" }<br />    }<br />  }<br /><br />  def getProperty(String property){<br />     println "MOPHandler was asked for property ${property}"<br />  }  <br />}<br />def hndler = new MOPHandler()<br />hndler.helloWorld()<br />hndler.createUser("Joe", 18, new Date())<br />hndler.name<br /></pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>继续，运行清单 1 中的代码，就会看到如清单 2 所示的输出。</p>
		<br />
		<br />
		<a name="code2">
				<b>清单 2. 您不相信我，是不是？</b>
		</a>
		<br />
		<table border="0" cellpadding="0" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td class="code-outline">
										<pre class="displaycode">aglover@glove-ubutu:~/projects/groovy-mop$ groovy <br />  ./src/groovy/com/vanward/groovy/MOPHandler1.groovy<br />MOPHandler was asked to invoke helloWorld<br />MOPHandler was asked to invoke createUser<br />        with parameter Joe<br />        with parameter 18<br />        with parameter Sun Sep 04 10:32:22 EDT 2005<br />MOPHandler was asked for property name<br /></pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>是不是很不错？MOP 就像一个安全网，捕捉传递错误的消息，但是这不是它最妙的功能。用它创建可以以<i>一般的方式</i> 智能地对传递进来的任何消息作出响应的智能对象，才是它的最大亮点。</p>
		<br />
		<table border="0" cellpadding="0" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td>
										<img src="http://www.ibm.com/i/v14/rules/blue_rule.gif" alt="" height="1" width="100%" />
										<br />
										<img alt="" src="http://www.ibm.com/i/c.gif" border="0" height="6" width="8" />
								</td>
						</tr>
				</tbody>
		</table>
		<table class="no-print" align="right" cellpadding="0" cellspacing="0">
				<tbody>
						<tr align="right">
								<td>
										<img src="http://www.ibm.com/i/c.gif" alt="" height="4" width="100%" />
										<br />
										<br />
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<br />
		<p>
				<a name="N100EE">
						<span class="atitle">让我成为一种迷你语言</span>
				</a>
		</p>
		<p>用 MOP 可以做的一件有趣的事情是创建伪领域专用语言，或者称为<i>迷你语言</i>。这些是专门用于解决特定问题的独特语言。与像 Java、C# 或者甚至 Groovy 这样的流行语言不同，它们被看成是用来解决任何问题的一般性语言，而迷你语言只针对特定问题。需要一个例子？请考虑 Unix 及其 shell，如 Bash。</p>
		<p>只是为了练习 —— 并且这样可以真正<i>感受</i> MOP —— 我将在本文的其余部分创建一个字典应用程序，它本身实际就是一个迷你语言。这个应用程序将提供一个查询字典的界面。它让用户可以创建新的单词项、得到给定单词的定义、得到给定单词的同义字、查询单词的词性以及删除单词。表 1 总结了这个迷你语言。</p>
		<br />
		<br />
		<a name="N10101">
				<b>表 1. 字典迷你语言的语义</b>
		</a>
		<br />
		<table class="data-table-1" summary="Table using a caption tag, alternating color rows" border="0" cellpadding="0" cellspacing="0" width="100%">
				<caption>
         这个字典应用程序语言有以下语义（按从最特殊到最一般排列）：
        </caption>
				<tbody>
						<tr>
								<td class="tb-row">1. 词性</td>
								<td>要查询单词的词性，消息应该以 <code>is</code> 打头，后跟这个单词，然后是 <code>a</code> 或者 <code>an</code>，然后是词性。</td>
						</tr>
						<tr class="alt-row">
								<td class="tb-row">2. 同义词</td>
								<td>要查询一个单词的同义词，消息应该以 <code>synonymsOf</code> 打头，然后是这个单词。</td>
						</tr>
						<tr>
								<td class="tb-row">3. 删除单词</td>
								<td>要从字典中删除一个单词，消息应该以 <code>remove</code> 或 <code>delete</code> 打头，然后是这个单词。</td>
						</tr>
						<tr class="alt-row">
								<td class="tb-row">4. 创建单词</td>
								<td>要在字典中创建一个新单词，可将单词作为方法，并将其定义、词性和可选的一组同义词作为参数传递。</td>
						</tr>
						<tr>
								<td class="tb-row">5. 获取定义</td>
								<td>要查询一个单词的定义，可将这个单词作为属性或者方法传递。</td>
						</tr>
				</tbody>
		</table>
		<br />
		<table border="0" cellpadding="0" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td>
										<img src="http://www.ibm.com/i/v14/rules/blue_rule.gif" alt="" height="1" width="100%" />
										<br />
										<img alt="" src="http://www.ibm.com/i/c.gif" border="0" height="6" width="8" />
								</td>
						</tr>
				</tbody>
		</table>
		<table class="no-print" align="right" cellpadding="0" cellspacing="0">
				<tbody>
						<tr align="right">
								<td>
										<img src="http://www.ibm.com/i/c.gif" alt="" height="4" width="100%" />
										<br />
										<br />
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<br />
		<p>
				<a name="N10160">
						<span class="atitle">字典应用程序</span>
				</a>
		</p>
		<p>字典应用程序基于表结构如图 1 所示的数据库。如果您经常读我们的文章，那么您可能会看出这个表结构源自专栏文章“<a href="http://www.ibm.com/developerworks/cn/java/j-pg04125/">Mark it up with Groovy Builders</a>”。</p>
		<br />
		<br />
		<a name="N10170">
				<b>图 1. 字典的简单数据库模型</b>
		</a>
		<br />
		<img alt="" src="http://www.ibm.com/developerworks/cn/java/j-pg09205/words-db.jpg" border="0" height="191" width="463" />
		<br />
		<p>
				<i>注意：我将忽略 <code>definition</code> 的 <code>EXAMPLE_SENTENCE</code> 这一列。</i>
		</p>
		<p>我将创建一个简单的 facade，它将作为用户与数据库之间的接口。这个 facade 将通过提供 <code>invokeMethod</code> 和 <code>getProperty</code> 的实现来利用 Groovy 的 MOP 特性。<code>invokeMethod</code> 方法将确定命令并将责任委派给相应的内部 <code>private</code> 方法。 </p>
		<p>
				<a name="N101A0">
						<span class="smalltitle">一些前提条件</span>
				</a>
		</p>
		<p>因为这个应用程序依赖于数据库，在继续之前，可能需要复习一下 <a href="http://www.ibm.com/developerworks/cn/java/j-pg01115.html">
GroovySql</a>。我还会使用 Groovy 的正则表达式（在 <a href="http://www.ibm.com/developerworks/cn/java/j-alj08034/">
感受 Groovy</a> 中介绍）来确定传递给 facade 的消息。</p>
		<p>我会在写这个 facade 时，<i>用</i> Groovy 测试它，因此需要回顾 Groovy 的单元测试能力，请参阅我的“<a href="http://www.ibm.com/developerworks/cn/java/j-pg11094/?ca=dwcn-newsletter-java">Unit
test your Java code faster with Groovy</a>”。</p>
		<p>最后，在测试过程中，我将用 DbUnit 管理数据库状态。因为在本系列中没有写过 DbUnit 的内容，我将在继续之前简单介绍在 Groovy 中使用 DbUnit。</p>
		<br />
		<table border="0" cellpadding="0" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td>
										<img src="http://www.ibm.com/i/v14/rules/blue_rule.gif" alt="" height="1" width="100%" />
										<br />
										<img alt="" src="http://www.ibm.com/i/c.gif" border="0" height="6" width="8" />
								</td>
						</tr>
				</tbody>
		</table>
		<table class="no-print" align="right" cellpadding="0" cellspacing="0">
				<tbody>
						<tr align="right">
								<td>
										<img src="http://www.ibm.com/i/c.gif" alt="" height="4" width="100%" />
										<br />
										<br />
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<br />
		<p>
				<a name="N101BF">
						<span class="atitle">DbUnit，结合 Groovy</span>
				</a>
		</p>
		<p>DbUnit
是一项 JUnit 扩展，它在每一次运行测试之前，使数据库处于一种已知状态。在 Groovy 中使用 DbUnit 非常简单，因为
DbUnit 提供了一个 API，可以在测试用例中进行委派。为了使用
DbUnit，需要向它提供一个数据库连接和一个包含作为数据库种子的文件。将它们插入到 JUnit 的 fixture 机制中（即 <code>setUp()</code>）后，就可以继续了！
清单 3 显示了字典应用程序的开始测试类。</p>
		<br />
		<br />
		<a name="code3">
				<b>清单 3. 字典应用程序的开始测试类</b>
		</a>
		<br />
		<table border="0" cellpadding="0" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td class="code-outline">
										<pre class="displaycode">package test.com.vanward.groovy<br />import com.vanward.groovy.SimpleDictionary<br />import groovy.util.GroovyTestCase<br />import java.io.File<br />import java.sql.Connection<br />import java.sql.DriverManager<br />import org.dbunit.database.DatabaseConnection<br />import org.dbunit.database.IDatabaseConnection<br />import org.dbunit.dataset.IDataSet<br />import org.dbunit.dataset.xml.FlatXmlDataSet<br />import org.dbunit.operation.DatabaseOperation<br />class DictionaryTest extends GroovyTestCase{  <br />   def dictionary<br /><br />   void setUp() {        <br />      this.handleSetUpOperation()  <br />      dictionary = new SimpleDictionary()    <br />   } <br /><br />   def handleSetUpOperation() {<br />      def conn = this.getConnection()<br />      def data = this.getDataSet()       <br />      try{<br />          DatabaseOperation.CLEAN_INSERT.execute(conn, data)<br />      }finally{<br />          conn.close()<br />      }<br />    }<br /><br />    def getDataSet()  {<br />      return new FlatXmlDataSet(new File("test/conf/words-seed.xml"))<br />    }<br /><br />    def getConnection()  {<br />       Class.forName("org.gjt.mm.mysql.Driver")<br />       def jdbcConnection = DriverManager.<br />        	getConnection("jdbc:mysql://localhost/words", <br />       	         "words", "words")             <br />       return new DatabaseConnection(jdbcConnection)<br />    }  <br />}<br /></pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>在清单 3 中，我创建了类 shell，它作为在编写字典应用程序时的测试类。调用测试时，JUnit 会调用 <code>setUp()</code>，它又会调用 DbUnit 的 API。DbUnit 会将在文件 test/conf/words-seed.xml 中找到的数据插入到数据库中。文件 test/conf/words-seed.xml 的内容可见清单 4。</p>
		<br />
		<br />
		<a name="code4">
				<b>清单 4. 示例种子文件</b>
		</a>
		<br />
		<table border="0" cellpadding="0" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td class="code-outline">
										<pre class="displaycode">&lt;?xml version='1.0' encoding='UTF-8'?&gt;<br />&lt;dataset&gt;<br /> &lt;word WORD_ID="1" SPELLING="pugnacious" PART_OF_SPEECH="Adjective"/&gt;   <br /> &lt;definition DEFINITION_ID="10" <br />             DEFINITION="Combative in nature; belligerent." <br />             WORD_ID="1" /&gt;<br /> &lt;synonym SYNONYM_ID="20" WORD_ID="1" SPELLING="belligerent"/&gt;<br /> &lt;synonym SYNONYM_ID="21" WORD_ID="1" SPELLING="aggressive"/&gt;  <br /> &lt;word WORD_ID="2" SPELLING="glib" PART_OF_SPEECH="Adjective"/&gt;<br /> &lt;definition DEFINITION_ID="11" <br />     	       DEFINITION="Performed with a natural, offhand ease" <br />             WORD_ID="2" /&gt;             <br /> &lt;definition DEFINITION_ID="12" <br />  	      DEFINITION="Marked by ease and fluency of speech or <br />  	      writing that often suggests or stems from insincerity, <br />  	      superficiality, or deceitfulness" <br />         WORD_ID="2" /&gt;              <br /> &lt;synonym SYNONYM_ID="30" WORD_ID="2" SPELLING="artful"/&gt;<br /> &lt;synonym SYNONYM_ID="31" WORD_ID="2" SPELLING="suave"/&gt;  <br /> &lt;synonym SYNONYM_ID="32" WORD_ID="2" SPELLING="insincere"/&gt;  <br /> &lt;synonym SYNONYM_ID="33" WORD_ID="2" SPELLING="urbane"/&gt;  <br /><br /> &lt;word WORD_ID="3" SPELLING="rowel" PART_OF_SPEECH="Verb"/&gt;  <br /> &lt;definition DEFINITION_ID="50" <br />             DEFINITION="to vec, trouble" <br />             WORD_ID="13" /&gt;<br />&lt;/dataset&gt;<br /></pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>种子文件的 XML 元素（如清单 4 所示）匹配表名。元素的属性匹配对应的表列。</p>
		<br />
		<table border="0" cellpadding="0" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td>
										<img src="http://www.ibm.com/i/v14/rules/blue_rule.gif" alt="" height="1" width="100%" />
										<br />
										<img alt="" src="http://www.ibm.com/i/c.gif" border="0" height="6" width="8" />
								</td>
						</tr>
				</tbody>
		</table>
		<table class="no-print" align="right" cellpadding="0" cellspacing="0">
				<tbody>
						<tr align="right">
								<td>
										<img src="http://www.ibm.com/i/c.gif" alt="" height="4" width="100%" />
										<br />
										<br />
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<br />
		<p>
				<a name="N101ED">
						<span class="atitle">构建一种迷你语言</span>
				</a>
		</p>
		<p>定义了测试类后，就可以开始开发（并测试）这个应用程序了。我将按 <a href="http://www.ibm.com/developerworks/cn/java/j-pg09205/#table1">表 1</a> 的排列顺序处理每一项特性。</p>
		<table align="right" border="0" cellpadding="0" cellspacing="0" width="40%">
				<tbody>
						<tr>
								<td width="10">
										<img alt="" src="http://www.ibm.com/i/c.gif" height="1" width="10" />
								</td>
								<td>
										<table border="1" cellpadding="5" cellspacing="0" width="100%">
												<tbody>
														<tr>
																<td bgcolor="#eeeeee">
																		<a name="N101FD">
																				<b>正则表达式组</b>
																		</a>
																		<br />
																		<p>正则表达式组在字典例子中起了主要作用。在 Groovy 中，可以通过 <code>=~</code> 语法创建一个普通 Java <code>Matcher</code> 实例。可以用 <code>Matcher</code> 实例，通过调用 <code>group()</code> 方法获得 <code>String</code> 代码段。使用括号在一个正则表达式中创建组。例如，正则表达式 <code>(synonymsOf)(.*)</code> 创建两个组。一个组完全匹配 <code>String</code><i>"synonymsOf"</i>，而另一个匹配 <i>"synonymsOf"</i> 后面的<i>任何</i> 字符。不过要记住，在要获得组值之前，首先必须调用 <code>Matcher</code> 的 <code>matches()</code> 方法。</p>
																</td>
														</tr>
												</tbody>
										</table>
								</td>
						</tr>
				</tbody>
		</table>
		<p>
				<a name="N10234">
						<span class="smalltitle">1. 词性</span>
				</a>
		</p>
		<p>如果用户想要查询一个单词的词性，他或者她可以在消息中传递像 <code>isRowelAVerb</code> 或者 <code>isEstivalAnAdjective</code> 这样的内容。（注意，我使用了 camel-case 语义，并通过同时允许 <code>a</code> 和 <code>an</code> 以尽量符合正规的英语。）回答问题的智能逻辑就变成了确定正确的单词，在第一种情况下它是 <i>Rowel</i>，而在第二种情况下是 <i>Estival</i>。还必须确定词性，在本例中分别为 <i>Verb</i> 和 <i>Adjective</i>。</p>
		<p>使用正则表达式，逻辑就变得简单了。模式成为 <code>is(.*)(An|A)(Verb|Adjective|Adverb|Noun)</code>。我只对第一和第三组感兴趣（单词和词性）。有了这些，就可以编写一个简单的数据库查询，以获取词性并比较问题和答案，如清单 5 所示。 </p>
		<br />
		<br />
		<a name="code5">
				<b>清单 5. 确定词性</b>
		</a>
		<br />
		<table border="0" cellpadding="0" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td class="code-outline">
										<pre class="displaycode">private determinePartOfSpeech(question){<br />  def matcher = question =~ 'is(.*)(An|A)(Verb|Adjective|Adverb|Noun)'<br />  matcher.matches()<br />  def word = matcher.group(1)<br />  def partOfSpeech = matcher.group(3)<br />  def row = sql.firstRow("select part_of_speech from word <br />  	where spelling=?", [word])	<br />  return row[0] == partOfSpeech<br />}<br /></pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>清单 5 看起来很简单，但是我为它编写了几个测试用例，看看会是什么情况。</p>
		<br />
		<br />
		<a name="code6">
				<b>清单 6. 测试单词词性的确定</b>
		</a>
		<br />
		<table border="0" cellpadding="0" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td class="code-outline">
										<pre class="displaycode">void testPartOfSpeechFalse() {<br />  def val = dictionary.isPugnaciousAVerb()<br />  assertFalse("pugnacious is not a verb", val)<br />}	<br />void testPartOfSpeechTrue() {<br />  def val = dictionary.isPugnaciousAnAdjective()<br />  assertTrue("pugnacious is an Adjective", val)<br />}<br /></pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>再看看清单 4 中的 XML。因为我用 DbUnit 让数据库在每次测试之前处于一种已知状态，因此可以假定单词 <i>pugnacious</i> 是有效的，且其词性设置为 <i>Adjective</i>。在清单 6 中，我在 <code>DictionaryTest</code> 中加入了两个简单的测试（请参阅 <a href="http://www.ibm.com/developerworks/cn/java/j-pg09205/#code3">清单 3</a>），以确保逻辑正确地工作。</p>
		<p>
				<a name="N1028B">
						<span class="smalltitle">2. 同义词</span>
				</a>
		</p>
		<p>查询同义词的语义模式如下：<code>synonymsOfBloviate</code>，其中所要查的单词（<i>Bloviate</i>）跟在 <code>synonymsOf</code> 后面。正则表达式更简单：<code>(synonymsOf)(.*)</code>。找到所需要的单词后，逻辑就进行一个数据库查询，该查询会连接 <code>word</code> 和 <code>synonym</code> 表。返回的同义词加入到一个 <code>List</code> 中并返回，如清单 7 所示。</p>
		<br />
		<br />
		<a name="code7">
				<b>清单 7. getSynonyms 实现</b>
		</a>
		<br />
		<table border="0" cellpadding="0" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td class="code-outline">
										<pre class="displaycode">private getSynonyms(question){<br />  def matcher = question =~ '(synonymsOf)(.*)'<br />  matcher.matches()<br />  def word = matcher.group(2).toLowerCase()<br />  def syns = []	<br />  sql.eachRow("select synonym.spelling from synonym, word " +<br />      "where synonym.word_id = word.word_id and " +<br />      "word.spelling = ?", [word]){ arow -&gt;<br />          syns &lt;&lt; arow.spelling<br />       }	   <br />  return syns		<br />}<br /></pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>清单 8 中的测试验证了，定义了同义词的单词可以正确地返回同义词，而没有同义词的单词（<i>Rowel</i>）返回一个空 <code>List</code>。</p>
		<br />
		<br />
		<a name="code8">
				<b>清单 8. 不要忘记测试这个方法！ </b>
		</a>
		<br />
		<table border="0" cellpadding="0" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td class="code-outline">
										<pre class="displaycode">void testSynonymsForWord() {<br />  def val = dictionary.synonymsOfPugnacious()<br />  def expect = ["belligerent","aggressive"]<br />  assertEquals("should be: " + expect, expect, val)<br />}<br />void testNoSynonymsForWord() {<br />  def val = dictionary.synonymsOfRowel()<br />  def expect = []<br />  assertEquals("should be: " + expect, expect, val)<br />}<br /></pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>
				<a name="N102D0">
						<span class="smalltitle">3. 删除单词</span>
				</a>
		</p>
		<p>清单 9 中的删除逻辑是灵活的，因为我允许使用 <code>remove</code> 或者 <code>delete</code> 后面加单词的命令。例如，<code>removeGlib</code> 和 <code>deleteGlib</code> 都是有效的命令。因此正则表达式变成：<code>(remove|delete)(.*)</code>，而逻辑是一个 SQL <code>delete</code>。</p>
		<br />
		<br />
		<a name="code9">
				<b>清单 9. 删除单词</b>
		</a>
		<br />
		<table border="0" cellpadding="0" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td class="code-outline">
										<pre class="displaycode">private removeWord(word){<br />  def matcher = word =~ '(remove|delete)(.*)'<br />  matcher.matches()<br />  def wordToRemove = matcher.group(2).toLowerCase()	<br />  sql.execute("delete from word where spelling=?" , [wordToRemove])	<br />}<br /></pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>当然，这种灵活意味着我必须为删除单词编写<i>至少</i> 两个测试用例，如清单 10 所示。要验证单词真的被删除了，我要获取它们的定义（更多信息请参阅 <a href="http://www.ibm.com/developerworks/cn/java/j-pg09205/#retrieve">5. 获取单词的定义</a>）并确定没有返回任何东西。</p>
		<br />
		<br />
		<a name="code10">
				<b>清单 10. 测试这两种情况</b>
		</a>
		<br />
		<table border="0" cellpadding="0" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td class="code-outline">
										<pre class="displaycode">void testDeleteWord() {<br />  dictionary.deleteGlib()<br />  def val =  dictionary.glib()<br />  def expect = []<br />  assertEquals("should be: " + expect, expect, val)<br />}<br />void testRemoveWord() {<br />  dictionary.removePugnacious()<br />  def val =  dictionary.pugnacious()<br />  def expect = []<br />  assertEquals("should be: " + expect, expect, val)<br />}<br /></pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>
				<a name="N10312">
						<span class="smalltitle">4. 创建单词</span>
				</a>
		</p>
		<p>创建一个新单词的语义是一个不匹配任何查询模式并且包含一个参数清单的消息。例如，一个像 <code>echelon("Noun", ["a level within an organization"])</code> 这样的消息就符合这种模式。单词是 <i>echelon</i>，第一个参数是词性，然后是包含定义的 <code>List</code>，还有可选的第三个参数，它可以是同义词的 <code>List</code>。</p>
		<p>如清单 11 所示，在数据库中创建一个新单词就是在正确的表（<code>word</code> 和 <code>definition</code>）中插入这个单词及其定义，而且，如果有同义词 <code>List</code> 的话，那么要把它们都要加入。 </p>
		<br />
		<br />
		<a name="code11">
				<b>清单 11. 创建一个单词</b>
		</a>
		<br />
		<table border="0" cellpadding="0" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td class="code-outline">
										<pre class="displaycode">private createWord(word, defsAndSyms){<br />  def wordId = id++<br />  def definitionId = wordId + 10<br />  sql.execute("insert into word <br />  	(word_id, part_of_speech, spelling) values (?, ?, ?)" , <br />    [wordId, defsAndSyms[0], word])<br />  for(definition in defsAndSyms[1]){	<br />    sql.execute("insert into definition <br />    	(definition_id, definition, word_id) " +<br />      "values (?, ?, ?)" , [definitionId, definition, wordId])<br />    }<br />  //has a list of synonyms has been passed in<br />  if(defsAndSyms.length &gt; 2){<br />    def synonyms = defsAndSyms[2]<br />    synonyms.each{ syn -&gt;<br />      sql.execute("insert into synonym <br />      	(synonym_id, word_id, spelling) values (?, ?, ?)" , <br />        [id++, wordId, syn])<br />      }<br />    }<br />}<br /></pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>在清单 11 中，主键逻辑过于简单了，不过我可以用几个测试证明我的信心。</p>
		<br />
		<br />
		<a name="code12">
				<b>清单 12. 创建单词逻辑的测试用例</b>
		</a>
		<br />
		<table border="0" cellpadding="0" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td class="code-outline">
										<pre class="displaycode">void testCreateWord() {	<br />  dictionary.bloviate("Verb", <br />  	["To discourse at length in a pompous or boastful manner"], <br />    ["orate", "gabble", "lecture"])<br />  def val = dictionary.bloviate()<br />  def expect = "To discourse at length in a pompous or boastful manner"<br />  assertEquals("should be: " + expect, expect, val[0])<br />}<br />void testCreateWordNoSynonyms() {	<br />  dictionary.echelon("Noun", ["a level within an organization"])<br />  def val = dictionary.echelon()<br />  def expect = "a level within an organization"<br />  assertEquals("should be: " + expect, expect, val[0])<br />}<br /></pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>与通常一样，我在清单 12 中编写了几个测试用例以验证它按预想的那样工作。创建单词后，我查询这个单词的 <code>dictionary</code> 实例以确认它被加入了数据库。</p>
		<p>
				<a name="retrieve">
						<span class="smalltitle">5. 获取单词的定义</span>
				</a>
		</p>
		<p>任何传递给字典应用程序的、不匹配前面任何查询类型（词性和同义词）、并且不包含任何参数的消息都被认为是定义查询。例如，一个像 <code>.glib</code> 或者 <code>.glib()</code> 的消息会返回 <i>glib</i> 的定义。</p>
		<br />
		<br />
		<a name="N1036F">
				<b>清单 13. 查单词的定义并不困难！ </b>
		</a>
		<br />
		<table border="0" cellpadding="0" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td class="code-outline">
										<pre class="displaycode">private getDefinitions(word){	<br />  def definitions = []			   	  <br />  sql.eachRow("select definition.definition from definition, word " +<br />    "where definition.word_Id = word.word_id and " +<br />    "word.spelling = ?", [word]){ arow -&gt;<br />      definitions &lt;&lt; arow.definition<br />    }	   <br />  return definitions	<br />}<br /></pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>因为我同时允许让方法调用和属性调用作为定义查询，因此在清单 14 中必须编写至少两个测试。就像在清单 6 中一样，可以假定 <i>pugnacious</i> 已经在数据库中了。DbUnit 是不是很方便？</p>
		<br />
		<br />
		<a name="code14">
				<b>清单 14. 测试两种情况 —— 方法调用和属性</b>
		</a>
		<br />
		<table border="0" cellpadding="0" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td class="code-outline">
										<pre class="displaycode">void testFindWord() {<br />  def val = dictionary.pugnacious()<br />  def expect = "Combative in nature; belligerent."<br />  assertEquals("should be: " + expect, expect, val[0])<br />}<br />void testFindWordAsProperty() {<br />  def val = dictionary.pugnacious<br />  def expect = "Combative in nature; belligerent."<br />  assertEquals("should be: " + expect, expect, val[0])<br />}<br /></pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>这就是字典应用程序的语义。现在让我们更深入地分析应用程序背后的逻辑。</p>
		<br />
		<table border="0" cellpadding="0" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td>
										<img src="http://www.ibm.com/i/v14/rules/blue_rule.gif" alt="" height="1" width="100%" />
										<br />
										<img alt="" src="http://www.ibm.com/i/c.gif" border="0" height="6" width="8" />
								</td>
						</tr>
				</tbody>
		</table>
		<table class="no-print" align="right" cellpadding="0" cellspacing="0">
				<tbody>
						<tr align="right">
								<td>
										<img src="http://www.ibm.com/i/c.gif" alt="" height="4" width="100%" />
										<br />
										<br />
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<br />
		<p>
				<a name="N1038E">
						<span class="atitle">MOP 逻辑</span>
				</a>
		</p>
		<p>字典应用程序的关键是 <code>invokeMethod</code> 和 <code>getProperty</code> 的实现。
我要在这些方法中做出智能的决定，即在向应用程序传递消息之后，应该如何继续。决定是通过一组条件语句而确定的，它们进行 <code>String</code> 操作以确定消息的类型。 </p>
		<p>清单 15 中<i>惟一</i> 麻烦的条件就是第一条，它要验证消息是一个定义查询而不是其他可能的组合，如 <code>is...</code>、<code>remove...</code>、<code>delete...</code> 或者 <code>synonymOf...</code>。</p>
		<br />
		<br />
		<a name="code15">
				<b>清单 15. MOP 的核心逻辑</b>
		</a>
		<br />
		<table border="0" cellpadding="0" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td class="code-outline">
										<pre class="displaycode">def invokeMethod(String methodName, Object params) { 	<br />  if(isGetDefinitions(methodName, params)){<br />    return getDefinitions(methodName)<br />  }else if (params.length &gt; 0){	 <br />    createWord(methodName, params)<br />  }else if(methodName[0..1] == 'is'){<br />    return determinePartOfSpeech(methodName)<br />  }else if<br />  (methodName[0..5] == 'remove' || methodName[0..5] == 'delete'){	<br />  	 removeWord(methodName)<br />  }else if (methodName[0..9] == 'synonymsOf'){<br />    return getSynonyms(methodName)<br />  }<br />}<br /><br />private isGetDefinitions(methodName, params){<br />  return !(params.length &gt; 0) &amp;&amp; <br />    ( (methodName.length() &lt;= 5 <br />    &amp;&amp; methodName[0..1] != 'is' ) || <br />    (methodName.length() &lt;= 10 <br />    &amp;&amp; isRemoveDeleteIs(methodName) ) || <br />    (methodName.length() &gt;= 10 <br />    &amp;&amp; methodName[0..9] != 'synonymsOf' <br />    &amp;&amp; isRemoveDeleteIs(methodName)))	<br />}<br /><br />private isRemoveDeleteIs(methodName){<br />	return (methodName[0..5] != 'remove' <br />      &amp;&amp; methodName[0..5] != 'delete' <br />      &amp;&amp; methodName[0..1] != 'is')<br />  }<br /></pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>
				<code>isGetDefinitions</code> 方法做了很多工作，其中一些工作依赖于 <code>isRemoveDeleteIs</code>。当它确定一个消息不符合定义查询时，逻辑就变得简单多了。</p>
		<p>清单 16 中的 <code>getProperty</code> 方法很简单，因为我规定用户只能按属性查询定义，因此，调用 <code>getProperty</code> 时，我调用 <code>getDefinitions</code> 方法。 </p>
		<br />
		<br />
		<a name="code16">
				<b>清单 16. 太好了，属性很简单！</b>
		</a>
		<br />
		<table border="0" cellpadding="0" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td class="code-outline">
										<pre class="displaycode">def getProperty(String property){<br />  return getDefinitions(property)<br />}<br /></pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>就是这样了！真的。清单 5 到 16
中的逻辑创建了一个应用程序，它给予用户相当的灵活性，同时又不会太复杂。当然，如前所述，应用程序中的主键逻辑并不是很保险。在这方面有多种改进方法，
从数据库序列到像 Hibernate 这样的框架都可以，Hibernate 框架用于相当得体地处理 ID。</p>
		<p>眼见为实，清单 17 展示了字典应用程序的语言的实际能力。（如果在使用 SAT 之前有这样的东西该多好！）</p>
		<br />
		<br />
		<a name="code17">
				<b>清单 17. 字典展示</b>
		</a>
		<br />
		<table border="0" cellpadding="0" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td class="code-outline">
										<pre class="displaycode">import com.vanward.groovy.SimpleDictionary<br />def dict = new SimpleDictionary()  <br />dict.vanward("Adjective", ["Being on, or towards the front"], <br />	["Advanced"])<br />dict.pulchritude("Noun", ["Great physical beauty and appeal"])<br />dict.vanward             //prints "Being on, or towards the front"<br />dict.pulchritude()       //prints "Great physical beauty and appeal"<br />dict.synonymsOfVanward() //prints "Advanced"<br />dict.isVanwardANoun()    //prints "false"<br />dict.removeVanward()<br />dict.deletePulchritude()<br /></pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<br />
		<table border="0" cellpadding="0" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td>
										<img src="http://www.ibm.com/i/v14/rules/blue_rule.gif" alt="" height="1" width="100%" />
										<br />
										<img alt="" src="http://www.ibm.com/i/c.gif" border="0" height="6" width="8" />
								</td>
						</tr>
				</tbody>
		</table>
		<table class="no-print" align="right" cellpadding="0" cellspacing="0">
				<tbody>
						<tr align="right">
								<td>
										<img src="http://www.ibm.com/i/c.gif" alt="" height="4" width="100%" />
										<br />
										<br />
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<br />
		<p>
				<a name="N103FB">
						<span class="atitle">MOP 的好处</span>
				</a>
		</p>
		<p>现在，您可能会问 <i>有什么好处？</i> 我本可以轻易地公开这些 <code>private</code> 方法，重新安排几项内容，就可以给出一个正常工作的应用程序（即，可以公开 <code>getDefinition</code> 方法、<code>createWord</code> 方法等），而无需使用 MOC。 </p>
		<p>让我们分析这种提议 —— 假定我要不使用 Goovy 的 MOC 实现来创建完全相同的字典应用程序。我需要重新定义 <code>createWord()</code> 方法的参数清单，使它变成类似  <code>def createWord(word, partOfSpeech, defs, syns=[]){}</code> 的样子。
</p>
		<p>可以看出，第一步是去掉 <code>private</code> 修饰符，用 <code>def</code> 替换它，这与将方法声明为 <code>public</code> 是一样的。然后，要定义参数，并让最后一个参数为可选的（<code>syns=[]</code>）。 </p>
		<p>还要定义一个 <code>delete</code> 方法，它至少要调用 <code>remove</code> 方法以同时支持 remove 和 delete。词性查询也应该修改。可以加入另一个参数，这样它看起来像 <code>determinePartOfSpeech(word, partOfSpeech)</code> 这样。</p>
		<p>实际上，经过以上步骤，字典应用程序的概念复杂性就从 MOP 实现转移到了静态 API 上了。这就带来了这个问题 —— <i>这样做</i> 的好处是什么？当然您可以看出由于实现 MOP，我为应用程序的使用者提供了无可比拟的灵活性。得到的 API 是一组静态定义的方法，灵活完全比不上<i>语言</i> 本身！</p>
		<br />
		<table border="0" cellpadding="0" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td>
										<img src="http://www.ibm.com/i/v14/rules/blue_rule.gif" alt="" height="1" width="100%" />
										<br />
										<img alt="" src="http://www.ibm.com/i/c.gif" border="0" height="6" width="8" />
								</td>
						</tr>
				</tbody>
		</table>
		<table class="no-print" align="right" cellpadding="0" cellspacing="0">
				<tbody>
						<tr align="right">
								<td>
										<img src="http://www.ibm.com/i/c.gif" alt="" height="4" width="100%" />
										<br />
										<br />
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<br />
		<p>
				<a name="N1044A">
						<span class="atitle">结束语</span>
				</a>
		</p>
		<p>如果现在头有些发晕了，那么想一下这个：如果可以构建这样一个字典应用程序，使用户可以随意创建查询会怎么样呢？例如，<code>findAllWordsLikeGlib</code> 或者 <code>findAllWordsWithSynonymGlib</code> 等等，这些语义对于 MOP 来说这只是文字解析罢了，而对用户来说，则是强大的查询功能！</p>
		<p>现在再进一步：如果可以创建另一种迷你语言，它对一项业务更有用一些，比如针对股市交易的迷你语言，那会怎么样呢？如果更进一步，将这个应用程序构建为有友好的控制台呢？不用编写脚本，用户使用的是 Groovy 的 shell。（记住我是怎么说 Bash 的？）</p>
		<p>如果您认为这种“炼金术”工具只是痴迷于 Emacs 扩展的古怪的 LISP 家伙们用的，那就错了！只要看看马路对面那些喧嚷的 Ruby on Rails 老手们就会知道这种平台是多么的令人激动。深入了解您就会看到当 MOP 发挥作用时，只要 <i>遵守命名规范</i>，不用深入 SQL 就可创建很好的查询。谁在那儿乐呢？
</p>
<img src ="http://www.blogjava.net/JafeLee/aggbug/128679.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/JafeLee/" target="_blank">Jafe</a> 2007-07-06 21:15 <a href="http://www.blogjava.net/JafeLee/articles/128679.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>实战 Groovy: 用 curry 过的闭包进行函数式编程</title><link>http://www.blogjava.net/JafeLee/articles/128678.html</link><dc:creator>Jafe</dc:creator><author>Jafe</author><pubDate>Fri, 06 Jul 2007 13:13:00 GMT</pubDate><guid>http://www.blogjava.net/JafeLee/articles/128678.html</guid><wfw:comment>http://www.blogjava.net/JafeLee/comments/128678.html</wfw:comment><comments>http://www.blogjava.net/JafeLee/articles/128678.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/JafeLee/comments/commentRss/128678.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/JafeLee/services/trackbacks/128678.html</trackback:ping><description><![CDATA[
		<p>
				<a href="http://www.ibm.com/developerworks/cn/java/j-pg08235/#author">Andrew Glover</a>, CTO, Vanward Technologies<br /><a href="http://www.ibm.com/developerworks/cn/java/j-pg08235/#author">Ken Barclay</a>, 讲师, Napier 大学<br /><a href="http://www.ibm.com/developerworks/cn/java/j-pg08235/#author">John Savage</a>, 讲师, Napier 大学<br /></p>
		<p>2005 年  9 月  23 日</p>
		<blockquote>在
Groovy 中处处都是闭包，Groovy 闭包惟一的问题是：当每天都使用它们的时候，看起来就有点平淡了。在本文中，客座作者 Ken
Barclay 和 John Savage 介绍了如何对标准的闭包（例如闭包复合和 Visitor 设计模式）进行 curry 处理。<code>curry()</code> 方法是由 Haskell Curry 发明的，在 JSR 标准发布之前就已经在 Groovy 语言中了。</blockquote>
		<!--START RESERVED FOR FUTURE USE INCLUDE FILES-->
		<!-- include java script once we verify teams wants to use this and it will work on dbcs and cyrillic characters -->
		<!--END RESERVED FOR FUTURE USE INCLUDE FILES-->
		<p>几乎从一年前<i>实战 Groovy</i> 系列开始，我就已经提供了多个让您了解闭包的机会。在首次作为 <i>alt.lang.jre</i> 系列的一部分写 Groovy 时（“感受 Groovy”，2004 年 8 月），我介绍了 Groovy 的闭包语法，而且 <a href="http://www.ibm.com/developerworks/cn/java/j-pg07195.html"> 就在上一期文章中</a>，我介绍了最新的 JSR 标准对相同语法的更新。学习至今，您知道了 Groovy 闭包是代码块，可以被引用、带参数、作为方法参数传递、作为返回值从方法调用返回。而且，它们也可以作为其他闭包的参数或返回值。因为闭包是 <code>Closure</code> 类型的对象，所以它们也可以作为类的属性或集合的成员。</p>
		<p>虽然这些技术都是很神奇的，但是本期文章要学习的闭包技术要比您迄今为止尝试过的都要更火辣一些。客座作者 John Savage 和 Ken Barclay 已经用 Groovy 闭包中的 <code>curry()</code> 方法做了一些有趣的实验，我们非常有幸可以见识他们的技艺。</p>
		<table align="right" border="0" cellpadding="0" cellspacing="0" width="40%">
				<tbody>
						<tr>
								<td width="10">
										<img alt="" src="http://www.ibm.com/i/c.gif" height="1" width="10" />
								</td>
								<td>
										<br />
								</td>
						</tr>
				</tbody>
		</table>
		<p>Barclay 和 Savage 的 curry 过的闭包不仅会重新激起您对熟悉的操作（例如复合）和 Visitor 设计模式的兴奋，还会用 Groovy 打开函数式编程的大门。</p>
		<p>
				<a name="N100B7">
						<span class="atitle">进行 curry 处理</span>
				</a>
		</p>
		<p>
				<i>curry 过的函数</i> 一般可在函数式编程语言（例如 ML 和 Haskell）中找得到（请参阅 <a href="http://www.ibm.com/developerworks/cn/java/j-pg08235/#resources">参考资料</a>）。<i>curry</i> 这个术语来自 Haskell Curry，这个数学家发明了局部函数的概念。<i>Currying</i> 指的是把多个参数放进一个接受许多参数的函数，形成一个新的函数接受余下的参数，并返回结果。令人兴奋的消息是，Groovy 的当前版本（在编写本文时是 jsr-02 版）支持在<code>闭包</code>上使用 <code>curry()</code> 方法 —— 这意味着，我们这些 Groovy 星球的公民，现在可以利用函数式编程的某些方面了！</p>
		<p>您以前可能从未用过 <code>curry()</code>，所以我们先从一个简单的、熟悉的基础开始。清单 1 显示了一个叫做 <code>multiply</code> 的闭包。它有形式参数 <code>x</code> 和 <code>y</code>，并返回这两个值的乘积。假设没有歧义存在，然后代码演示了用于执行 <code>multiply</code> 闭包的两种方法：显式（通过 <code>call</code> 的方式）或隐式。后一种样式引起了函数调用方式。</p>
		<br />
		<br />
		<a name="N100F0">
				<b>清单 1. 简单的闭包</b>
		</a>
		<br />
		<table border="0" cellpadding="0" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td class="code-outline">
										<pre class="displaycode">def multiply = { x, y -&gt; return x * y } // closure<br />def p = multiply.call(3, 4)             // explicit call<br />def q = multiply(4, 5)                  // implicit call<br />println "p: ${p}"                       // p is 12<br />println "q: ${q}"                       // q is 20<br /></pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>这个闭包当然很好，但是我们要对它进行 curry 处理。在调用 <code>curry()</code> 方法时，不需要提供所有的实际参数。<i>curry 过的</i> 调用只引起了闭包的部分应用程序。闭包的 <i>部分应用程序</i> 是另一个 <code>Closure</code> 对象，在这个对象中有些值已经被修正。</p>
		<p>清单 2 演示了对 <code>multiply</code> 闭包进行 curry 处理的过程。在第一个例子中，参数 <code>x</code> 的值被设置为 3。名为 <code>triple</code> 的闭包现在有效地拥有了 <code>triple = { y -&gt; return 3 * y }</code> 的定义。</p>
		<br />
		<br />
		<a name="N1011F">
				<b>清单 2. curry 过的闭包</b>
		</a>
		<br />
		<table border="0" cellpadding="0" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td class="code-outline">
										<pre class="displaycode">def multiply = { x, y -&gt; return x * y }  // closure<br />def triple = multiply.curry(3)           // triple = { y -&gt; return 3 * y }<br />def quadruple = multiply.curry(4) <br />// quadruple = { y -&gt; return 4 * y }<br />def p = triple.call(4)                   // explicit call<br />def q = quadruple(5)                     // implicit call<br />println "p: ${p}"                        // p is 12<br />println "q: ${q}"                        // q is 20<br /></pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>可以看到，参数 <code>x</code> 已经从 <code>multiply</code> 的定义中删除，所有它出现的地方都被 3 这个值代替了。</p>
		<p>
				<a name="N10135">
						<span class="smalltitle">curry 过的数学 101</span>
				</a>
		</p>
		<p>从基本数学可能知道，乘法运算符是<i>可交换的</i>（换句话说 <code>x * y = y * x</code>）。但是，减法运算符是不可交换的；所以，需要两个操作来处理减数和被减数。清单 3 为这个目的定义了闭包 <code>lSubtract</code> 和 <code>rSubtract</code>（分别在左边和右边），结果显示了 <code>curry</code> 函数的一个有趣的应用。</p>
		<br />
		<br />
		<a name="N10156">
				<b>清单 3. 右和右操作数</b>
		</a>
		<br />
		<table border="0" cellpadding="0" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td class="code-outline">
										<pre class="displaycode">def lSubtract = { x, y -&gt; return x - y }<br />def rSubtract = { y, x -&gt; return x - y }<br />def dec = rSubtract.curry(1)            <br /> // dec = { x -&gt; return x - 1 }<br />def cent = lSubtract.curry(100)          <br />// cent = { y -&gt; return 100 - y }<br />def p = dec.call(5)                      // explicit call<br />def q = cent(25)                         // implicit call<br />println "p: ${p}"                        // p is 4<br />println "q: ${q}"                        // q is 75<br /></pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<br />
		<table border="0" cellpadding="0" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td>
										<img src="http://www.ibm.com/i/v14/rules/blue_rule.gif" alt="" height="1" width="100%" />
										<br />
										<img alt="" src="http://www.ibm.com/i/c.gif" border="0" height="6" width="8" />
								</td>
						</tr>
				</tbody>
		</table>
		<table class="no-print" align="right" cellpadding="0" cellspacing="0">
				<tbody>
						<tr align="right">
								<td>
										<img src="http://www.ibm.com/i/c.gif" alt="" height="4" width="100%" />
										<br />
										<br />
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<br />
		<p>
				<a name="N1015D">
						<span class="atitle">迭代和复合</span>
				</a>
		</p>
		<p>您会回忆起这个系列以前的文章中，闭包一般用于在 <code>List</code> 和 <code>Map</code> 集合上应用的<i>迭代器方法</i> 上。例如，迭代器方法 <code>collect</code> 把闭包应用到集合中的每个元素上，并返回一个带有新值的新集合。清单 4 演示了把
<code>collect</code> 方法应用于 <code>List</code> 和 <code>Map</code>。名为 <code>ages</code> 的 <code>List</code> 被发送给 <code>collect()</code>
方法，使用单个闭包 <code>{ element -&gt; return
element + 1 }</code> 作为参数。注意方法的最后一个参数是个闭包，在这个地方 Groovy 允许把它从实际参数列表中删除，并把它直接放在结束括号后面。在没有实际参数时，可以省略括号。用名为 <code>accounts</code> 的 <code>Map</code> 对象调用的 <code>collect()</code> 方法可以展示这一点。</p>
		<br />
		<br />
		<a name="N1019E">
				<b>清单 4. 闭包和集合</b>
		</a>
		<br />
		<table border="0" cellpadding="0" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td class="code-outline">
										<pre class="displaycode">def ages = [20, 30, 40]<br />def accounts = ['ABC123' : 200, 'DEF456' : 300, 'GHI789' : 400]<br />def ages1 = ages.collect({ element -&gt; return element + 1 })<br />def accounts1 = accounts.collect <br />  { entry -&gt; entry.value += 10; return entry }<br />println "ages1: ${ages1}" <br />// ages1: [21, 31, 41]<br />println "accounts1: ${accounts1}"<br />// accounts1: [ABC123=210, GHI789=410, DEF456=310]<br />def ages2 = ages.collect { element -&gt; return dec(element) }<br />println "ages2: ${ages2}"<br /> // ages2: [19, 29, 39]<br /></pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>最后一个例子搜集名为 <code>ages</code> 的 <code>List</code> 中的所有元素，并将 <code>dec</code> 闭包 （来自清单 3）应用于这些元素。</p>
		<p>
				<a name="N101B8">
						<span class="smalltitle">闭包复合</span>
				</a>
		</p>
		<p>闭包更重要的一个特征可能就是<i>复合（composition）</i>，在复合中可以定义一个闭包，它的目的是组合其他闭包。使用复合，两个或多个简单的闭包可以组合起来构成一个更复杂的闭包。</p>
		<p>清单 5 介绍了一个漂亮的 <code>composition</code>
闭包。现在请注意仔细阅读：参数 <code>f</code> 和 <code>g</code> 代表 <i>单个参数闭包</i>。到现在还不错？现在，对于某些参数值 <code>x</code>，闭包 <code>g</code> 被应用于 x，而闭包 <code>f</code> 被应用于生成的结果！哦，只对前两个闭包参数进行了 curry 处理，就有效地形成了一个组合了这两个闭包的效果的新闭包。 </p>
		<p>清单 5 组合了闭包 <code>triple</code> 和 <code>quadruple</code>，形成闭包 <code>twelveTimes</code>。当把这个闭包应用于实际参数 3 时，返回值是 36。</p>
		<br />
		<br />
		<a name="N101F2">
				<b>清单 5. 超级闭包复合</b>
		</a>
		<br />
		<table border="0" cellpadding="0" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td class="code-outline">
										<pre class="displaycode">def multiply = { x, y -&gt; return x * y }    <br />// closure<br />def triple = multiply.curry(3)            <br />// triple = { y -&gt; return 3 * y }<br />def quadruple = multiply.curry(4) <br />// quadruple = { y -&gt; return 4 * y }<br />def composition = { f, g, x -&gt; return f(g(x)) }<br />def twelveTimes = composition.curry(triple, quadruple)<br />def threeDozen = twelveTimes(3)<br />println "threeDozen: ${threeDozen}"		 <br />// threeDozen: 36<br /></pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>非常漂亮，是么？</p>
		<br />
		<table border="0" cellpadding="0" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td>
										<img src="http://www.ibm.com/i/v14/rules/blue_rule.gif" alt="" height="1" width="100%" />
										<br />
										<img alt="" src="http://www.ibm.com/i/c.gif" border="0" height="6" width="8" />
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<br />
		<p>
				<a name="N10200">
						<span class="atitle">五星计算</span>
				</a>
		</p>
		<p>现在我们来研究闭包的一些更刺激的方面。我们先从一个机制开始，用这个机制可以表示包含<i>计算模式</i> 的闭包，计算模式是一个来自函数式编程的概念。计算模式的一个例子就是用某种方式把 <code>List</code> 中的每个元素进行转换。因为这些模式发生得如此频繁，所以我们开发了一个叫做 <code>Functor</code> 的类，把它们封装成 <code>static Closure</code>。清单 6 显示了一个摘要。</p>
		<br />
		<br />
		<a name="N10219">
				<b>清单 6. Functor 封装了一个计算模式</b>
		</a>
		<br />
		<table border="0" cellpadding="0" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td class="code-outline">
										<pre class="displaycode">package fp<br />abstract class Functor {<br /> //  arithmetic (binary, left commute and right commute)<br /> public static Closure bMultiply     = { x, y -&gt; return x * y }<br /> public static Closure rMultiply     = { y, x -&gt; return x * y }<br /> public static Closure lMultiply     = { x, y -&gt; return x * y }<br /><br /> // ...<br /> // composition<br /> public static Closure composition   = { f, g, x -&gt; return f(g(x)) }<br /><br /> // lists<br /> public static Closure map    = <br />   { action, list -&gt; return list.collect(action) }<br /><br /> public static Closure apply  = { action, list -&gt; list.each(action) }<br /><br /> public static Closure forAll = { predicate, list -&gt;<br />                                  for(element in list) {<br />                                    if(predicate(element) == false) {<br />                                        return false<br />                                    }<br />                                  }<br />                                  return true<br />                               }<br />    // ...<br />}</pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>在这里可以看到名为 <code>map</code> 的闭包，不要把它与 <code>Map</code> 接口混淆。<code>map</code>
闭包有一个参数 <code>f</code> 代表闭包，还有一个参数 <code>list</code> 代表（不要惊讶）<code>List</code>。它返回一个新 <code>List</code>，其中 <code>f</code> 已经映射到 <code>list</code> 中的每个元素。当然，Groovy 已经有了用于 <code>Lists</code> 的 <code>collect()</code> 方法，所以我们在我们的实现中也使用了它。</p>
		<p>在清单 7 中，我们把事情又向前进行了一步，对 <code>map</code> 闭包进行了 <i>curry </i> 处理，形成一个块，会将指定列表中的所有元素都乘以 12。</p>
		<br />
		<br />
		<a name="N1025D">
				<b>清单 7. 添加一些 curry，并乘以 12</b>
		</a>
		<br />
		<table border="0" cellpadding="0" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td class="code-outline">
										<pre class="displaycode">import fp.*<br />def twelveTimes = { x -&gt; return 12 * x }<br />def twelveTimesAll = Functor.map.curry(twelveTimes)<br />def table = twelveTimesAll([1, 2, 3, 4])<br />println "table: ${table}"		<br />// table: [12, 24, 36, 48]<br /></pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>现在，<i>这</i> 就是我们称之为五星计算的东西！</p>
		<br />
		<table border="0" cellpadding="0" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td>
										<img src="http://www.ibm.com/i/v14/rules/blue_rule.gif" alt="" height="1" width="100%" />
										<br />
										<img alt="" src="http://www.ibm.com/i/c.gif" border="0" height="6" width="8" />
								</td>
						</tr>
				</tbody>
		</table>
		<table class="no-print" align="right" cellpadding="0" cellspacing="0">
				<tbody>
						<tr align="right">
								<td>
										<img src="http://www.ibm.com/i/c.gif" alt="" height="4" width="100%" />
										<br />
										<br />
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<br />
		<p>
				<a name="N1026E">
						<span class="atitle">业务规则用 curry 处理</span>
				</a>
		</p>
		<p>关于闭包的技艺的讨论很不错，但是更关注业务的人会更欣赏下面这个例子。在考虑计算特定 <code>Book</code> 条目净值的问题时，请考虑商店的折扣和政府的税金（例如 <i>增值税</i>）。如果想把这个逻辑作为 <code>Book</code> 类的一部分包含进来，那么形成的解决方案可能是个难缠的方案。因为书店可能会改变折扣，或者折扣只适用于选定的存货，所以这样一个解决方案可能会太刚性了。</p>
		<p>但是猜猜情况如何。变化的业务规则非常适合于使用 curry 过的闭包。可以用一组简单的闭包来表示单独的业务规则，然后用复合把它们以不同的方式组合起来。最后，可以用 <i>计算模式</i> 把它们映射到集合。</p>
		<p>清单 8 演示了书店的例子。闭包 <code>rMultiply</code> 是个局部应用程序，通过使用一个不变的第二操作数，把二元乘法改变成一元闭包。两个图书闭包 <code>calcDiscountedPrice</code> 和 <code>calcTax</code> 是 <code>rMultiply</code> 闭包的实例，为乘数值设置了值。闭包 <code>calcNetPrice</code> 是计算净价的算法：先计算折扣价格，然后在折扣价格上计算销售税。最后， <code>calcNetPrice</code> 被应用于图书价格。</p>
		<br />
		<br />
		<a name="N102A4">
				<b>清单 8. 图书业务对象</b>
		</a>
		<br />
		<table border="0" cellpadding="0" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td class="code-outline">
										<pre class="displaycode">import fp.*<br />class Book {<br />    @Property name<br />    @Property author<br />    @Property price<br />    @Property category<br />}<br />def bk = new Book(name : 'Groovy', author : <br />  'KenB', price : 25, category : 'CompSci')<br />// constants<br />def discountRate = 0.1<br />def taxRate = 0.17<br />//  book closures<br />def calcDiscountedPrice = Functor.rMultiply.curry(1 - discountRate)<br />def calcTax = Functor.rMultiply.curry(1 + taxRate)<br />def calcNetPrice = <br />  Functor.composition.curry(calcTax, calcDiscountedPrice)<br />//  now calculate net prices<br />def netPrice = calcNetPrice(bk.price)<br />println "netPrice: ${netPrice}"		// netPrice: 26.325<br /></pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<br />
		<table border="0" cellpadding="0" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td>
										<img src="http://www.ibm.com/i/v14/rules/blue_rule.gif" alt="" height="1" width="100%" />
										<br />
										<img alt="" src="http://www.ibm.com/i/c.gif" border="0" height="6" width="8" />
								</td>
						</tr>
				</tbody>
		</table>
		<table class="no-print" align="right" cellpadding="0" cellspacing="0">
				<tbody>
						<tr align="right">
								<td>
										<img src="http://www.ibm.com/i/c.gif" alt="" height="4" width="100%" />
										<br />
										<br />
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<br />
		<p>
				<a name="N102AF">
						<span class="atitle">更加 groovy 的访问者</span>
				</a>
		</p>
		<p>已经看到了如何把 curry
过的闭包应用于函数模式，所以现在我们来看看在使用相似的技术重新访问重要的面向对象设计模式时发生了什么。对于面向对象系统来说，必须遍历对象集合并在
集合中的每个元素上执行某个操作，是非常普通的使用情况。假设一个不同的场景，系统要遍历相同的集合，但是要执行不同的操作。通常，需要用 <i>Visitor 设计模式</i>（请参阅
<a href="http://www.ibm.com/developerworks/cn/java/j-pg08235/#resources">参考资料</a>）来满足这一需求。<code>Visitor</code> 接口引入了处理集合元素的动作协议。具体的子类定义需要的不同行为。方法被引进来遍历集合并对每个元素应用 <code>Visitor</code> 动作。 </p>
		<p>如果到现在您还没猜出来，那么可以用闭包实现同的效果。这种方法的一个抽象是：使用闭包，不需要开发访问者类的层次结构。而且，可以有效地使用闭包复合和映射来定义集合的动作和效果遍历。 </p>
		<p>例如，考虑用来表示图书馆库存的类 <code>Library</code> 和类 <code>Book</code> 之间的一对多关系。可以用 <code>List</code> 或 <code>Map</code> 实现这个关系；但是 <code>Map</code> 提供的优势是它能提供快速的查询，也就是说用图书目录编号作为键。 </p>
		<p>清单 9 显示了一个使用 <code>Map</code> 的简单的一对多关系。请注意 <code>Library</code> 类中的两个显示方法。引入访问者时，两者都是重构的目标。</p>
		<br />
		<br />
		<a name="N102ED">
				<b>清单 9. 图书馆应用程序</b>
		</a>
		<br />
		<table border="0" cellpadding="0" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td class="code-outline">
										<pre class="displaycode">class Book {    <br />    @Property title<br />    @Property author<br />    @Property catalogNumber<br />    @Property onLoan = false<br />	String toString() {<br />        return "Title: ${title}; author: ${author}"<br />    }<br />}<br />class Library {<br />    @Property name<br />    @Property stock = [ : ]<br /><br />	def addBook(title, author, catalogNumber) {<br />        def bk = new Book(title : title, author : <br />          author, catalogNumber : catalogNumber)<br />        stock[catalogNumber] = bk<br />    }<br /><br />    def lendBook(catalogNumber) {<br />        stock[catalogNumber].onLoan = true<br />    }<br /><br />    def displayBooksOnLoan() {<br />        println "Library: ${name}"<br />        println "Books on loan"<br />        stock.each { entry -&gt;<br />            if(entry.value.onLoan == true) println entry.value<br />        }<br />    }<br /><br />    def displayBooksAvailableForLoan() {<br />        println "Library: ${name}"<br />        println "Books available for loan"<br />        stock.each { entry -&gt;<br />            if(entry.value.onLoan == false) println entry.value<br />        }<br />    }    <br />}<br />def lib = new Library(name : 'Napier')<br />lib.addBook('Groovy', 'KenB', <br />  'CS123')<br />lib.addBook('Java', 'JohnS', 'CS456')<br />lib.addBook('UML', 'Ken and John', <br />  'CS789')<br />lib.lendBook('CS123')<br />lib.displayBooksOnLoan()	// Title: Groovy; author: KenB<br />lib.displayBooksAvailableForLoan()	// Title: UML; author: Ken and John<br />	// Title: Java; author: JohnS<br /></pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>清单 10 包含 <code>Library</code> 类中的几个闭包，模拟了访问者的用法。<code>action</code> 闭包（与 <code>map</code> 闭包有点相似）把 <code>action</code> 闭包应用于 <code>List</code> 的每个元素。如果某本书被借出，则闭包 <code>displayLoanedBook</code> 显示它；如果某本书未被借出，则闭包 <code>displayAvailableBook</code> 显示它。两者都扮演访问者和相关的动作。用 <code>displayLoanedBook</code> 对 <code>apply</code> 闭包进行 curry 处理，会形成闭包 <code>displayLoanedBooks</code>，它为处理图书集合做好了准备。类似的方案也用来生成可供借阅的图书显示，如清单 10 所示。 </p>
		<br />
		<br />
		<a name="N10323">
				<b>清单 10. 修订后的图书馆访问者</b>
		</a>
		<br />
		<table border="0" cellpadding="0" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td class="code-outline">
										<pre class="displaycode">import fp.*<br />class Book {<br />    @Property title<br />    @Property author<br />    @Property catalogNumber<br />    @Property onLoan = false<br />    String toString() {<br />        return "    Title: ${title}; author: ${author}"<br />    }<br /><br />}<br />class Library {      <br />    @Property name<br />    @Property stock = [ : ]<br />    def addBook(title, author, catalogNumber) {<br />        def bk = new Book(title : title, author : <br />          author, catalogNumber : catalogNumber)<br />        stock[catalogNumber] = bk<br />    }<br /><br />    def lendBook(catalogNumber) {<br />        stock[catalogNumber].onLoan = true<br />    }<br /><br />    def displayBooksOnLoan() {<br />        println "Library: ${name}"<br />        println "Books on loan"<br />        displayLoanedBooks(stock.values())<br />    }<br /><br />    def displayBooksAvailableForLoan() {<br />        println "Library: ${name}"<br />        println "Books available for loan"<br />        displayAvailableBooks(stock.values())<br />    }<br /><br /><br />    private displayLoanedBook = { bk -&gt; if(bk.onLoan == true) <br />      println bk }<br />    private displayAvailableBook = { bk -&gt; if(bk.onLoan == false) <br />      println bk }<br /><br />    private displayLoanedBooks = <br />      Functor.apply.curry(displayLoanedBook)<br />    private displayAvailableBooks = <br />      Functor.apply.curry(displayAvailableBook)<br />}<br />def lib = new Library(name : 'Napier')<br />lib.addBook('Groovy', 'KenB', <br />  'CS123')<br />lib.addBook('Java', 'JohnS', 'CS456')<br />lib.addBook('UML', 'Ken and John', <br />  'CS789')<br />lib.lendBook('CS123')<br />lib.displayBooksOnLoan()	// Title: Groovy; author: KenB<br />lib.displayBooksAvailableForLoan() // Title: UML; author: Ken and John<br />                             // Title: Java; author: JohnS<br /></pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<br />
		<table border="0" cellpadding="0" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td>
										<img src="http://www.ibm.com/i/v14/rules/blue_rule.gif" alt="" height="1" width="100%" />
										<br />
										<img alt="" src="http://www.ibm.com/i/c.gif" border="0" height="6" width="8" />
								</td>
						</tr>
				</tbody>
		</table>
		<table class="no-print" align="right" cellpadding="0" cellspacing="0">
				<tbody>
						<tr align="right">
								<td>
										<img src="http://www.ibm.com/i/c.gif" alt="" height="4" width="100%" />
										<br />
										<br />
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<br />
		<p>
				<a name="N1032E">
						<span class="atitle">用闭包进行测试</span>
				</a>
		</p>
		<p>在结束之前，我们来看一下 Groovy 闭包的一个附加用途。请考虑一个被建模为具有许多 <code>Employee</code> 的 <code>Company</code> 的应用程序。递归的关系在单个 <code>Employee</code>（团队领导）和许多 <code>Employee</code>（团队成员）之间进一步建立起一对多的聚合。图 1 是这样一个组织的类图。</p>
		<br />
		<br />
		<a name="N1034A">
				<b>图 1. Company 应用程序</b>
		</a>
		<br />
		<img alt="Company 应用程序的类图" src="http://www.ibm.com/developerworks/cn/java/j-pg08235/figure1.gif" height="93" width="402" />
		<br />
		<p>可以用闭包来表述模型架构上的完整性。例如，在这个例子中，可能想确保每个员工都分配了一个经理。简单的闭包 <code>hasManager</code> 为每个员工表达了这个需求： <code>def hasManager = { employee -&gt; return (employee.manager != null) }</code>。</p>
		<p>来自清单 6 的 <code>Functor</code> 类中的 <code>forAll</code> 闭包的局部应用程序能够描述架构的需求：<code>def
everyEmployeeHasManager = Functor.forAll.curry(hasManager)</code>。</p>
		<p>清单 11 演示了 curry 过的闭包的应用：测试系统架构的完整性。</p>
		<br />
		<br />
		<a name="N10376">
				<b>清单 11. 用于测试架构完整性的闭包</b>
		</a>
		<br />
		<table border="0" cellpadding="0" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td class="code-outline">
										<pre class="displaycode">import fp.*<br />/**<br /> *  A company with any number of employees. <br /> *  Each employee is responsible<br /> *  to a team leader who, in turn, manages a team of staff.<br /> */<br />import java.util.*<br />class Employee {<br />	@Property id<br />    @Property name<br />    @Property staff = [ : ]<br />    @Property manager = null<br />    String toString() {<br />        return "Employee: ${id} ${name}"<br />    }<br /><br />    def addToTeam(employee) {<br />        staff[employee.id] = employee<br />        employee.manager = this<br />    }<br /><br />}<br />class Company {<br />	@Property name<br />    @Property employees = [ : ]<br />    def hireEmployee(employee) {<br />        employees[employee.id] = employee<br />    }<br /><br />    def displayStaff() {<br />        println "Company: ${name}"<br />        println "===================="<br />        employees.each { entry -&gt; println "    <br />          ${entry.value}" }<br />    }<br /><br /><br />}<br />def co = new Company(name : 'Napier')<br />def emp1 = new Employee(id : 123, name : 'KenB')<br />def emp2 = new Employee(id : 456, name : 'JohnS')<br />def emp3 = new Employee(id : 789, name : 'JonK')<br />co.hireEmployee(emp1)<br />co.hireEmployee(emp2)<br />co.hireEmployee(emp3)<br />emp3.addToTeam(emp1)<br />emp3.addToTeam(emp2)<br />co.displayStaff()<br />//  Architectural closures<br />def hasManager = { employee -&gt; return (employee.manager != null) }<br />def everyEmployeeHasManager = Functor.forAll.curry(hasManager)<br />def staff = new ArrayList(co.employees.values())<br />println "Every employee has a manager?: <br />  ${everyEmployeeHasManager.call(staff)}"    // false<br /></pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<br />
		<table border="0" cellpadding="0" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td>
										<img src="http://www.ibm.com/i/v14/rules/blue_rule.gif" alt="" height="1" width="100%" />
										<br />
										<img alt="" src="http://www.ibm.com/i/c.gif" border="0" height="6" width="8" />
								</td>
						</tr>
				</tbody>
		</table>
		<table class="no-print" align="right" cellpadding="0" cellspacing="0">
				<tbody>
						<tr align="right">
								<td>
										<img src="http://www.ibm.com/i/c.gif" alt="" height="4" width="100%" />
										<br />
										<br />
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<br />
		<p>
				<a name="N10381">
						<span class="atitle">curry 是优秀的</span>
				</a>
		</p>
		<p>在本文中您已看到了大量闭包，但是希望能激起您对更多闭包的渴望。在学习乘法例子时，curry
过的闭包使得实现计算的函数模式出奇得容易。一旦掌握了这些模式，就可以把它们部署到常见的企业场景中，例如我们在书店例子中把它们应用于业务规则。把闭
包应用于函数模式是令人兴奋的，一旦这么做了之后，再把它们应用于面向对象设计模式，就不是什么大事情了。Curry 过的闭包可以用来模拟
Visitor 模式的基本元素，正如在 <code>Library</code> 例子中显示的。它们在软件测试期间执行完整性测试时也会有用，就像用 <code>Company</code> 例子所展示的。 </p>
		<p>本文中看到的全部例子都是企业系统常见的用例。看到 Groovy 闭包和
<code>curry</code> 方法能够如此流畅地应用于众多编程场景、函数模式和面向对象模式，真是激动人心。Haskell Curry 肯定发现了这个可怕的 <i>groovy</i>！</p>
<img src ="http://www.blogjava.net/JafeLee/aggbug/128678.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/JafeLee/" target="_blank">Jafe</a> 2007-07-06 21:13 <a href="http://www.blogjava.net/JafeLee/articles/128678.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>实战 Groovy: Groovy 的腾飞</title><link>http://www.blogjava.net/JafeLee/articles/128677.html</link><dc:creator>Jafe</dc:creator><author>Jafe</author><pubDate>Fri, 06 Jul 2007 13:12:00 GMT</pubDate><guid>http://www.blogjava.net/JafeLee/articles/128677.html</guid><wfw:comment>http://www.blogjava.net/JafeLee/comments/128677.html</wfw:comment><comments>http://www.blogjava.net/JafeLee/articles/128677.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/JafeLee/comments/commentRss/128677.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/JafeLee/services/trackbacks/128677.html</trackback:ping><description><![CDATA[
		<p>
				<a href="http://www.ibm.com/developerworks/cn/java/j-pg07195.html#author">Andrew Glover</a>, CTO, Vanward Technologies<br /></p>
		<p>2005 年  8 月  22 日</p>
		<blockquote>随
着 Groovy JSR-1（及其后续发行版本）的发布，Groovy 语法的变化已经规范化 ——
这意味着如果以前没有对此加以注意，那么现在是开始注意它的时候了。这个月，Groovy 的常驻实践者 Andrew Glover 将介绍
Groovy 语法最重要的变化，以及在经典 Groovy 中找不到的一个方便特性。</blockquote>
		<!--START RESERVED FOR FUTURE USE INCLUDE FILES-->
		<!-- include java script once we verify teams wants to use this and it will work on dbcs and cyrillic characters -->
		<!--END RESERVED FOR FUTURE USE INCLUDE FILES-->
		<p>从我在 <i>alt.lang.jre</i> 的系列文章“<a href="http://www.ibm.com/developerworks/java/library/j-alj08034.html?S_TACT=105AGX52&amp;S_CMP=cn-a-j">Feeling Groovy</a>”
中介绍 Groovy
开始，差不多有一年时间了。从那时起，通过发行许多版本，逐步解决了语言实现中的问题，并满足开发人员社区的一些特性请求，Groovy
已经成熟了许多。最后，在今年四月，Groovy 有了一个重大飞跃，它正式发布了新的解析器，该解析器的目标就是将这门语言标准化为 JSR
进程的一部分。</p>
		<p>在本月“<i>实战 Groovy</i>”这一期的文章中，我将祝贺 Groovy 的成长，介绍通过
Groovy 非常好用的新解析器规范化的一些最重要的变化：即变量声明和闭包。因为我要将一些新 Groovy 语法与我在关于 Groovy
的第一篇文章中介绍的经典语法进行比较，所以您可以在另一个浏览器窗口中打开“<a href="http://www.ibm.com/developerworks/cn/java/j-alj08034/"> alt.lang.jre: 感受 Groovy</a>”这篇文章。</p>
		<p>
				<a name="N1006A">
						<span class="atitle">为什么会发生这些变化？</span>
				</a>
		</p>
		<p>
如果您一直在跟踪 Groovy，不管是阅读文章和
blog，还是自己编写代码，您都可能已经遭遇过这门语言的一、两个微妙的问题。在进行一些灵敏的操作，例如对象导航，特别是使用闭包的时候，
Groovy 偶尔会遇到歧义性问题和语法受限的问题。几个月之前，作为 JSR 进程的一部分，Groovy 团队开始着手解决这些问题。四月份，随
groovy-1.0-jsr-01 发行版本提供的解决方案是一个更新过的语法以及一个用来对语法进行标准化的新语法内容解析器。 </p>
		<table align="right" border="0" cellpadding="0" cellspacing="0" width="40%">
				<tbody>
						<tr>
								<td width="10">
										<img alt="" src="http://www.ibm.com/i/c.gif" height="1" width="10" />
								</td>
								<td>
										<br />
								</td>
						</tr>
				</tbody>
		</table>
		<p> 好消息是：新语法是对语言的完全增强。另一个好消息是：它和以前的语法没有很大不同。像所有 Groovy 一样，语法的设计目标是较短的学习曲线和较大的回报。</p>
		<p>当
然，符合 JSR 的解析器也给新 Groovy
带来一些与目前“经典”语法不兼容的地方。如果用新的解析器运行本系列以前文章中的代码示例，那么您自己就可以看，代码示例可能无法工作！现在，这一点看
起来可能有点苛刻 —— 特别是对 Groovy 这样自由的语言来说 —— 但是解析器的目标是确保作为 Java 平台的<i>标准化</i> 语言的 Groovy 的持续成长。可以把它当作新 Groovy 的一个有帮助的指南。</p>
		<br />
		<table border="0" cellpadding="0" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td>
										<img src="http://www.ibm.com/i/v14/rules/blue_rule.gif" alt="" height="1" width="100%" />
										<br />
										<img alt="" src="http://www.ibm.com/i/c.gif" border="0" height="6" width="8" />
								</td>
						</tr>
				</tbody>
		</table>
		<table class="no-print" align="right" cellpadding="0" cellspacing="0">
				<tbody>
						<tr align="right">
								<td>
										<img src="http://www.ibm.com/i/c.gif" alt="" height="4" width="100%" />
										<br />
										<br />
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<br />
		<p>
				<a name="N1008F">
						<span class="atitle">Groovy 依然是 Groovy！</span>
				</a>
		</p>
		<p>在深入研究变化的内容之前，我要花几秒钟谈谈什么<i>没有改变</i>。首先，动态类型化的基本性质没有改变。变量的显式类型化（即将变量声明为 <code>String</code> 或 <code>Collection</code>） 依然是可选的。稍后，我会讨论对这一规则的一点新增内容。</p>
		<p>知道分号依然是可选的时候，许多人都会感到轻松。对于放松对这个语法的使用，存在许多争论，但是最终少数派赢得了胜利。底线是：如果愿意，也可以使用分号。</p>
		<p>集合（Collection）的使用大部分还保持不变。仍然可以用 <i>array</i> 语法和 <code>map</code>，像以前那样（即最初从文章“<a href="http://www.ibm.com/developerworks/cn/java/j-alj08034/">alt.lang.jre: 感受 Groovy</a>”中学到的方式）声明类似 <code>list</code> 的集合。但范围上略有变化，我将在后面部分展示这一点。</p>
		<p>最后，Groovy 对标准 JDK 类的增加没有发生多少变化。语法糖衣和漂亮的 API 也没变， 就像普通的 Java <code>File</code> 类型的情况一样，我稍后将展示这一点。</p>
		<br />
		<table border="0" cellpadding="0" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td>
										<img src="http://www.ibm.com/i/v14/rules/blue_rule.gif" alt="" height="1" width="100%" />
										<br />
										<img alt="" src="http://www.ibm.com/i/c.gif" border="0" height="6" width="8" />
								</td>
						</tr>
				</tbody>
		</table>
		<table class="no-print" align="right" cellpadding="0" cellspacing="0">
				<tbody>
						<tr align="right">
								<td>
										<img src="http://www.ibm.com/i/c.gif" alt="" height="4" width="100%" />
										<br />
										<br />
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<br />
		<p>
				<a name="N100BF">
						<span class="atitle">容易变的变量</span>
				</a>
		</p>
		<p>Groovy 的变量规则对新的符合 JSR 的语法的打击可能最大。经典的 Groovy 在变量声明上相当灵活（而且实际上很简洁）。而使用新的 JSR Groovy 时，所有的变量前都必须加上 <code>def</code> 关键字或者 <code>private</code>、<code>protected</code> 或 <code>public</code> 这样的修饰符。当然，也可以声明变量类型。另外，如果正在定义类，希望声明属性（使用 JavaBeans 样式的 getter 和 setter 公开），那么也可以用 <code>@Property</code> 关键字声明成员变量。请注意 —— <i>Property</i> 中的  <i>P</i> 是大写的！</p>
		<p>例如，在“<a href="http://www.ibm.com/developerworks/cn/java/j-alj08034/">alt.lang.jre: 感受 Groovy</a>”中介绍 <i>GroovyBeans</i> 时，我在文章的清单 22 中定义了一个叫做 <code>LavaLamp</code> 的类型。这个类不再符合 JSR 规范，如果要运行它，则会造成解析器错误。幸运的是，迁移这个类不是很困难：我要做的全部工作就是给所有需要的成员变量添加 <code>@Property</code> 属性，如清单 1 所示：</p>
		<br />
		<br />
		<a name="code1">
				<b>清单 1. LavaLamp 的返回结果</b>
		</a>
		<br />
		<table border="0" cellpadding="0" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td class="code-outline">
										<pre class="displaycode">package com.vanward.groovy<br />class LavaLamp{<br />  @Property model<br />  @Property baseColor<br />  @Property liquidColor<br />  @Property lavaColor<br />}<br />llamp = new LavaLamp(model:1341, baseColor:"Black", <br />  liquidColor:"Clear", lavaColor:"Green")<br />println llamp.baseColor<br />println "Lava Lamp model ${llamp.model}"<br />myLamp = new LavaLamp()<br />myLamp.baseColor = "Silver"<br />myLamp.setLavaColor("Red")<br />println "My Lamp has a ${myLamp.baseColor} base"<br />println "My Lava is " + myLamp.getLavaColor()<br /></pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>不是太坏，不是吗？</p>
		<p>正如上面描述的，对于<i>任何</i> 变量，如果没有修饰符、<code>@Property</code> 关键字或者类型，则需要具有 <code>def</code> 关键字。例如，清单 2 的代码在 <code>toString</code> 方法中包含一个中间变量 <code>numstr</code> ，如果用 JSR 解析器运行此代码，则会造成一个错误：</p>
		<br />
		<br />
		<a name="code2">
				<b>清单 2. 不要忘记 def 关键字！</b>
		</a>
		<br />
		<table border="0" cellpadding="0" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td class="code-outline">
										<pre class="displaycode">class Person { <br />  @Property fname<br />  @Property lname<br />  @Property age<br />  @Property address<br />  @Property contactNumbers<br />  String toString(){<br /><br />   numstr = new StringBuffer()<br /><br />   if (contactNumbers != null){<br />	   contactNumbers.each{<br />		numstr.append(it)<br />		numstr.append(" ")<br />	   }<br />   }<br /><br />   "first name: " + fname + " last name: " + lname + <br />	" age: " + age + " address: " + address + <br />	" contact numbers: " + numstr.toString()<br /> }<br />}<br /></pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>认识这个代码吗？它借用来自“<a href="http://www.ibm.com/developerworks/cn/java/j-pg05245/">在 Java 应用程序中加一些 Groovy 进来 </a>”一文的清单 1 中的代码。在清单 3  中，可以看到运行代码时弹出的错误消息：</p>
		<br />
		<br />
		<a name="code3">
				<b>清单 3. 错误消息</b>
		</a>
		<br />
		<table border="0" cellpadding="0" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td class="code-outline">
										<pre class="displaycode">c:\dev\projects&gt;groovy BusinessObjects.groovy<br /><br /> BusinessObjects.groovy: 13: The variable numstr is undefined in the current scope<br /> @ line 13, column 4.<br />      numstr = new StringBuffer()<br />      ^<br />1 Error<br /></pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>当然，解决方案也是在 <code>toString</code> 方法中将 <code>def</code> 关键字添加到 <code>numstr</code>。清单 4 显示了这个更合适的 <i>def</i> 解决方案。</p>
		<br />
		<br />
		<a name="code4">
				<b>清单 4. 用 def 重新处理</b>
		</a>
		<br />
		<table border="0" cellpadding="0" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td class="code-outline">
										<pre class="displaycode">  String toString(){<br /><br />   def numstr = new StringBuffer()<br /><br />   if (contactNumbers != null){<br />	   contactNumbers.each{<br />		numstr.append(it)<br />		numstr.append(" ")<br />	   }<br />   }<br /><br />   "first name: " + fname + " last name: " + lname + <br />	" age: " + age + " address: " + address + <br />	" contact numbers: " + numstr.toString()<br /> }<br /></pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>另外，我还可以为 <code>numstr</code> 提供一个像 <code>private</code> 这样的修饰符，或者将它声明为 <code>StringBuffer</code>。不论哪种方法，重要的一点是：在 JSR Groovy 中，必须在变量前加上<i>某些东西</i>。</p>
		<br />
		<table border="0" cellpadding="0" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td>
										<img src="http://www.ibm.com/i/v14/rules/blue_rule.gif" alt="" height="1" width="100%" />
										<br />
										<img alt="" src="http://www.ibm.com/i/c.gif" border="0" height="6" width="8" />
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<br />
		<p>
				<a name="N10164">
						<span class="atitle">封闭闭包（closure）</span>
				</a>
		</p>
		<p> 闭包的语法发生了变化，但是大多数变化只与参数有关。在经典的 Groovy 中，如果为闭包声明参数，就必须用 <code>|</code> 字符作为分隔符。您可能知道，<code>|</code> 也是普通 Java 语言中的位操作符；结果，在 Groovy 中，只有在某个闭包的参数声明的上下文中，才能使用 <code>|</code> 字符。</p>
		<p>在“<a href="http://www.ibm.com/developerworks/cn/java/j-alj08034/">alt.lang.jre: 感受 Groovy</a>”的清单 21 中，我演示了迭代，查看了用于闭包的经典 Groovy 参数语法。可以回想一下，我在集合上运用了 <code>find</code> 方法，该方法试图找到值 <i>3</i>。然后我传入了参数 <code>x</code>，它代表 <code>iterator</code> 的下一个值 （有经验的 <i>Groovy</i> 开发人员会注意到，<code>x</code> 完全是可选的，我可以引用隐式变量 <code>it</code>）。使用 JSR Groovy 时，必须删除 <code>|</code> ，并用 Nice <i>样式的 </i><code>-&gt;</code> 分隔符代替它，如清单 5 所示：</p>
		<br />
		<br />
		<a name="code5">
				<b>清单 5. 新的 Groovy 闭包语法</b>
		</a>
		<br />
		<table border="0" cellpadding="0" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td class="code-outline">
										<pre class="displaycode">[2, 4, 6, 8, 3].find { x -&gt;<br />  if (x == 3){<br />    println "found ${x}"<br />  }<br />}<br /></pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>新的闭包语法有没有让您想起 Nice 语言的块语法呢？如果不熟悉 Nice 语言，请参阅 <a href="http://www.ibm.com/developerworks/cn/java/j-alj10064.html">alt.lang.jre: Nice 的双倍功能</a>，这是我在 <i>alt.lang.jre</i> 系列上贡献的另一篇文章。</p>
		<p>正如我在前面提到过的，Groovy 的 JDK 没有变。但是就像刚才所学到的，闭包却发生了变化；所以，使用 Groovy  的 JDK 中那些漂亮的 <i>API</i> 的方式也发生了变化，但仅仅是轻微的变化。在清单 6 中，可以看到这些变化对 Groovy IO 的影响根本是微不足道的：</p>
		<br />
		<br />
		<a name="code6">
				<b>清单 6. Groovy 的 JDK 依旧功能强大！</b>
		</a>
		<br />
		<table border="0" cellpadding="0" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td class="code-outline">
										<pre class="displaycode">import java.io.File<br />new File("maven.xml").eachLine{ line -&gt;<br />  println "read the following line -&gt; " + line<br />}<br /></pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>
				<a name="N101CB">
						<span class="smalltitle">改编过滤器</span>
				</a>
		</p>
		<p>现在，不得不让您跳过很大一部分，但您还记得在“<a href="http://www.ibm.com/developerworks/cn/java/j-pg12144.html#IDAQ2BLB">用 Groovy 进行 Ant 脚本编程</a>”一文中，我是如何介绍闭包的威力和工具的吗？谢天谢地，我在这个专栏的示例中所做的多数工作都很容易针对新语法重新进行改编。在清单 7 中，我只是将 <code>@Property</code> 属性添加到  <code>Filter</code> 的成员 <code>strategy</code>（最初在那篇文章的清单 2 和清单 3 中显示）。然后在闭包中添加 <code>-&gt;</code> 分隔符，<i>万岁</i> —— 它可以工作了！</p>
		<br />
		<br />
		<a name="code7">
				<b>清单 7. 过滤改编！</b>
		</a>
		<br />
		<table border="0" cellpadding="0" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td class="code-outline">
										<pre class="displaycode">package com.vanward.groovy<br />class Filter{<br /> @Property strategy<br /> boolean apply(str){<br />  return strategy.call(str)<br /> }<br />}<br />simplefilter = { str -&gt; <br />  if(str.indexOf("java.") &gt;= 0){<br />    return true<br />  }else{<br />    return false<br />  }<br />}<br /><br />fltr = new Filter(strategy:simplefilter)<br />assert !fltr.apply("test")<br />assert fltr.apply("java.lang.String")<br /><br />rfilter = { istr -&gt;<br />  if(istr =~ "com.vanward.*"){<br />    return true<br />  }else{<br />    return false<br />  }<br />}<br /><br />rfltr = new Filter(strategy:rfilter)<br />assert !rfltr.apply("java.lang.String")<br />assert rfltr.apply("com.vanward.sedona.package") <br /></pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>目前为止还不坏，您觉得呢？新的 Groovy 语法很容易掌握！</p>
		<br />
		<table border="0" cellpadding="0" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td>
										<img src="http://www.ibm.com/i/v14/rules/blue_rule.gif" alt="" height="1" width="100%" />
										<br />
										<img alt="" src="http://www.ibm.com/i/c.gif" border="0" height="6" width="8" />
								</td>
						</tr>
				</tbody>
		</table>
		<table class="no-print" align="right" cellpadding="0" cellspacing="0">
				<tbody>
						<tr align="right">
								<td>
										<img src="http://www.ibm.com/i/c.gif" alt="" height="4" width="100%" />
										<br />
										<br />
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<br />
		<p>
				<a name="N101F9">
						<span class="atitle">对范围（range）的更改</span>
				</a>
		</p>
		<p>Groovy 的范围语法的变化非常小。在经典的 Groovy 中，您可以通过使用 <code>...</code> 语法指明排他性（即上界）来避开这些变化。在 JSR Groovy 中，只要去掉最后一个点（<code>.</code>），并用直观的 <code>&lt;</code> 标识替代它即可。</p>
		<p> 请注意观察我在下面的清单 8 中对来自“Feeling Groovy”一文中的范围示例进行的改编：</p>
		<br />
		<br />
		<a name="code8">
				<b>清单 8. 新的范围语法</b>
		</a>
		<br />
		<table border="0" cellpadding="0" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td class="code-outline">
										<pre class="displaycode">myRange = 29..&lt;32<br />myInclusiveRange = 2..5<br />println myRange.size() // still prints 3<br />println myRange[0]   // still prints 29<br />println myRange.contains(32) //  still prints false<br />println myInclusiveRange.contains(5) // still prints true<br /></pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<br />
		<table border="0" cellpadding="0" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td>
										<img src="http://www.ibm.com/i/v14/rules/blue_rule.gif" alt="" height="1" width="100%" />
										<br />
										<img alt="" src="http://www.ibm.com/i/c.gif" border="0" height="6" width="8" />
								</td>
						</tr>
				</tbody>
		</table>
		<table class="no-print" align="right" cellpadding="0" cellspacing="0">
				<tbody>
						<tr align="right">
								<td>
										<img src="http://www.ibm.com/i/c.gif" alt="" height="4" width="100%" />
										<br />
										<br />
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<br />
		<p>
				<a name="N1021C">
						<span class="atitle">您是说存在歧义？</span>
				</a>
		</p>
		<p>您可能注意到，在使用 Groovy 时，有一项微妙的功能可以让您获得方法引用，并随意调用这个引用。可以将方法指针当作调用对象方法的方便机制。关于方法指针，有意思的事情是：它们的使用可能就表明代码违反了迪米特法则。</p>
		<p>您可能会问“什么是迪米特法则”呢？迪米特法则使用<i>只与直接朋友对话</i> 这句格言指出：我们应当避免调用由另一个对象方法返回的对象上的方法。例如，如果 <code>Foo</code> 对象公开了一个 <code>Bar</code> 对象类型，那么客户应当<i>通过 <code>Foo</code></i> 访问 <code>Bar </code> 的行为。结果可能是一些脆弱的代码，因为对某个对象的更改会传播到整个范围。 </p>
		<p>一位受尊敬的学者写了一篇优秀的文章，叫做“The Paperboy, the Wallet, and the Law of Demeter”（请参阅 <a href="http://www.ibm.com/developerworks/cn/java/j-pg07195.html#resources">参考资料</a>）。这篇文章中的示例是用 Java 语言编写的；但是，我在下面用 Groovy 重新定义了这些示例。在清单 9 中，可以看到这些代码演示了迪米特法则 —— 如何用它洗劫人们的钱包！</p>
		<br />
		<br />
		<a name="code9">
				<b>清单 9. 迪米特在行动（同情啊，同情！）</b>
		</a>
		<br />
		<table border="0" cellpadding="0" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td class="code-outline">
										<pre class="displaycode">package com.vanward.groovy<br />import java.math.BigDecimal<br />class Customer {<br /> @Property firstName<br /> @Property lastName<br /> @Property wallet<br />}<br />class Wallet {<br /> @Property value;<br /> def getTotalMoney() {<br />  return value;<br /> }<br /><br /> def setTotalMoney(newValue) {<br />  value = newValue;<br /> }<br /> def addMoney(deposit) {<br />  value = value.add(deposit)<br /> }<br /> def subtractMoney(debit) {<br />  value = value.subtract(debit)<br /> }<br />}<br /></pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>在清单 9 中，有两个定义的类型 —— 一个 <code>Customer</code> 和一个 <code>Wallet</code>。请注意 <code>Customer</code> 类型公开自己的 <code>wallet</code>
实例的方式。正如前面所说的，代码简单的公开方式存在问题。例如，如果我（像原文章的作者所做的那样）添加了一个坏报童，去抢劫那些不知情客户的钱包，又
会怎么样？在清单 10 中，我使用了 Groovy 的方法指针来做这件坏事。请注意我是如何使用 Groovy 新的 <code>&amp;</code> 方法指针语法，通过 <code>Customer</code> 实例夺取对 <code>subtractMoney</code> 方法的引用。</p>
		<br />
		<br />
		<a name="code10">
				<b>清单 10. 添加坏报童 ...</b>
		</a>
		<br />
		<table border="0" cellpadding="0" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td class="code-outline">
										<pre class="displaycode">iwallet = new Wallet(value:new BigDecimal(32))<br />victim = new Customer(firstName:"Lane", lastName:"Meyer", wallet:iwallet)<br />victim.getWallet().subtractMoney(new BigDecimal("0.10"))//Didn't *ask* for a dime. Two Dollars.<br />//paperboy turns evil by snatching a reference to the subtractMoney method<br />mymoney = victim.wallet.&amp;subtractMoney<br />mymoney(new BigDecimal(2)) // "I want my 2 dollars!"<br />mymoney(new BigDecimal(25)) // "late fees!"<br /></pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>现在，不要误会我：方法指针不是为了侵入代码或者获得对人们
现金的引用！方法指针只是一种方便的机制。方法指针也很适合于重新连接上您喜爱的 80
年代的老电影！但是，如果您把这些可爱的、漂亮的东西弄湿了，那么它们可就帮不上您的忙了。严格地说，可以把 Groovy 的 <code>println</code> 快捷方式当作 <code>System.out.println</code> 的隐式方法指针。</p>
		<p>如果一直都很留心，那么您可能已经注意到，JSR Groovy 要求我使用新的 <code>&amp;</code> 语法来创建 <code>subtractMoney</code> 方法的指针。您可能已经猜到，这个添加消除了经典 Groovy 中的歧义性。</p>
		<br />
		<table border="0" cellpadding="0" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td>
										<img src="http://www.ibm.com/i/v14/rules/blue_rule.gif" alt="" height="1" width="100%" />
										<br />
										<img alt="" src="http://www.ibm.com/i/c.gif" border="0" height="6" width="8" />
								</td>
						</tr>
				</tbody>
		</table>
		<table class="no-print" align="right" cellpadding="0" cellspacing="0">
				<tbody>
						<tr align="right">
								<td>
										<img src="http://www.ibm.com/i/c.gif" alt="" height="4" width="100%" />
										<br />
										<br />
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<br />
		<p>
				<a name="N10290">
						<span class="atitle">一些新东西！</span>
				</a>
		</p>
		<p>如果在 Groovy 的 JSR 发行版中没有什么<i>新东西</i>，那就没有意思了，不是吗？谢天谢地，JSR Groovy 引入了 <code>as</code> 关键字，它是一个方便的类型转换机制。这个特性与新的对象创建语法关系密切，新的语法可以用类似数组的语法很容易地在 Groovy 中创建<i>非定制</i> 类。所谓非定制，指的是在 JDK 中可以找到的类，例如 <code>Color</code>、<code>Point</code>、<code>File</code>，等等。</p>
		<p>在清单 11 中，我用这个新语法创建了一些简单类型：</p>
		<br />
		<br />
		<a name="code11">
				<b>清单 11. Groovy 中的新语法</b>
		</a>
		<br />
		<table border="0" cellpadding="0" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td class="code-outline">
										<pre class="displaycode">def nfile = ["c:/dev", "newfile.txt"] as File<br />def val = ["http", "www.vanwardtechnologies.com", "/"] as URL<br />def ival = ["89.90"] as BigDecimal<br />println ival as Float<br /></pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>注意，我用便捷语法创建了一个新 <code>File</code> 和 <code>URL</code>，还有 <code>BigDecimal</code> ，还要注意的是，我可以用 <code>as</code> 把 <code>BigDecimal</code> 类型转换成 <code>Float</code> 类型。</p>
		<br />
		<table border="0" cellpadding="0" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td>
										<img src="http://www.ibm.com/i/v14/rules/blue_rule.gif" alt="" height="1" width="100%" />
										<br />
										<img alt="" src="http://www.ibm.com/i/c.gif" border="0" height="6" width="8" />
								</td>
						</tr>
				</tbody>
		</table>
		<table class="no-print" align="right" cellpadding="0" cellspacing="0">
				<tbody>
						<tr align="right">
								<td>
										<img src="http://www.ibm.com/i/c.gif" alt="" height="4" width="100%" />
										<br />
										<br />
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<br />
		<p>
				<a name="N102D8">
						<span class="atitle">接下来是什么呢？</span>
				</a>
		</p>
		<p>JSR 对 Groovy 的规范化过程并没有结束，特别是在有些东西在 Groovy 的当前版本中（在本文发布时是 JSR-2）仍然不起作用的情况下。例如，在新的 Groovy 中，不能用 <code>do</code>/<code>while</code> 循环。此外，新的 Groovy 还无法完全支持 Java 5.0 的 <code>for</code> 循环概念。结果是，可以使用 <code>in</code> 语法，但是不能使用新推出的 <code>:</code> 语法。</p>
		<p>这些都是重要的特性，不能没有，但是不用担心 —— Groovy 小组正在努力工作，争取在未来几个月内实现它们。请参阅 <a href="http://www.ibm.com/developerworks/cn/java/j-pg07195.html#resources">参考资料</a>，下载最新的发行版本，并学习更多关于 JSR Groovy 进程的内容；还请继续关注下个月的“<i>实战 Groovy</i>”，下个月我（和两个客座专栏作家）将深入讨论 Groovy 闭包的更精彩的细节。</p>
		<br />
<img src ="http://www.blogjava.net/JafeLee/aggbug/128677.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/JafeLee/" target="_blank">Jafe</a> 2007-07-06 21:12 <a href="http://www.blogjava.net/JafeLee/articles/128677.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>实战 Groovy: 在 Java 应用程序中加一些 Groovy 进来</title><link>http://www.blogjava.net/JafeLee/articles/128676.html</link><dc:creator>Jafe</dc:creator><author>Jafe</author><pubDate>Fri, 06 Jul 2007 13:09:00 GMT</pubDate><guid>http://www.blogjava.net/JafeLee/articles/128676.html</guid><wfw:comment>http://www.blogjava.net/JafeLee/comments/128676.html</wfw:comment><comments>http://www.blogjava.net/JafeLee/articles/128676.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/JafeLee/comments/commentRss/128676.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/JafeLee/services/trackbacks/128676.html</trackback:ping><description><![CDATA[
		<div class="postText">
				<p>
						<a href="http://www.ibm.com/developerworks/cn/java/j-pg05245/#author">Andrew Glover</a> (<a href="mailto:aglover@vanwardtechnologies.com?subject=%E5%9C%A8%20Java%20%E5%BA%94%E7%94%A8%E7%A8%8B%E5%BA%8F%E4%B8%AD%E5%8A%A0%E4%B8%80%E4%BA%9B%20Groovy%20%E8%BF%9B%E6%9D%A5">aglover@vanwardtechnologies.com</a>), CTO, Vanward Technologies<br /></p>
				<p>2005 年  6 月  13 日</p>
				<blockquote>
您有没有想过在自己相对复杂的 Java 程序中嵌入 Groovy 简单的、易于编写的脚本呢？在这一期 <i>实战 Groovy</i> 系列文章中，Andrew Glover 将介绍把 Groovy 集成到 Java 代码中的多种方法，并解释在什么地方、什么时候适合这么做。</blockquote>
				<!--START RESERVED FOR FUTURE USE INCLUDE FILES-->
				<!-- include java script once we verify teams wants to use this and it will work on dbcs and cyrillic characters -->
				<!--END RESERVED FOR FUTURE USE INCLUDE FILES-->
				<p>如果您一直在阅读这个系列，那么您应该已经看到有各种各样使用 Groovy 的有趣方式，Groovy
的主要优势之一就是它的生产力。Groovy 代码通常要比 Java
代码更容易编写，而且编写起来也更快，这使得它有足够的资格成为开发工作包中的一个附件。在另一方面，正如我在这个系列中反复强调的那样，Groovy
并不是 —— 而且也不打算成为 —— Java 语言的替代。所以，这里存在的问题是，能否把 Groovy 集成到 Java
的编程实践中？或者说这样做有什么用？<i>什么时候</i> 这样做有用？</p>
				<p>这个月，我将尝试回答这个问题。我将从一些熟悉的事物开始，即从如何将 Groovy 脚本编译成与 Java 兼容的类文件开始，然后进一步仔细研究 Groovy 的编译工具（<code>groovyc</code>）是如何让这个奇迹实现的。了解 Groovy 在幕后做了什么是在 Java 代码中使用 Groovy 的第一步。</p>
				<p>注意，本月示例中演示的一些编程技术是 <code>Groovlets</code> 框架和 Groovy 的 <code>GroovyTestCase</code> 的核心，这些技术我在前面的文章中已经讨论过。 </p>
				<table align="right" border="0" cellpadding="0" cellspacing="0" width="40%">
						<tbody>
								<tr>
										<td width="10">
												<img alt="" src="http://www.ibm.com/i/c.gif" height="1" width="10" />
										</td>
										<td>
												<br />
										</td>
								</tr>
						</tbody>
				</table>
				<p>
						<a name="N1007B">
								<span class="atitle">天作之合？</span>
						</a>
				</p>
				<p>在本系列中以前的文章中，当我介绍如何 <a href="http://www.ibm.com/developerworks/java/library/j-pg11094/?S_TACT=105AGX52&amp;S_CMP=cn-a-j">用 Groovy 测试普通 Java 程序</a> 的时候，您可能已经注意到一些奇怪的事：我 <i>编译了</i> 那些 Groovy 脚本。实际上，我将 groovy 单元测试编译成普通的 Java .class 文件，然后把它们作为 Maven 构建的一部分来运行。</p>
				<p>这种编译是通过调用 <code>groovyc</code> 命令进行的，该命令将 Groovy 脚本编译成普通的 Java 兼容的 .class 文件。例如，如果脚本声明了一个类，那么调用 <code>groovyc</code> 会生成至少三个 .class 。文件本身会遵守标准的 Java 规则：.class 文件名称要和声明的类名匹配。
</p>
				<p>作为示例，请参见清单 1，它创建了一个简单的脚本，脚本声明了几个类。然后，您自己就可以看出 <code>groovyc</code> 命令生成的结果：</p>
				<br />
				<br />
				<a name="code1">
						<b>清单 1. Groovy 中的类声明和编译</b>
				</a>
				<br />
				<table border="0" cellpadding="0" cellspacing="0" width="100%">
						<tbody>
								<tr>
										<td class="code-outline">
												<pre class="displaycode">package com.vanward.groovy<br />class Person {<br />  fname<br />  lname<br />  age<br />  address<br />  contactNumbers<br />  String toString(){<br /><br />    numstr = new StringBuffer()<br />    if (contactNumbers != null){<br />     contactNumbers.each{<br />       numstr.append(it)<br />       numstr.append(" ")<br />     }<br />    }<br />    "first name: " + fname + " last name: " + lname + <br />    " age: " + age + " address: " + address + <br />    " contact numbers: " + numstr.toString()<br />  }<br />}<br />class Address {<br />  street1<br />  street2<br />  city<br />  state<br />  zip<br />  String toString(){<br />   "street1: " + street1 + " street2: " + street2 +<br />     " city: " + city + " state: " + state + " zip: " + zip<br />  }<br />}<br />class ContactNumber {<br />  type<br />  number<br />  String toString(){<br />   "Type: " + type + " number: " + number <br />  }<br />}<br />nums = [new ContactNumber(type:"cell", number:"555.555.9999"), <br />	new ContactNumber(type:"office", number:"555.555.5598")]<br />addr = new Address(street1:"89 Main St.", street2:"Apt #2", <br />	city:"Utopia", state:"VA", zip:"34254")<br />pers = new Person(fname:"Mollie", lname:"Smith", age:34, <br />	address:addr, contactNumbers:nums)<br />println pers.toString()<br /></pre>
										</td>
								</tr>
						</tbody>
				</table>
				<br />
				<p>在清单 1 中，我声明了三个类 —— <code>Person</code>、<code>Address</code> 和 <code>ContactNumber</code>。之后的代码根据这些新定义的类型创建对象，然后调用 <code>toString()</code> 方法。迄今为止，Groovy 中的代码还非常简单，但现在来看一下清单 2 中 <code>groovyc</code> 产生什么样的结果：</p>
				<br />
				<br />
				<a name="code2">
						<b>清单 2. groovyc 命令生成的类</b>
				</a>
				<br />
				<table border="0" cellpadding="0" cellspacing="0" width="100%">
						<tbody>
								<tr>
										<td class="code-outline">
												<pre class="displaycode">aglover@12d21 /cygdrive/c/dev/project/target/classes/com/vanward/groovy<br />$ ls -ls  <br />total 15<br /> 4 -rwxrwxrwx+ 1 aglover  user   3317 May  3 21:12 Address.class<br /> 3 -rwxrwxrwx+ 1 aglover  user   3061 May  3 21:12 BusinessObjects.class<br /> 3 -rwxrwxrwx+ 1 aglover  user   2815 May  3 21:12 ContactNumber.class<br /> 1 -rwxrwxrwx+ 1 aglover  user   1003 May  3 21:12 <br />   Person$_toString_closure1.class<br /> 4 -rwxrwxrwx+ 1 aglover  user   4055 May  3 21:12 Person.class<br /></pre>
										</td>
								</tr>
						</tbody>
				</table>
				<br />
				<p>哇！<i>五个</i> .class 文件！我们了解 <code>Person</code>、<code>Address</code> 和 <code>ContactNumber</code> 文件的意义，但是其他两个文件有什么作用呢？</p>
				<p>研究发现，<code>Person$_toString_closure1.class</code> 是 <code>Person</code> 类的
<code>toString()</code> 方法中发现的闭包的结果。它是 <code>Person</code> 的一个内部类，但是 
<code>BusinessObjects.class</code> 文件是怎么回事 —— 它可能是什么呢？</p>
				<p>对 <a href="http://www.ibm.com/developerworks/cn/java/j-pg05245/#code1">清单 1</a> 的深入观察指出：我在脚本主体中编写的代码（声明完三个类之后的代码）变成一个 .class 文件，它的名称采用的是脚本名称。在这个例子中，脚本被命名为 <code>BusinessObjects.groovy</code>，所以，类定义中没有包含的代码被编译到一个名为 <code>BusinessObjects</code> 的  .class 文件。</p>
				<p>
						<a name="N10102">
								<span class="smalltitle">反编译</span>
						</a>
				</p>
				<p>反编译这些类可能会非常有趣。由于 Groovy 处于代码顶层，所以生成的 .java 文件可能相当巨大；不过，您应当注意的是 Groovy 脚本中声明的类（如 <code>Person</code>） 与类之外的代码（比如 <code>BusinessObjects.class</code> 中找到的代码）之间的区别。在
Groovy 文件中定义的类完成了 <code>GroovyObject</code> 的实现，而在类之外定义的代码则被绑定到一个扩展自 <code>Script</code> 的类。 </p>
				<p> 例如，如果研究由 BusinessObjects.class 生成的 .java 文件，可以发现：它定义了一个
<code>main()</code> 方法和一个 <code>run()</code> 方法。不用惊讶， <code>run()</code> 方法包含我编写的、用来创建这些对象的新实例的代码，而 <code>main()</code> 方法则调用  <code>run()</code> 方法。</p>
				<p>这个细节的全部要点再一次回到了：对 Groovy 的理解越好，就越容易把它集成到 Java 程序中。有人也许会问：“为什么我要这么做呢？”好了，我们想说您用 Groovy 开发了一些很酷的东西；那么如果能把这些东西集成到 Java 程序中，那不是很好吗？ </p>
				<p>只是为了讨论的原因，我首先<i>试图</i> 用 Groovy 创建一些有用的东西，然后我再介绍把它嵌入到普通 Java 程序中的各种方法。</p>
				<br />
				<table border="0" cellpadding="0" cellspacing="0" width="100%">
						<tbody>
								<tr>
										<td>
												<img src="http://www.ibm.com/i/v14/rules/blue_rule.gif" alt="" height="1" width="100%" />
												<br />
												<img alt="" src="http://www.ibm.com/i/c.gif" border="0" height="6" width="8" />
										</td>
								</tr>
						</tbody>
				</table>
				<table class="no-print" align="right" cellpadding="0" cellspacing="0">
						<tbody>
								<tr align="right">
										<td>
												<img src="http://www.ibm.com/i/c.gif" alt="" height="4" width="100%" />
												<br />
												<br />
										</td>
								</tr>
						</tbody>
				</table>
				<br />
				<br />
				<p>
						<a name="N1013B">
								<span class="atitle">再制作一个音乐 Groovy</span>
						</a>
				</p>
				<p> 我热爱音乐。实际上，我的 CD 收藏超过了我计算机图书的收藏。多年以来，我把我的音乐截取到不同的计算机上，在这个过程中，我的 MP3 收藏乱到了这样一种层度：只是表示品种丰富的音乐目录就有一大堆。</p>
				<p>最近，为了让我的音乐收藏回归有序，我采取了第一步行动。我编写了一个快速的 Groovy 脚本，在某个目录的 MP3 收藏上进行迭代，然后把每个文件的详细信息（例如艺术家、专辑名称等）提供给我。脚本如清单 3 所示：</p>
				<br />
				<br />
				<a name="code3">
						<b>清单 3. 一个非常有用的 Groovy 脚本</b>
				</a>
				<br />
				<table border="0" cellpadding="0" cellspacing="0" width="100%">
						<tbody>
								<tr>
										<td class="code-outline">
												<pre class="displaycode">package com.vanward.groovy<br />import org.farng.mp3.MP3File<br />import groovy.util.AntBuilder<br />class Song {<br /><br />  mp3file<br />  Song(String mp3name){   <br />    mp3file = new MP3File(mp3name)   <br />  }<br />  getTitle(){<br />    mp3file.getID3v1Tag().getTitle()<br />  }<br />  getAlbum(){<br />    mp3file.getID3v1Tag().getAlbum()<br />  }<br />  getArtist(){<br />    mp3file.getID3v1Tag().getArtist()<br />  }<br />  String toString(){<br />    "Artist: " + getArtist() + " Album: " + <br />      getAlbum() + " Song: " + getTitle()<br />  }<br />  static getSongsForDirectory(sdir){<br />    println "sdir is: " + sdir<br />    ant = new AntBuilder()<br />    scanner = ant.fileScanner {<br />       fileset(dir:sdir) {<br />         include(name:"**/*.mp3")<br />       }<br />    }<br />    songs = []<br />    for(f in scanner){   <br />      songs &lt;&lt; new Song(f.getAbsolutePath())   <br />    }<br />    return songs<br />  }<br />}<br />songs = Song.getSongsForDirectory(args[0])<br />songs.each{<br /> println it<br />}<br /></pre>
										</td>
								</tr>
						</tbody>
				</table>
				<br />
				<p>正如您所看到的，脚本非常简单，对于像我这样的人来说特别有用。而我要做的全部工作只是把某个具体的目录名传递给它，然后我就会得到该目录中每个 MP3 文件的相关信息（艺术家名称、歌曲名称和专辑） 。</p>
				<p>现在让我们来看看，如果要把这个干净的脚本集成到一个能够通过数据库组织音乐甚至播放 MP3 的普通 Java 程序中，我需要做些什么。</p>
				<br />
				<table border="0" cellpadding="0" cellspacing="0" width="100%">
						<tbody>
								<tr>
										<td>
												<img src="http://www.ibm.com/i/v14/rules/blue_rule.gif" alt="" height="1" width="100%" />
												<br />
												<img alt="" src="http://www.ibm.com/i/c.gif" border="0" height="6" width="8" />
										</td>
								</tr>
						</tbody>
				</table>
				<table class="no-print" align="right" cellpadding="0" cellspacing="0">
						<tbody>
								<tr align="right">
										<td>
												<img src="http://www.ibm.com/i/c.gif" alt="" height="4" width="100%" />
												<br />
												<br />
										</td>
								</tr>
						</tbody>
				</table>
				<br />
				<br />
				<p>
						<a name="N10158">
								<span class="atitle">Class 文件是类文件</span>
						</a>
				</p>
				<p>正如前面讨论过的，我的第一个选项可能只是用 <code>groovyc</code> 编译脚本。在这个例子中，我期望 <code>groovyc</code> 创建 <i>至少</i> 两个
.class 文件 —— 一个用于 <code>Song</code> 类，另一个用于 <code>Song</code> 声明之后的脚本代码。</p>
				<p>实际上，<code>groovyc</code> 可能创建 5 个 .class 文件。这是与 <code>Songs.groovy</code> 包含三个闭包有关，两个闭包在 <code>getSongsForDirectory()</code> 方法中，另一个在脚本体中，我在脚本体中对 <code>Song</code> 的集合进行迭代，并调用 <code>println</code>。</p>
				<p>因为 .class 文件中有三个实际上是 Song.class 和 Songs.class 的内部类，所以我只需要把注意力放在两个 .class 文件上。Song.class 直接映射到 Groovy 脚本中的 <code>Song</code> 声明，并实现了 <code>GroovyObject</code>，而 Songs.class 则代表我在定义 <code>Song</code> 之后编写的代码，所以也扩展了 <code>Script</code>。</p>
				<p> 此时此刻，关于如何把新编译的 Groovy 代码集成到 Java 代码，我有两个选择：可以通过 Songs.class 文件中的 <code>main()</code> 方法运行代码 （因为它扩展了 <code>Script</code>），或者可以将 Song.class 包含到类路径中，就像在 Java 代码中使用其他对象一样使用它。 </p>
				<br />
				<table border="0" cellpadding="0" cellspacing="0" width="100%">
						<tbody>
								<tr>
										<td>
												<img src="http://www.ibm.com/i/v14/rules/blue_rule.gif" alt="" height="1" width="100%" />
												<br />
												<img alt="" src="http://www.ibm.com/i/c.gif" border="0" height="6" width="8" />
										</td>
								</tr>
						</tbody>
				</table>
				<br />
				<br />
				<p>
						<a name="N101A9">
								<span class="atitle">变得更容易些</span>
						</a>
				</p>
				<p>通过 <code>java</code> 命令调用 Songs.class 文件非常简单，只要您记得把 Groovy 相关的依赖关系和
Groovy 脚本需要的依赖关系包含进来就可以。把 Groovy 需要的类全都包含进来的最简单方法就是把包含全部内容的 Groovy 可嵌入
jar 文件添加到类路径中。在我的例子中，这个文件是 groovy-all-1.0-beta-10.jar。要运行
Songs.class，需要记得包含将要用到的 MP3 库（jid3lib-0.5.jar&gt;），而且因为我使用 <code>AntBuilder</code>，所以我还需要在类路径中包含 <code>Ant</code>。清单 4 把这些放在了一起：</p>
				<br />
				<br />
				<a name="code4">
						<b>清单 4. 通过 Java 命令行调用 Groovy</b>
				</a>
				<br />
				<table border="0" cellpadding="0" cellspacing="0" width="100%">
						<tbody>
								<tr>
										<td class="code-outline">
												<pre class="displaycode">c:\dev\projects&gt;java -cp  ./target/classes/;c:/dev/tools/groovy/<br />  groovy-all-1.0-beta-10.jar;C:/dev/tools/groovy/ant-1.6.2.jar;<br />  C:/dev/projects-2.0/jid3lib-0.5.jar  <br />  com.vanward.groovy.Songs c:\dev09\music\mp3s<br />Artist: U2 Album: Zooropa Song: Babyface<br />Artist: James Taylor Album: Greatest Hits Song: Carolina in My Mind<br />Artist: James Taylor Album: Greatest Hits Song: Fire and Rain<br />Artist: U2 Album: Zooropa Song: Lemon<br />Artist: James Taylor Album: Greatest Hits Song: Country Road<br />Artist: James Taylor Album: Greatest Hits Song: Don't Let Me <br />  Be Lonely Tonight<br />Artist: U2 Album: Zooropa Song: Some Days Are Better Than Others<br />Artist: Paul Simon Album: Graceland Song: Under African Skies<br />Artist: Paul Simon Album: Graceland Song: Homeless<br />Artist: U2 Album: Zooropa Song: Dirty Day<br />Artist: Paul Simon Album: Graceland Song: That Was Your Mother<br /></pre>
										</td>
								</tr>
						</tbody>
				</table>
				<br />
				<br />
				<table border="0" cellpadding="0" cellspacing="0" width="100%">
						<tbody>
								<tr>
										<td>
												<img src="http://www.ibm.com/i/v14/rules/blue_rule.gif" alt="" height="1" width="100%" />
												<br />
												<img alt="" src="http://www.ibm.com/i/c.gif" border="0" height="6" width="8" />
										</td>
								</tr>
						</tbody>
				</table>
				<table class="no-print" align="right" cellpadding="0" cellspacing="0">
						<tbody>
								<tr align="right">
										<td>
												<img src="http://www.ibm.com/i/c.gif" alt="" height="4" width="100%" />
												<br />
												<br />
										</td>
								</tr>
						</tbody>
				</table>
				<br />
				<br />
				<p>
						<a name="N101C9">
								<span class="atitle">把 Groovy 嵌入 Java 代码</span>
						</a>
				</p>
				<p>虽然命令行的解决方案简单有趣，但它并不是所有问题的最终解决方案。如果对更高层次的完善感兴趣，那么可能将 MP3 歌曲工具直接导入
Java 程序。在这个例子中，我想导入 Song.class ，并像在 Java 语言中使用其他类那样使用它。类路径的问题与上面相同
：我需要确保包含了 <i>uber-Groovy</i>
jar 文件、<code>Ant</code> 和 jid3lib-0.5.jar 文件。在清单 5 中，可以看到如何将 Groovy MP3 工具导入简单的 Java 类中：</p>
				<br />
				<br />
				<a name="code5">
						<b>清单 5. 嵌入的 Groovy 代码</b>
				</a>
				<br />
				<table border="0" cellpadding="0" cellspacing="0" width="100%">
						<tbody>
								<tr>
										<td class="code-outline">
												<pre class="displaycode">package com.vanward.gembed;<br />import com.vanward.groovy.Song;<br />import java.util.Collection;<br />import java.util.Iterator;<br />public class SongEmbedGroovy{<br /> public static void main(String args[]) {<br />  Collection coll = (Collection)Song.getSongsForDirectory<br />    ("C:\\music\\temp\\mp3s");<br />  for(Iterator it = coll.iterator(); it.hasNext();){<br />    System.out.println(it.next());<br />  }	<br /> }<br />}<br /></pre>
										</td>
								</tr>
						</tbody>
				</table>
				<br />
				<br />
				<table border="0" cellpadding="0" cellspacing="0" width="100%">
						<tbody>
								<tr>
										<td>
												<img src="http://www.ibm.com/i/v14/rules/blue_rule.gif" alt="" height="1" width="100%" />
												<br />
												<img alt="" src="http://www.ibm.com/i/c.gif" border="0" height="6" width="8" />
										</td>
								</tr>
						</tbody>
				</table>
				<table class="no-print" align="right" cellpadding="0" cellspacing="0">
						<tbody>
								<tr align="right">
										<td>
												<img src="http://www.ibm.com/i/c.gif" alt="" height="4" width="100%" />
												<br />
												<br />
										</td>
								</tr>
						</tbody>
				</table>
				<br />
				<br />
				<p>
						<a name="N101E4">
								<span class="atitle">Groovy 类加载器</span>
						</a>
				</p>
				<p>就在您以为自己已经掌握全部的时候，我要告诉您的是，还有更多在 Java 语言中使用 Groovy 的方法。除了通过直接编译把 Groovy 脚本集成到 Java 程序中的这个选择之外，当我想直接嵌入脚本时，还有其他一些选择。</p>
				<p>例如，我可以用 Groovy 的 <code>GroovyClassLoader</code> ，<i>动态地</i> 加载一个脚本并执行它的行为，如清单 6 所示：</p>
				<br />
				<br />
				<a name="code6">
						<b>清单 6. GroovyClassLoader 动态地加载并执行 Groovy 脚本</b>
				</a>
				<br />
				<table border="0" cellpadding="0" cellspacing="0" width="100%">
						<tbody>
								<tr>
										<td class="code-outline">
												<pre class="displaycode">package com.vanward.gembed;<br />import groovy.lang.GroovyClassLoader;<br />import groovy.lang.GroovyObject;<br />import groovy.lang.MetaMethod;<br />import java.io.File;<br />public class CLEmbedGroovy{<br /> public static void main(String args[]) throws Throwable{<br /><br />  ClassLoader parent = CLEmbedGroovy.class.getClassLoader();<br />  GroovyClassLoader loader = new GroovyClassLoader(parent);<br /><br />  Class groovyClass = loader.parseClass(<br />    new File("C:\\dev\\groovy-embed\\src\\groovy\\<br />      com\\vanward\\groovy\\Songs.groovy"));<br /><br />  GroovyObject groovyObject = (GroovyObject) <br />    groovyClass.newInstance();<br /><br />  Object[] path = {"C:\\music\\temp\\mp3s"};<br />  groovyObject.setProperty("args", path);<br />  Object[] argz = {};<br /><br />  groovyObject.invokeMethod("run", argz);<br /><br /> }<br />}<br /></pre>
										</td>
								</tr>
						</tbody>
				</table>
				<br />
				<table align="right" border="0" cellpadding="0" cellspacing="0" width="40%">
						<tbody>
								<tr>
										<td width="10">
												<img alt="" src="http://www.ibm.com/i/c.gif" height="1" width="10" />
										</td>
										<td>
												<table border="1" cellpadding="5" cellspacing="0" width="100%">
														<tbody>
																<tr>
																		<td bgcolor="#eeeeee">
																				<a name="N10204">
																						<b>Meta，宝贝</b>
																				</a>
																				<br />
																				<p> 如果您属于那群疯狂的人中的一员，热爱反射，喜欢利用它们能做的精彩事情，那么您将热衷于 Groovy 的 <code>Meta</code> 类。就像反射一样，使用这些类，您可以发现 <code>GroovyObject</code> 的各个方面（例如它的方法），这样就可以实际地 <i>创建</i> 新的行为并执行它。而且，这是 Groovy 的核心 —— 想想运行脚本时它将如何发威吧！</p>
																		</td>
																</tr>
														</tbody>
												</table>
										</td>
								</tr>
						</tbody>
				</table>
				<p>注意，默认情况下，类加载器将加载与脚本名称对应的类 —— 在这个例子中是 Songs.class，而<i>不是</i> Song.class&gt;。因为我（和您）知道 Songs.class 扩展了 Groovy 的 Script 类，所以不用想也知道接下来要做的就是执行 <code>run()</code> 方法。</p>
				<p>您记起，我的 Groovy 脚本也依赖于运行时参数。所以，我需要恰当地配置 <code>args</code> 变量，在这个例子中，我把第一个元素设置为目录名。</p>
				<br />
				<br />
				<br />
				<br />
				<br />
				<table border="0" cellpadding="0" cellspacing="0" width="100%">
						<tbody>
								<tr>
										<td>
												<img src="http://www.ibm.com/i/v14/rules/blue_rule.gif" alt="" height="1" width="100%" />
												<br />
												<img alt="" src="http://www.ibm.com/i/c.gif" border="0" height="6" width="8" />
										</td>
								</tr>
						</tbody>
				</table>
				<table class="no-print" align="right" cellpadding="0" cellspacing="0">
						<tbody>
								<tr align="right">
										<td>
												<img src="http://www.ibm.com/i/c.gif" alt="" height="4" width="100%" />
												<br />
												<br />
										</td>
								</tr>
						</tbody>
				</table>
				<br />
				<br />
				<p>
						<a name="N1022A">
								<span class="atitle">更加动态的选择</span>
						</a>
				</p>
				<p>对于使用编译好的类，而且，通过类加载器来动态加载 
<code>GroovyObject</code> 的替代，是使用 Groovy 优美的 <code>GroovyScriptEngine</code> 和 <code>GroovyShell</code> 动态地执行 Groovy 脚本。 </p>
				<p>把 <code>GroovyShell</code> 对象嵌入普通  Java 类，可以像类加载器所做的那样动态执行 Groovy 脚本。除此之外，它还提供了大量关于控制脚本运行的选项。在清单 7 中，可以看到 <code>GroovyShell</code> 嵌入到普通 Java 类的方式：</p>
				<br />
				<br />
				<a name="code7">
						<b>清单 7. 嵌入 GroovyShell</b>
				</a>
				<br />
				<table border="0" cellpadding="0" cellspacing="0" width="100%">
						<tbody>
								<tr>
										<td class="code-outline">
												<pre class="displaycode">package com.vanward.gembed;<br />import java.io.File;<br />import groovy.lang.GroovyShell;<br />public class ShellRunEmbedGroovy{<br /> public static void main(String args[]) throws Throwable{<br /><br />  String[] path = {"C:\\music\\temp\\mp3s"};		<br />  GroovyShell shell = new GroovyShell();<br />  shell.run(new File("C:\\dev\\groovy-embed\\src\\groovy\\<br />    com\\vanward\\groovy\\Songs.groovy"), <br />    path);<br /> }<br />}<br /></pre>
										</td>
								</tr>
						</tbody>
				</table>
				<br />
				<p> 可以看到，运行 Groovy 脚本非常容易。我只是创建了 <code>GroovyShell</code> 的实例，传递进脚本名称，然后调用 <code>run()</code> 方法。</p>
				<p>还可以做其他事情。如果您喜欢，那么也可以得到自己脚本的 <code>Script</code> 类型的 <code>GroovyShell</code> 实例。使用 <code>Script</code> 类型，您就可以传递进一个 <code>Binding</code> 对象，其中包含任何运行时值，然后再继续调用  <code>run()</code> 方法，如清单 8 所示：</p>
				<br />
				<br />
				<a name="code8">
						<b>清单 8. 有趣的 GroovyShell</b>
				</a>
				<br />
				<table border="0" cellpadding="0" cellspacing="0" width="100%">
						<tbody>
								<tr>
										<td class="code-outline">
												<pre class="displaycode">package com.vanward.gembed;<br />import java.io.File;<br />import groovy.lang.Binding;<br />import groovy.lang.GroovyShell;<br />import groovy.lang.Script;<br />public class ShellParseEmbedGroovy{<br /> public static void main(String args[]) throws Throwable{<br />  GroovyShell shell = new GroovyShell();<br />  Script scrpt = shell.parse(<br />    new File("C:\\dev\\groovy-embed\\src\\groovy\\<br />      com\\vanward\\groovy\\Songs.groovy"));<br /><br />  Binding binding = new Binding();<br />  Object[] path = {"C:\\music\\temp\\mp3s"};<br />  binding.setVariable("args",path);			<br />  scrpt.setBinding(binding);<br /><br />  scrpt.run();<br /> }<br />}<br /></pre>
										</td>
								</tr>
						</tbody>
				</table>
				<br />
				<br />
				<table border="0" cellpadding="0" cellspacing="0" width="100%">
						<tbody>
								<tr>
										<td>
												<img src="http://www.ibm.com/i/v14/rules/blue_rule.gif" alt="" height="1" width="100%" />
												<br />
												<img alt="" src="http://www.ibm.com/i/c.gif" border="0" height="6" width="8" />
										</td>
								</tr>
						</tbody>
				</table>
				<table class="no-print" align="right" cellpadding="0" cellspacing="0">
						<tbody>
								<tr align="right">
										<td>
												<img src="http://www.ibm.com/i/c.gif" alt="" height="4" width="100%" />
												<br />
												<br />
										</td>
								</tr>
						</tbody>
				</table>
				<br />
				<br />
				<p>
						<a name="N10282">
								<span class="atitle">Groovy 的脚本引擎</span>
						</a>
				</p>
				<p>
						<code>GroovyScriptEngine</code> 对象动态运行脚本的时候，非常像 <code>GroovyShell</code>。区别在于：对于 <code>GroovyScriptEngine</code>，您可以在实例化的时候给它提供一系列目录，然后让它根据要求去执行多个脚本，如清单 9 所示：</p>
				<br />
				<br />
				<a name="code9">
						<b>清单 9. GroovyScriptEngine 的作用</b>
				</a>
				<br />
				<table border="0" cellpadding="0" cellspacing="0" width="100%">
						<tbody>
								<tr>
										<td class="code-outline">
												<pre class="displaycode">package com.vanward.gembed;<br />import java.io.File;<br />import groovy.lang.Binding;<br />import groovy.util.GroovyScriptEngine;<br />public class ScriptEngineEmbedGroovy{<br /> public static void main(String args[]) throws Throwable{<br /><br />  String[] paths = {"C:\\dev\\groovy-embed\\src\\groovy\\<br />    com\\vanward\\groovy"};<br />  GroovyScriptEngine gse = new GroovyScriptEngine(paths);<br />  Binding binding = new Binding();<br />  Object[] path = {"C:\\music\\temp\\mp3s"};<br />  binding.setVariable("args",path);<br /><br />  gse.run("Songs.groovy", binding);<br />  gse.run("BusinessObjects.groovy", binding);<br /> }<br />}<br /></pre>
										</td>
								</tr>
						</tbody>
				</table>
				<br />
				<p>在清单 9 中，我向实例化的 <code>GroovyScriptEngine</code> 传入了一个数组，数据中包含我要处理的路径，然后创建大家熟悉的 <code>Binding</code> 对象，然后再执行仍然很熟悉的 <code>Songs.groovy</code> 脚本。只是为了好玩，我还执行了<code>BusinessObjects.groovy</code> 脚本，您或许还能回忆起来，它在开始这次讨论的时候出现过。</p>
				<br />
				<table border="0" cellpadding="0" cellspacing="0" width="100%">
						<tbody>
								<tr>
										<td>
												<img src="http://www.ibm.com/i/v14/rules/blue_rule.gif" alt="" height="1" width="100%" />
												<br />
												<img alt="" src="http://www.ibm.com/i/c.gif" border="0" height="6" width="8" />
										</td>
								</tr>
						</tbody>
				</table>
				<table class="no-print" align="right" cellpadding="0" cellspacing="0">
						<tbody>
								<tr align="right">
										<td>
												<img src="http://www.ibm.com/i/c.gif" alt="" height="4" width="100%" />
												<br />
												<br />
										</td>
								</tr>
						</tbody>
				</table>
				<br />
				<br />
				<p>
						<a name="N102B5">
								<span class="atitle">Bean 脚本框架</span>
						</a>
				</p>
				<p> 最后，当然并不是最不重要的，是来自 Jakarta 的古老的 Bean 脚本框架（ Bean Scripting
Framework  —— BSF）。BSF 试图提供一个公共的 API，用来在普通 Java 应用程序中嵌入各种脚本语言（包括 Groovy）。这个标准的、但是有争议的最小公因子方法，可以让您毫不费力地将 Java 应用程序嵌入 Groovy 脚本。</p>
				<p> 还记得前面的 <code>BusinessObjects</code> 脚本吗？在清单 10 中，可以看到 BSF 可以多么容易地让我把这个脚本插入普通 Java 程序中：</p>
				<br />
				<br />
				<a name="code10">
						<b>清单 10. BSF 开始工作了</b>
				</a>
				<br />
				<table border="0" cellpadding="0" cellspacing="0" width="100%">
						<tbody>
								<tr>
										<td class="code-outline">
												<pre class="displaycode">package com.vanward.gembed;<br />import org.apache.bsf.BSFManager;<br />import org.codehaus.groovy.runtime.DefaultGroovyMethods;<br />import java.io.File;<br />import groovy.lang.Binding;<br />public class BSFEmbedGroovy{<br /> public static void main(String args[]) throws Exception {<br />  String fileName = "C:\\dev\\project\\src\\groovy\\<br />    com\\vanward\\groovy\\BusinessObjects.groovy";<br />  //this is required for bsf-2.3.0<br />  //the "groovy" and "gy" are extensions<br />  BSFManager.registerScriptingEngine("groovy", <br />    "org.codehaus.groovy.bsf.GroovyEngine", new <br />      String[] { "groovy" });<br />  BSFManager manager = new BSFManager();<br />  //DefaultGroovyMethods.getText just returns a <br />  //string representation of the contents of the file<br />  manager.exec("groovy", fileName, 0, 0, <br />    DefaultGroovyMethods.getText(new File(fileName)));<br />  }<br />}<br /></pre>
										</td>
								</tr>
						</tbody>
				</table>
				<br />
				<br />
				<table border="0" cellpadding="0" cellspacing="0" width="100%">
						<tbody>
								<tr>
										<td>
												<img src="http://www.ibm.com/i/v14/rules/blue_rule.gif" alt="" height="1" width="100%" />
												<br />
												<img alt="" src="http://www.ibm.com/i/c.gif" border="0" height="6" width="8" />
										</td>
								</tr>
						</tbody>
				</table>
				<table class="no-print" align="right" cellpadding="0" cellspacing="0">
						<tbody>
								<tr align="right">
										<td>
												<img src="http://www.ibm.com/i/c.gif" alt="" height="4" width="100%" />
												<br />
												<br />
										</td>
								</tr>
						</tbody>
				</table>
				<br />
				<br />
				<p>
						<a name="N102D0">
								<span class="atitle">结束语</span>
						</a>
				</p>
				<p>如果在本文中有一件事是清楚的话，那么只件事就是 Groovy 为了 Java 代码内部的重用提供了一堆选择。从把 Groovy
脚本编译成普通 Java .class 文件，到动态地加载和运行脚本，这些问题需要考虑的一些关键方面是灵活性和耦合。把 Groovy
脚本编译成普通 .class 文件是 <i>使用</i> 您打算嵌入的功能的最简单选择，但是动态加载脚本可以使添加或修改脚本的行为变得更容易，同时还不必在编译上牺牲时间。（当然，这个选项只是在接口不变的情况下才有用。）</p>
				<p>把脚本语言嵌入普通 Java 不是每天都发生，但是机会确实不断出现。这里提供的示例把一个简单的目录搜索工具嵌入到基于 Java 的应用程序中，这样 Java 应用程序就可以很容易地变成 MP3 播放程序或者其他 MP3 播放工具。虽然我 <i>可以</i> 用 Java 代码重新编写 MP3 文件搜索器，但是我不需要这么做：Groovy 极好地兼容 Java 语言，而且，我很有兴趣去摆弄所有选项！</p>
		</div>
<img src ="http://www.blogjava.net/JafeLee/aggbug/128676.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/JafeLee/" target="_blank">Jafe</a> 2007-07-06 21:09 <a href="http://www.blogjava.net/JafeLee/articles/128676.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>实战 Groovy: 用 Groovy 生成器作标记</title><link>http://www.blogjava.net/JafeLee/articles/128674.html</link><dc:creator>Jafe</dc:creator><author>Jafe</author><pubDate>Fri, 06 Jul 2007 13:06:00 GMT</pubDate><guid>http://www.blogjava.net/JafeLee/articles/128674.html</guid><wfw:comment>http://www.blogjava.net/JafeLee/comments/128674.html</wfw:comment><comments>http://www.blogjava.net/JafeLee/articles/128674.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/JafeLee/comments/commentRss/128674.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/JafeLee/services/trackbacks/128674.html</trackback:ping><description><![CDATA[
		<p>
				<a href="http://www.ibm.com/developerworks/cn/java/j-pg04125/#author">Andrew Glover</a> (<a href="mailto:aglover@vanwardtechnologies.com?subject=%E7%94%A8%20Groovy%20%E7%94%9F%E6%88%90%E5%99%A8%E4%BD%9C%E6%A0%87%E8%AE%B0">aglover@vanwardtechnologies.com</a>), CTO, Vanward Technologies<br /></p>
		<p>2005 年  4 月  12 日</p>
		<blockquote>Groovy 生成器让您能够利用诸如 Swing 这样的框架来模拟标记语言（如 XML、HTML、Ant） 任务以及 GUI。它们对于快速原型化非常有
用，并且正像 Andrew Glover 这个月在“<i>实战 Groovy</i>”专栏中向您展示的那样，当您马上需要可消费的标记时，它们是数据绑定框架的一种便利的替代方案。</blockquote>
		<!--START RESERVED FOR FUTURE USE INCLUDE FILES-->
		<!-- include java script once we verify teams wants to use this and it will work on dbcs and cyrillic characters -->
		<!--END RESERVED FOR FUTURE USE INCLUDE FILES-->
		<p>几个月前，当我最初撰写有关 <a href="http://www.ibm.com/developerworks/cn/java/j-pg12144.html">实战 Groovy: 用 Groovy 进行 Ant 脚本编程</a> 的文章时，我提及了 Groovy 中的<i>生成器</i> 概念。在那篇文章里，我向您展示了，使用一个叫做 <code>AntBuilder</code> 的 
Groovy 类，构建富有表现力的 Ant 构建文件是多么容易。本文中，我将深入 Groovy 生成器的世界，向您展示您还能用这些强大的类做些什么。</p>
		<p>
				<a name="N10061">
						<span class="atitle">用生成器进行构建</span>
				</a>
		</p>
		<p>Groovy 生成器让您能够利用诸如 Swing 这样的框架来模拟标记语言（如 XML、HTML、Ant） 任务以及 GUI。使用生成器，您可以迅速地创
建复杂的标记（如 XML），而无须理会 XML 本身。</p>
		<p>生成器的范例非常简单。生成器的实例的方法表示该标记（如 HTML 中的 <code>&lt;body&gt;</code> 标
签）的元素。方法的创建于闭包中的对象表示子节点（例如，<code>&lt;body&gt;</code> 标签中所包含的 <code>&lt;p&gt;</code> 标签）。</p>
		<p>为了便于您查看这一过程，我将创建一个简单的生成器，以程序方式来表示一个具有清单 1 所示结构的 XML 文档。</p>
		<br />
		<br />
		<br />
		<br />
		<br />
		<a name="code1">
				<b>清单 1. 简单 XML 结构</b>
		</a>
		<br />
		<table border="0" cellpadding="0" cellspacing="0" width="600">
				<tbody>
						<tr>
								<td class="code-outline">
										<pre class="displaycode"> &lt;person&gt;<br />   &lt;name first="Megan" last="Smith"&gt;<br />     &lt;age&gt;32&lt;/age&gt;<br />     &lt;gender&gt;female&lt;/gender&gt;<br />   &lt;/name&gt;<br />   &lt;friends&gt;<br />     &lt;friend&gt;Julie&lt;/friend&gt;<br />     &lt;friend&gt;Joe&lt;/friend&gt;<br />     &lt;friend&gt;Hannah&lt;/friend&gt;<br />   &lt;/friends&gt;<br /> &lt;/person&gt;<br /></pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>要表示这个结构非常简单。首先将 <code>person</code> 方法连接到生成器实例，现在它表示 XML 的根节点，即 <code>&lt;person&gt;</code>。要创建子节点，我创建一个闭包并声明一个名叫 <code>name</code> 的新对象（它接收 <code>map</code> 形式的参数。顺便说一下，这些参数是元素的属性的基础。</p>
		<p>接下来，在 <code>name</code> 对象中，将两个附加对象连接到闭包，一个对象是 <code>age</code>，另
一个是 <code>gender</code>，它们对应于 <code>&lt;name&gt;</code> 的类似子元素。您明白其中的诀窍了么？确实很简单。</p>
		<p>
				<code>&lt;friends&gt;</code> 元素是 <code>&lt;person&gt;</code> 的兄弟元素，于是我跳出这个闭包，声明了一个 <code>friends</code> 对象，当然，还附加了一个集合了多个 <code>friend</code> 元素的闭包，如清单 2 所示。</p>
		<br />
		<br />
		<a name="code1">
				<b>清单 2. 生成器是如此的简单</b>
		</a>
		<br />
		<table border="0" cellpadding="0" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td class="code-outline">
										<pre class="displaycode">import groovy.xml.*<br />import java.io.*<br />class XMLBuilder{<br /><br />  static void main(args) {<br /><br />    writer = new StringWriter()	 	<br />    builder = new MarkupBuilder(writer)<br />    friendnames = [ "Julie", "Joey", "Hannah"]<br /><br />	builder.person() {<br />       name(first:"Megan", last:"Smith") {<br />         age("33")<br />         gender("female")<br />       }<br />       friends() {<br />         for (e in friendnames) { friend(e) }<br />       }<br />    }<br />    println writer.toString()<br />  }<br />}<br /></pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>如您所见，这里的 Groovy 表示非常优雅，且易于映射到相应的标记表示。在底层，Groovy 显然在处理烦人的标记元素（如 &lt; and &gt;），使我们可以将更多精力放在内容上，而不必过分在意结构的细节。</p>
		<br />
		<table border="0" cellpadding="0" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td>
										<img src="http://www.ibm.com/i/v14/rules/blue_rule.gif" alt="" height="1" width="100%" />
										<br />
										<img alt="" src="http://www.ibm.com/i/c.gif" border="0" height="6" width="8" />
								</td>
						</tr>
				</tbody>
		</table>
		<table class="no-print" align="right" cellpadding="0" cellspacing="0">
				<tbody>
						<tr align="right">
								<td>
										<img src="http://www.ibm.com/i/c.gif" alt="" height="4" width="100%" />
										<br />
										<br />
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<br />
		<p>
				<a name="N100E7">
						<span class="atitle">显示 HTML</span>
				</a>
		</p>
		<p>生成器也可以有助于构建 HTML，这在开发 Groovlet 时可以派上用场。如同小菜一碟，假设我要创建一个如清单 3 所示的 HTML 页面。</p>
		<br />
		<br />
		<a name="code1">
				<b>清单 3. HTML 101</b>
		</a>
		<br />
		<table border="0" cellpadding="0" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td class="code-outline">
										<pre class="displaycode"> &lt;html&gt;<br />  &lt;head&gt;<br />   &lt;title&gt;Groov'n with Builders&lt;/title&gt;<br />  &lt;/head&gt;<br />  &lt;body&gt;<br />   &lt;p&gt;Welcome to Builders 101. As you can see this Groovlet is fairly simple.&lt;/p&gt;<br />  &lt;/body&gt;<br /> &lt;/html&gt;<br /></pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>我可以轻易地将它编码在 Groovy 中，清单 4 所示。</p>
		<br />
		<br />
		<a name="code1">
				<b>清单 4. HTML in Groovy 101
</b>
		</a>
		<br />
		<table border="0" cellpadding="0" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td class="code-outline">
										<pre class="displaycode">import groovy.xml.*<br />import java.io.*<br />class HTMLBuilderExample{<br /><br />  static void main(args) {<br />   writer = new StringWriter()	 	<br />   builder = new MarkupBuilder(writer)<br /><br />   builder.html(){<br />     head(){<br />       title("Groov'n with Builders"){}<br />     }<br />     body(){<br />       p("Welcome to Builders 101. As you can see " +<br />         "this Groovlet is fairly simple.") <br />     }<br />   }<br />   println writer.toString()<br />}<br /></pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>来点有意思的，让我们再看看用生成器建立一个成熟的 GUI 有多么容易。前面我曾提到过，Groovy 的 <code>SwingBuilder</code> 使它能够以一种极为简单的方式构造 GUI。您可以查阅清单 5 中 <code>SwingBuilder</code> 是如何工作的。</p>
		<br />
		<br />
		<a name="code1">
				<b>清单 5. Groovy 中的 GUI 生成器真的很“GROOVY”（很“棒”）</b>
		</a>
		<br />
		<table border="0" cellpadding="0" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td class="code-outline">
										<pre class="displaycode">import java.awt.FlowLayout<br />import javax.swing.*<br />import groovy.swing.SwingBuilder<br />class SwingExample{<br /><br />  static void main(args) {<br />    swinger = new SwingBuilder()<br />    langs = ["Groovy", "Ruby", "Python", "Pnuts"]<br /><br />	gui = swinger.frame(title:'Swinging with Groovy!', size:[290,100]) {<br />      panel(layout:new FlowLayout()) {<br />        panel(layout:new FlowLayout()) {<br />          for (lang in langs) {<br />            checkBox(text:lang)<br />          }<br />        }<br />        button(text:'Groovy Button', actionPerformed:{ <br />          swinger.optionPane(message:'Indubitably Groovy!').createDialog(null, 'Zen Message').show()<br />        })<br />        button(text:'Groovy Quit', actionPerformed:{ System.exit(0)})<br />     }<br />   }<br />   gui.show()<br />   }<br />}<br /></pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>图 1 显示了上面的结果，还不错吧？</p>
		<br />
		<br />
		<a name="fig1">
				<b>
图 1. Groovy 中神奇的 GUI 编程</b>
		</a>
		<br />
		<img alt="" src="http://www.ibm.com/developerworks/cn/java/j-pg04125/sgui1.gif" border="0" height="101" width="294" />
		<br />
		<p>可以想像，对于原型化，<code>SwingBuilder</code> 是一个多么强大的工具，不是么？</p>
		<br />
		<table border="0" cellpadding="0" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td>
										<img src="http://www.ibm.com/i/v14/rules/blue_rule.gif" alt="" height="1" width="100%" />
										<br />
										<img alt="" src="http://www.ibm.com/i/c.gif" border="0" height="6" width="8" />
								</td>
						</tr>
				</tbody>
		</table>
		<table class="no-print" align="right" cellpadding="0" cellspacing="0">
				<tbody>
						<tr align="right">
								<td>
										<img src="http://www.ibm.com/i/c.gif" alt="" height="4" width="100%" />
										<br />
										<br />
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<br />
		<p>
				<a name="N1013B">
						<span class="atitle">一些事实</span>
				</a>
		</p>
		<p>这
些例子虽然琐碎，却也有趣。我希望我能让您明白，Groovy 的生成器可以让您避免特定语言（如 XML）中的底层标记。显然，有时避免 XML 或
HTML 会更好，并且，那些标记协助器（facilitator）对 Java 平台来说并不陌生。例如，我最喜欢的 XML 协助框架是 JiBX。</p>
		<p>使用 JiBX，您可以轻易地将 XML 结构映射到对象模型，<i>反之亦然</i>。绑定是个强大的范例，有不计其数的类似工具拥有此功能，如 JAXB、 Castor 和 Zeus 等。</p>
		<p>绑定框架的惟一缺点是，它们<i>恐怕</i> 要耗费不少时间。幸运的是，您可以使用 Groovy 的生成器作为一个<i>较简单的</i> 解决方案，这在某些情况下是有效的。</p>
		<br />
		<table border="0" cellpadding="0" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td>
										<img src="http://www.ibm.com/i/v14/rules/blue_rule.gif" alt="" height="1" width="100%" />
										<br />
										<img alt="" src="http://www.ibm.com/i/c.gif" border="0" height="6" width="8" />
								</td>
						</tr>
				</tbody>
		</table>
		<table class="no-print" align="right" cellpadding="0" cellspacing="0">
				<tbody>
						<tr align="right">
								<td>
										<img src="http://www.ibm.com/i/c.gif" alt="" height="4" width="100%" />
										<br />
										<br />
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<br />
		<p>
				<a name="N10153">
						<span class="atitle">用生成器进行伪绑定</span>
				</a>
		</p>
		<p>假设有一个英文词典的简单数据库。有一个表用于 <code>word</code>，另一个表用于 <code>definition
</code>，最后还有一个表用于 <code>synonym</code>。图 2 是这个数据库的简单表示。</p>
		<br />
		<br />
		<a name="fig2">
				<b>
图 2. 词典数据库</b>
		</a>
		<br />
		<img alt="" src="http://www.ibm.com/developerworks/cn/java/j-pg04125/words-db.jpg" border="0" height="191" width="463" />
		<br />
		<p>如您所见，这个数据库非常直观：<code>word</code> 与 <code>definition</code> 和 <code>synonym</code> 具有一对多的关系。</p>
		<p>词典数据库拥有一个消费者，他在寻求一种表示数据库内容的关键方面的 XML 结构。所寻求的 XML 结构如清单 6 所示。</p>
		<br />
		<br />
		<a name="code1">
				<b>清单 6. 可采用的词典 XML</b>
		</a>
		<br />
		<table border="0" cellpadding="0" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td class="code-outline">
										<pre class="displaycode">&lt;words&gt;<br />  &lt;word spelling="glib" partofspeech="adjective"&gt;<br />    &lt;defintions&gt;<br />      &lt;defintion&gt;Performed with a natural, offhand ease.&lt;/defintion&gt;<br />      &lt;defintion&gt;Marked by ease and fluency of speech or writing that often suggests <br />	  or stems from insincerity, superficiality, or deceitfulness&lt;/defintion&gt;<br />    &lt;/defintions&gt;<br />    &lt;synonyms&gt;<br />      &lt;synonym spelling="artful"/&gt; <br />      &lt;synonym spelling="urbane"/&gt; <br />    &lt;/synonyms&gt;<br />  &lt;/word&gt;	<br />&lt;/words&gt;<br /></pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>如果选择使用 JiBX 这样的绑定框架来解决这个问题，则很可能需要创建一些中间对象模型，以从关系模型到达最终的 XML 模型。然后必须将数据库内容读取到对象模型中，并请求底层框架将其内部的结构编组为 XML 格式。</p>
		<p>这一过程内含了将对象结构映射到 XML 格式的步骤（使用所需的框架过程）。某些框架，如 JAXB，实际上是从 XML 和其他框架（如 JiBX
）生成 Java 对象，允许您自定义自己的 Java 对象到 XML 格式的映射。总之，这都需要大量的工作。</p>
		<p>并且，这是一项宏伟的计划。我并不提倡避免使用绑定框架。这里，我要声明：我已经预先警告过您。我计划向您展示的是一个生成 XML 的便捷方式。</p>
		<p>
				<a name="N101A0">
						<span class="smalltitle">可消费的 XML 很简单</span>
				</a>
		</p>
		<p>使用 Groovy 的 <code>MarkupBuilder</code>，结合新的数据库访问框架 GroovySql，您可以轻易地生成可消费的 XML。您
所要做的只是计算出所需的查询，并将结果映射到生成器实例 —— 然后，您马上就可以得到表示词典数据库内容的 XML 文档。</p>
		<p>让我们逐步来了解这一过程。首先，创建一个生成器实例，在本例中是 <code>MarkupBuilder</code>，因为您想要生成 XML。最外面的 XML 元
素（也就是“根”）是 <code>words</code>，这样就创建了一个 <code>words</code> 方法。在闭包里，
调用第一个查询，并在迭代中将查询结果映射到 <code>word</code> 子节点。</p>
		<p>接着，通过两个新的查询，创建 <code>word</code> 的两个子节点。创建一个 <code>definitions</code> 对象，并在迭代中映射它，接着用同样的方法处理 <code>synonyms</code>。</p>
		<br />
		<br />
		<a name="code1">
				<b>清单 7. 用生成器集合所有元素</b>
		</a>
		<br />
		<table border="0" cellpadding="0" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td class="code-outline">
										<pre class="displaycode">import groovy.sql.Sql<br />import groovy.xml.MarkupBuilder<br />import java.io.File<br />import java.io.StringWriter<br />class WordsDbReader{<br />  static void main(args) {<br />    sql = Sql.newInstance("jdbc:mysql://localhost/words", <br />      "words", "words", "org.gjt.mm.mysql.Driver")<br />    writer = new StringWriter()	 	<br />    builder = new MarkupBuilder(writer)<br />    builder.words() {<br />      sql.eachRow("select word_id, spelling, part_of_speech from word"){ row |<br />        builder.word(spelling:row.spelling, partofspeech:row.part_of_speech){<br /><br />		 builder.definitions(){<br />            sql.eachRow("select definition from definition where word_id = ${row.word_id}"){ defrow |<br />              builder.definition(defrow.definition)<br />            }<br />         }<br /><br />		 builder.synonyms(){  		       		<br />            sql.eachRow("select spelling from synonym where word_id = ${row.word_id}"){ synrow |<br />              builder.synonym(synrow.spelling)<br />            }		       					       		<br />         }<br />       }<br />      }<br />    }<br />   new File("dbouuput.xml").withPrintWriter{ pwriter |<br />      pwriter.println writer.toString()<br />   }<br /> }<br />}<br /></pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>
				<a name="N101DA">
						<span class="smalltitle">结束语</span>
				</a>
		</p>
		<p>这里，我向您展示的绑定解决方案似乎简单得让人难以置信，特别是以 Java 纯化论者的观点看来更是如此。尽管该解决方案不比使用绑定框架（如 JABX 和 JiBX） <i>更好</i>，但它确实更快一些 —— 而且，我主张使用这样较简单的方法。是不是我在<i>简单的</i> Java 代码中做一些类似的事情？是的，但我敢肯定，某些时候我也不得不处理 XML。</p>
		<p>用 Groovy 生成器进行开发的速度和简易性，在调用标记的时候可大显神威。例如，就像在第二个例子里展示的那样，我可以马上加快数据库的 XML 表示。对于原型化，或者当需要以最少的开发时间和精力来产生可工作的解决方案时，生成器也是一个不错的选择。</p>
		<p>在下个月的<i>实战 Groovy</i> 中我会讲些什么呢？哦，当然是在 Java 语言中使用 Groovy！</p>
<img src ="http://www.blogjava.net/JafeLee/aggbug/128674.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/JafeLee/" target="_blank">Jafe</a> 2007-07-06 21:06 <a href="http://www.blogjava.net/JafeLee/articles/128674.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>实战 Groovy: 用 Groovy 打造服务器端</title><link>http://www.blogjava.net/JafeLee/articles/128673.html</link><dc:creator>Jafe</dc:creator><author>Jafe</author><pubDate>Fri, 06 Jul 2007 13:04:00 GMT</pubDate><guid>http://www.blogjava.net/JafeLee/articles/128673.html</guid><wfw:comment>http://www.blogjava.net/JafeLee/comments/128673.html</wfw:comment><comments>http://www.blogjava.net/JafeLee/articles/128673.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/JafeLee/comments/commentRss/128673.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/JafeLee/services/trackbacks/128673.html</trackback:ping><description><![CDATA[
		<p>
				<a href="http://www.ibm.com/developerworks/cn/java/j-pg03155/index.html#author">Andrew Glover</a> (<a href="mailto:aglover@vanwardtechnologies.com?subject=%E7%94%A8%20Groovy%20%E6%89%93%E9%80%A0%E6%9C%8D%E5%8A%A1%E5%99%A8%E7%AB%AF">aglover@vanwardtechnologies.com</a>), 首席技术官, Vanward Technologies<br /></p>
		<p>2005 年  3 月  28 日</p>
		<blockquote>Groovlet
和 GroovyServer Pages（GSP）框架都是建立在 Java Servlet API 基础之上。不过，与 Strut 和 JSF
不同，Groovy 的服务器端实现不意味着适用于所有情况。相反，它提供了一种快速而又方便地开发服务器端应用程序的简化方法。下面请跟随
Groovy 的鼓吹者 Andrew Glover，听听他如何介绍这些框架，并展示它们的应用。</blockquote>
		<!--START RESERVED FOR FUTURE USE INCLUDE FILES-->
		<!-- include java script once we verify teams wants to use this and it will work on dbcs and cyrillic characters -->
		<!--END RESERVED FOR FUTURE USE INCLUDE FILES-->
		<p>Java 平台为自己赢得了服务器端应用程序开发的首选平台的名声。Servlet
是服务器端 Java 技术的强大支柱，因此有无数的框架是围绕着 Servlet API 建立
起来的，其中包括 Strut、JavaServer Faces (JSF) 和 Tapestry。您可能已经猜到，Groovy 也是以 Servlet API 为基础建立起来的框架，不过，这个框架的目的是简化开发。</p>
		<p>Groovlet 和 GroovyServer Pages（GSP）框架的目的是提供一种优雅而又简单的平台，将它用于构建复杂程度不高的 Web 应用程序。就像
 GroovySql 不是数据库开发的惟一选择一样，Groovlet 框架也<i>不是</i>
像 Strut 那样具有更丰富功能的框架的替代品。Groovlet 只是
开发人员寻求容易配置和产生工作代码的快速方法时的一种选择。</p>
		<p>例如，不久前，我需要 —— <i>快速地</i> —— 提供一个
 stub 应用程序，以测试像 <code>xml-rpc</code>
API 这样的客户端。显然可以用一个 servlet 快速编写出所需要的功能，但是我从没想过钻研
Strut，一秒钟也没有。我考虑过使用基本的普通 Java Servlet API 编写 servlet
及其相关的逻辑，但是由于需要尽快地使用这项功能，所以我选择了使用 Groovlet 快速完成它。</p>
		<p>很快您就可看到，这种选择是显而易见的。</p>
		<p>在深入研究使用 Groovlet 进行编程之前，我想简单介绍一个在示例代码中会用到的 Groovy 特性。
在几个月前的 <a href="http://www.ibm.com/developerworks/cn/java/j-alj08034/index.html">alt.lang.jre: 感受 Groovy</a>  一文中，我第一次介绍了 <code>def</code> 关键字。 </p>
		<table align="right" border="0" cellpadding="0" cellspacing="0" width="40%">
				<tbody>
						<tr>
								<td width="10">
										<img alt="" src="http://www.ibm.com/i/c.gif" height="1" width="10" />
								</td>
								<td>
										<br />
								</td>
						</tr>
				</tbody>
		</table>
		<p>
				<a name="N1007C">
						<span class="atitle">在脚本中定义函数</span>
				</a>
		</p>
		<p>在普通 Java 编程中，方法必须存在于类对象中。事实上，所有行为都必须在类的上
下文中定义。不过在 Groovy 中，行为可以在<i>函数</i> 中定义，而函数可以在类定义之外定义
。</p>
		<p>这些函数可以直接用名称引用，并且可以在 Groovy 脚本中定义，这样非常
有助于它们的重复使用。Groovy 函数需要 <code>def</code> 关键字，
可以将关键字想像为在脚本范围内可用的全局静态方法。因为 Groovy 是动态类型的语言，所以 <code>def</code> 不需要对参数作任何类型声明，<code>def</code> 也不需要 <code>return</code>
语句。</p>
		<p>例如，在清单 1 中，我定义了一个简单的函数，它将输出一个集合的内容，而不管这个集合是 <code>list</code> 还是 <code>map</code>。然后我定义
一个 <code>list</code>，填充它，并调用我新定义的
 <code>def</code>。之后，我创建一个
 <code>map</code>，并对这个集合做了同样的操作。</p>
		<br />
		<br />
		<a name="code1">
				<b>清单 1. 这就是 def!</b>
		</a>
		<br />
		<table border="0" cellpadding="0" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td class="code-outline">
										<pre class="displaycode">def logCollection(coll){<br />  counter = 0;<br />  coll.each{ x | <br />    println "${++counter} item: ${x}"<br />  }<br />}<br />lst = [12, 3, "Andy", 'c']<br />logCollection(lst)<br />mp = ["name" : "Groovy", "date" : new Date()]<br />logCollection(mp)<br /></pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>
				<code>def</code> 不需要 <code>return</code> 语句，因此如果最后一行产生某个
值，那么这个值由 <code>def</code> 返回。例如，在清单 2 中，代码定义了一个
 <code>def</code>，它返回传递进来的变量的名称。
我可以编写它，让它带有或者不带 <code>return</code> 语句，得到的结果是相同的。</p>
		<br />
		<br />
		<a name="code2">
				<b>清单 2. 在 def 中 return 语句是可选的</b>
		</a>
		<br />
		<table border="0" cellpadding="0" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td class="code-outline">
										<pre class="displaycode">def getJavaType(val){<br />  val.class.getName()<br />}<br />tst = "Test"<br />println getJavaType(tst)<br /></pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>在编写简单的脚本时，<code>def</code> 关键字会非常好用。您很快就会看到，在开发 Groovlet 时，这个关键字也会派上用场。</p>
		<br />
		<table border="0" cellpadding="0" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td>
										<img src="http://www.ibm.com/i/v14/rules/blue_rule.gif" alt="" height="1" width="100%" />
										<br />
										<img alt="" src="http://www.ibm.com/i/c.gif" border="0" height="6" width="8" />
								</td>
						</tr>
				</tbody>
		</table>
		<table class="no-print" align="right" cellpadding="0" cellspacing="0">
				<tbody>
						<tr align="right">
								<td>
										<img src="http://www.ibm.com/i/c.gif" alt="" height="4" width="100%" />
										<br />
										<br />
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<br />
		<p>
				<a name="N100E6">
						<span class="atitle">Groovlet 和 GSP</span>
				</a>
		</p>
		<p>使用 Groovlet 和 GSP 的前提条件相当简单：需要一个 servlet 容器，以及最新、最伟大
版本的 Groovy。这些框架的好处是它们通过一个 web.xml 文件将所选模式的所有 URL 映射到特定的 servlet。因此，
建立 Groovlet 和 GSP 的实现的第一步是定义一个 Web 应用程序上下文，并更新它的相关 web.xml 文件。
这个文件将包括特定的 servlet 类定义以及它们对应的 URL 模式。</p>
		<p>我将使用 Apache Jakarta Tomcat，并且已创建了一个名为
<i>groove</i> 的上下文。目录结构如清单 3 所示：</p>
		<br />
		<br />
		<a name="code3">
				<b>清单 3. groove 上下文的目录列表 
</b>
		</a>
		<br />
		<table border="0" cellpadding="0" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td class="code-outline">
										<pre class="displaycode">./groove:<br />drwxrwxrwx+   3 aglover  users        0 Jan 19 12:14 WEB-INF<br />./WEB-INF:<br />-rwxrwxrwx+   1 aglover  users      906 Jan 16 14:37 web.xml<br />drwxrwxrwx+   2 aglover  users        0 Jan 19 17:12 lib<br />./WEB-INF/lib:<br />-rwxrwxrwx+   1 aglover  users   832173 Jan 16 14:28 groovy-1.0-beta-9.jar<br />-rwxrwxrwx+   1 aglover  users    26337 Jan 16 14:29 asm-1.5.2.jar<br /></pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>在 WEB-INF 目录中要有一个 web.xml
文件，它至少有一个清单 4 中的元素：</p>
		<br />
		<br />
		<a name="code4">
				<b>清单 4. 一个完全配置的 web.xml 文件</b>
		</a>
		<br />
		<table border="0" cellpadding="0" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td class="code-outline">
										<pre class="displaycode">&lt;?xml version="1.0" encoding="ISO-8859-1"?&gt;<br />&lt;web-app xmlns="http://java.sun.com/xml/ns/j2ee"<br />    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"<br />    xsi:schemaLocation=<br />    "http://java.sun.com/xml/ns/j2ee<br />    http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"<br />    version="2.4"&gt;<br />    &lt;servlet&gt;<br />      &lt;servlet-name&gt;GroovyServlet&lt;/servlet-name&gt;<br />      &lt;servlet-class&gt;groovy.servlet.GroovyServlet&lt;/servlet-class&gt;<br />    &lt;/servlet&gt;<br />    &lt;servlet&gt;<br />        &lt;servlet-name&gt;GroovyTemplate&lt;/servlet-name&gt;<br />        &lt;servlet-class&gt;groovy.servlet.TemplateServlet&lt;/servlet-class&gt;    <br />	&lt;/servlet&gt;<br />    &lt;servlet-mapping&gt;<br />        &lt;servlet-name&gt;GroovyServlet&lt;/servlet-name&gt;<br />        &lt;url-pattern&gt;*.groovy&lt;/url-pattern&gt;<br />    &lt;/servlet-mapping&gt;<br />    &lt;servlet-mapping&gt;<br />        &lt;servlet-name&gt;GroovyTemplate&lt;/servlet-name&gt;<br />        &lt;url-pattern&gt;*.gsp&lt;/url-pattern&gt;<br />    &lt;/servlet-mapping&gt;<br />&lt;/web-app&gt;<br /></pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>上述 web.xml 文件中的定义声明了以下内容：所有以
 <code>.groovy</code> 结尾的请求（如 <code>http://localhost:8080/groove/hello.groovy</code>）都将发送给
类 <code>groovy.servlet.GroovyServlet</code>，
而所有以 <code>.gsp</code> 结尾的请求
都将送给类 <code>groovy.servlet.TemplateServlet</code>。</p>
		<p>下一步是将两个 jar 放到 lib 目录中：groovy 发行版本的 jar（在这里是 groovy-1.0-beta-9.jar）和
对应的 <code>asm</code> jar （对于 groovy beta-9 来说是 asm-1.5.2.jar）。</p>
		<p>瞧，就是这么简单 —— 我已经准备好了。</p>
		<br />
		<table border="0" cellpadding="0" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td>
										<img src="http://www.ibm.com/i/v14/rules/blue_rule.gif" alt="" height="1" width="100%" />
										<br />
										<img alt="" src="http://www.ibm.com/i/c.gif" border="0" height="6" width="8" />
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<br />
		<p>
				<a name="N1012F">
						<span class="atitle">Groovlet，请出场</span>
				</a>
		</p>
		<p>编写 Groovlet 无疑很简单，因为 Groovy 只有很少的几个
对类继承扩展的要求。使用 Groovlet 不需要扩展 <code>javax.servlet.http.HttpServlet</code>、<code>javax.servlet.GenericServlet</code> 或者一些华而不实的 <code>GroovyServlet</code> 类。事实上，创建 Groovlet
就像创建一个 Groovy 脚本一样简单。甚至不必
创建一个类。在清单 5 中，我编写了一个简单的 Groovlet，它
做两件事：打印一些 HTML，然后提供一些关于它所在的容器的信息。</p>
		<br />
		<br />
		<a name="code5">
				<b>清单 5. 开始使用 Groovlet</b>
		</a>
		<br />
		<table border="0" cellpadding="0" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td class="code-outline">
										<pre class="displaycode">println """<br />&lt;html&gt;&lt;head&gt;<br />&lt;title&gt;Groovlets 101&lt;/title&gt;<br />&lt;/head&gt;<br />&lt;body&gt;<br />&lt;p&gt;<br />Welcome to Groovlets 101. As you can see<br />this Groovlet is fairly simple.<br />&lt;/p&gt;<br />&lt;p&gt;<br />This course is being run on the following servlet container: &lt;/br&gt;<br />${application.getServerInfo()}<br />&lt;/p&gt;<br />&lt;/body&gt;<br />&lt;/html&gt;<br />"""<br /></pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>如果在浏览器中观看这个 Groovy，它看起来与图 1 所示类似。</p>
		<br />
		<br />
		<a name="fig1">
				<b>
图 1. 简单 Groovlet 的输出</b>
		</a>
		<br />
		<img alt="" src="http://www.ibm.com/developerworks/cn/java/j-pg03155/figure1.jpg" border="0" height="347" width="600" />
		<br />
		<p>仔细观察清单 5 中的 Groovlet，会让您回想起第一次编写 Groovy 脚本的时候。
首先，没有 <code>main</code> 方法或者类定义，只有一些简单的代码。而且，Groovlet 框架隐式地提供实例变量，比如
<code>ServletRequest</code>、<code>ServletResponse</code>、<code>ServletContext</code> 和 <code>HttpSession</code>。注意我是如何通过 <code>application</code> 变量引用 <code>ServletContext</code> 的实例的。如果想获得 <code>HttpSession</code> 的实例，那么就要使用 <code>session</code> 变量名。与此类似，可以对 <code>ServletRequest</code> 和 <code>ServletResponse</code> 分别使用 <code>request</code> 和 <code>response</code>。</p>
		<br />
		<table border="0" cellpadding="0" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td>
										<img src="http://www.ibm.com/i/v14/rules/blue_rule.gif" alt="" height="1" width="100%" />
										<br />
										<img alt="" src="http://www.ibm.com/i/c.gif" border="0" height="6" width="8" />
								</td>
						</tr>
				</tbody>
		</table>
		<table class="no-print" align="right" cellpadding="0" cellspacing="0">
				<tbody>
						<tr align="right">
								<td>
										<img src="http://www.ibm.com/i/c.gif" alt="" height="4" width="100%" />
										<br />
										<br />
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<br />
		<p>
				<a name="N1019B">
						<span class="atitle">一个诊断 Groovlet</span>
				</a>
		</p>
		<p>编写 Groovlet 不仅像创建一个 Groovy 脚本那样简单，而且还可以用 <code>def</code>
关键字定义函数，并在 Groovlet 中直接调用它们。为了展示这一点，我将
创建一个非凡的 Groovlet，它将对 Web 应用程序进行一些诊断。</p>
		<p>假设您编写了一个 Web 应用程序，它被世界上不同的客户所购买。您有一个
大客户群，并且不断发布这个应用程序有一段时间了。从过去的支持问题中，您
注意到许多急切的客户电话都与错误的 JVM 版本和错误的对象关系映射（ORM）所导致的问题有关。</p>
		<p>您很忙，所以让我拿出一个解决方案。我用 Groovlet <i>迅速地</i> 创建了一个简单的
诊断脚本，它将验证 VM 版本，并试图创建一个 Hibernate
 会话（请参阅<a href="http://www.ibm.com/developerworks/cn/java/j-pg03155/index.html#resources">参考资料</a>）。我首先创建
两个函数，并在浏览器连接脚本时调用它们。
清单 6 定义了这个诊断 Groovlet：</p>
		<br />
		<br />
		<a name="code6">
				<b>清单 6. 一个诊断 Groovlet</b>
		</a>
		<br />
		<table border="0" cellpadding="0" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td class="code-outline">
										<pre class="displaycode">import com.vanward.resource.hibernate.factory.DefaultHibernateSessionFactory<br />/**<br /> * Tests VM version from environment- note, even 1.5 will<br /> * cause an assertion error.<br /> */<br />def testVMVersion(){<br />  println "&lt;h3&gt;JVM Version Check: &lt;/h3&gt;"<br />  vers = System.getProperty("java.version")<br />  assert vers.startsWith("1.4"): "JVM must be at least 1.4"<br />  println "&lt;p&gt;JVM version: ${vers} &lt;/p&gt;"<br />}<br />/**<br /> * Attempts to create an instance of a hibernate session. If this<br /> * works we have a connection to a database; additionally, we <br /> * have a properly configured hibernate instance.<br /> */<br />def testHibernate(){<br />  println "&lt;h3&gt;Hibernate Configuration Check: &lt;/h3&gt;"<br />  try{<br />    sessFactory = DefaultHibernateSessionFactory.getInstance()<br />    session = sessFactory.getHibernateSession()<br />    assert session != null: "Unable to create hibernate session. <br />    Session was null"<br />    println "&lt;p&gt;Hibernate configuration check was successful&lt;/p&gt;"<br />  }catch(Throwable tr){<br />    println """<br />    &lt;p&gt;Unable to create hibernate session. Exception type is: &lt;br/&gt;<br />    &lt;i&gt;${tr.toString()} &lt;/i&gt;&lt;br/&gt;		<br />    &lt;/p&gt;<br />    """<br />  }   <br />}<br />println """<br />&lt;html&gt;&lt;head&gt;<br />&lt;title&gt;Diagnostics Check&lt;/title&gt;&lt;/head&gt;<br />&lt;body&gt;<br />"""<br />testVMVersion()<br />testHibernate()<br />println """<br />&lt;/body&gt;&lt;/html&gt;<br />"""<br /></pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>这个 Groovlet 的验证逻辑非常简单，但是它可以完成这项工作。只要将
诊断脚本绑定到 web 应用程序即可，当客户服务台收到电话时，它们将指点客户用浏览器
访问 <code>Diagnostics.groovy</code> 脚本，并让这些脚本报告它们的发现。
结果可能看起来像图 2 这样。</p>
		<br />
		<br />
		<a name="fig2">
				<b>
图 2. 诊断 Groovlet 的输出</b>
		</a>
		<br />
		<img alt="" src="http://www.ibm.com/developerworks/cn/java/j-pg03155/figure2.jpg" border="0" height="346" width="600" />
		<br />
		<br />
		<table border="0" cellpadding="0" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td>
										<img src="http://www.ibm.com/i/v14/rules/blue_rule.gif" alt="" height="1" width="100%" />
										<br />
										<img alt="" src="http://www.ibm.com/i/c.gif" border="0" height="6" width="8" />
								</td>
						</tr>
				</tbody>
		</table>
		<table class="no-print" align="right" cellpadding="0" cellspacing="0">
				<tbody>
						<tr align="right">
								<td>
										<img src="http://www.ibm.com/i/c.gif" alt="" height="4" width="100%" />
										<br />
										<br />
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<br />
		<p>
				<a name="N101D9">
						<span class="atitle">那些 GSP 呢？</span>
				</a>
		</p>
		<p>到目前为止，我主要关注于编写 Groovlet。不过，正如您将会看到的那样，
很容易用 Groovy 的 GSP 页对 Groovlets 框架进行补充，就像 JSP 补充 
 Servlet API 一样。</p>
		<p>表面上，GSP 看起来很像 JSP，实际上它们不可能有太大的差别，因为
 GSP 框架其实就是一个模板引擎。如果不熟悉模板引擎，那么可能需要快速地
回顾一下<a href="http://www.ibm.com/developerworks/cn/java/j-pg02155/index.html">上月的文章</a>。</p>
		<p>虽然 GSP 和 JSP 是根本不同的技术，但是 GSP 是加入表达 Web 应用程序的视图的很
好候选人，这一点它们是类似的。您可能会想起来，在上月的文章中，有一项促进视图的技术可以将应用程序的业务逻辑问题与其相应的视图分离。
如果快速查看一下<a href="http://www.ibm.com/developerworks/cn/java/j-pg03155/index.html#code6">清单
6</a> 中的诊断 Groovlet，就可以看出 GSP 代码改进了哪些地方。</p>
		<p>是的，Groovlet 有些简陋，不是吗？问题在于它混合了应用程序逻辑和大量输出 HTML 的 <code>println</code>。幸运的是，可以通过创建一个简单的 GSP 来补充这个
Groovlet，从而解决这个问题。</p>
		<p>
				<a name="N101F7">
						<span class="smalltitle">示例 GSP</span>
				</a>
		</p>
		<p>创建 GSP 与创建 Groovlet 一样容易。GSP 开发的关键是认识到 GSP 实质上
是一个模板，因此，它最适合有限的逻辑。我将在清单 7 中创建一个
简单的 GSP 作为开始：</p>
		<br />
		<br />
		<a name="code7">
				<b>清单 7. 一个简单的 GSP</b>
		</a>
		<br />
		<table border="0" cellpadding="0" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td class="code-outline">
										<pre class="displaycode">&lt;html&gt;<br />&lt;head&gt;&lt;title&gt;index.gsp&lt;/title&gt;&lt;/head&gt;<br />&lt;body&gt;<br />&lt;b&gt;&lt;% println "hello gsp" %&gt;&lt;/b&gt;<br />&lt;p&gt;<br />&lt;% wrd = "Groovy"<br />   for (i in wrd){ <br /> %&gt;<br /> &lt;h1&gt; &lt;%=i%&gt; &lt;br/&gt;<br /><br /> &lt;%} %&gt;<br />&lt;/p&gt;<br />&lt;/body&gt;<br />&lt;/html&gt;<br /></pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>观察上面的 GSP 可能很容易让您回想起标准 Groovy 模板开发。
像 JSP 一样，它使用 <code>&lt;%</code>， 但是，
与 Groovlet 框架类似，它允许您访问常用 servlet 对象，比如 <code>ServletRequest</code>、<code>ServletResponse</code>、<code>ServletContext</code> 和 <code>HttpSession</code> 对象。</p>
		<br />
		<table border="0" cellpadding="0" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td>
										<img src="http://www.ibm.com/i/v14/rules/blue_rule.gif" alt="" height="1" width="100%" />
										<br />
										<img alt="" src="http://www.ibm.com/i/c.gif" border="0" height="6" width="8" />
								</td>
						</tr>
				</tbody>
		</table>
		<table class="no-print" align="right" cellpadding="0" cellspacing="0">
				<tbody>
						<tr align="right">
								<td>
										<img src="http://www.ibm.com/i/c.gif" alt="" height="4" width="100%" />
										<br />
										<br />
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<br />
		<p>
				<a name="N10222">
						<span class="atitle">重构应用程序 ...</span>
				</a>
		</p>
		<p>在练习编程语言或者平台发展的时候，重构老的代码可以学到很多东西。我将重构<a href="http://www.ibm.com/developerworks/cn/java/j-pg01115.html">一月份专栏</a>中的简单报告应用程序，那时候您才刚开始学习 GroovySql。</p>
		<p>您还记得吗，我构建了一个快速但不完善的报告应用程序，它可以在组织中有
多次使用。但结果是，它变成了研究公司数据库活动的相当流行的应用程序。
现在，非技术人员希望可以访问这个巨大的报告，但是他们不想很费事地在自已的
计算机上安装 Groovy 来运行它。</p>
		<p>我多少预计到了这种情况的发生，解决方案<i>实际上</i> 是显而易见的：让报告应用程序支持 Web。很幸运，Groovlet 和 GSP 使重构变成小事一桩。</p>
		<p>
				<a name="N10238">
						<span class="smalltitle">重构报告应用程序</span>
				</a>
		</p>
		<p>首先，我将处理 <a href="http://www.ibm.com/developerworks/cn/java/j-pg01115.html#%20code12">&gt; GroovySql 一文的清单 12</a> 中的简单应用程序。重构这个应用程序很容易：只要将所有 <code>println</code>
替换成用 <code>setAttribute()</code> 方法，然后将实例变量放入 <code>HttpRequest</code> 对象的逻辑中即可。</p>
		<p>下一步是用 <code>RequestDispatcher</code> 将 <code>request</code>
转发给 GSP，它会处理报告应用程序的视图部分。清单 8 定义了新的报告
 Groovlet：</p>
		<br />
		<br />
		<a name="code8">
				<b>清单 8. 重构后的数据库报告应用程序</b>
		</a>
		<br />
		<table border="0" cellpadding="0" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td class="code-outline">
										<pre class="displaycode">import groovy.sql.Sql<br />/**<br /> * forwards to passed in page<br /> */<br />def forward(page, req, res){<br />  dis = req.getRequestDispatcher(page);<br />  dis.forward(req, res);<br />}<br />sql = Sql.newInstance("jdbc:mysql://yourserver.anywhere/tiger", "scott",<br />        "tiger", "org.gjt.mm.mysql.Driver")<br /><br />uptime = null<br />questions = null<br />insertnum = null<br />selectnum = null<br />updatenum = null<br />sql.eachRow("show status"){ status |<br />  if(status.variable_name == "Uptime"){<br />         uptime =  status[1]<br />	 request.setAttribute("uptime", uptime)<br />  }else if (status.variable_name == "Questions"){<br />         questions =  status[1]<br />	 request.setAttribute("questions", questions)<br />  }<br />}<br />request.setAttribute("qpm", Integer.valueOf(questions) / <br />Integer.valueOf(uptime) )<br />sql.eachRow("show status like 'Com_%'"){ status |<br />    if(status.variable_name == "Com_insert"){<br />         insertnum =  Integer.valueOf(status[1])<br />    }else if (status.variable_name == "Com_select"){<br />         selectnum =  Integer.valueOf(status[1])<br />    }else if (status.variable_name == "Com_update"){<br />          updatenum =  Integer.valueOf(status[1])<br />    }<br />}<br />request.setAttribute("qinsert", 100 * (insertnum / Integer.valueOf(uptime)))<br />request.setAttribute("qselect", 100 * (selectnum / Integer.valueOf(uptime)))<br />request.setAttribute("qupdate", 100 * (updatenum / Integer.valueOf(uptime)))<br />forward("mysqlreport.gsp", request, response)<br /></pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>清单 8 中的代码应当是您相当熟悉的。我只是将以前应用程序中的所有 <code>println</code> 替换掉，并添加了 <code>forward</code>
函数来处理报告的视图部分。</p>
		<p>
				<a name="N10272">
						<span class="smalltitle">添加视图部分</span>
				</a>
		</p>
		<p>下一步是创建 GSP 来处理报告应用程序的视图。
因为我是工程师而不是一个艺术家，所以我的视图是相当
简单的 ——  一些 HTML 加上一个表，如清单 9 所示：</p>
		<br />
		<br />
		<a name="code9">
				<b>清单 9. 报告的视图部分</b>
		</a>
		<br />
		<table border="0" cellpadding="0" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td class="code-outline">
										<pre class="displaycode">&lt;html&gt;&lt;head&gt;<br />&lt;title&gt;MySql Health Report&lt;/title&gt;<br />&lt;/head&gt;<br />&lt;body&gt;<br />&lt;table&gt;<br />&lt;tr&gt;<br />  &lt;td&gt;Database Uptime:&lt;/td&gt;&lt;td&gt;&lt;% println<br />  "${request.getAttribute("uptime")}" %&gt;&lt;/td&gt;<br />&lt;/tr&gt;<br />&lt;tr&gt;<br />  &lt;td&gt;Number of Queries:&lt;/td&gt;&lt;td&gt;&lt;% println<br />  "${request.getAttribute("questions")}" %&gt;&lt;/td&gt;<br />&lt;/tr&gt;<br />&lt;tr&gt;<br />  &lt;td&gt;Queries per Minute =&lt;/td&gt;&lt;td&gt;&lt;% println<br />  "${request.getAttribute("qpm")}" %&gt;&lt;/td&gt;<br />&lt;/tr&gt;<br />&lt;tr&gt;<br />  &lt;td&gt;% Queries Inserts =&lt;/td&gt;&lt;td&gt;&lt;% println<br />  "${request.getAttribute("qinsert")}" %&gt;&lt;/td&gt;<br />&lt;/tr&gt;<br />&lt;tr&gt;<br />  &lt;td&gt;% Queries Selects =&lt;/td&gt;&lt;td&gt;&lt;% println<br />  "${request.getAttribute("qselect")}" %&gt;&lt;/td&gt;<br />&lt;/tr&gt;<br />&lt;tr&gt;<br />  &lt;td&gt;% Queries Updates =&lt;/td&gt;&lt;td&gt;&lt;% println<br />  "${request.getAttribute("qupdate")}" %&gt;&lt;/td&gt;<br />&lt;/tr&gt;<br />&lt;/table&gt;<br />&lt;/body&gt;<br />&lt;/html&gt;<br /></pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>运行新的报告应当生成如图 3 所示的输出，数字会有变化。</p>
		<br />
		<br />
		<a name="fig3">
				<b>
图 3. 重构后的报告应用程序的输出</b>
		</a>
		<br />
		<img alt="" src="http://www.ibm.com/developerworks/cn/java/j-pg03155/figure3.jpg" border="0" height="347" width="600" />
		<br />
		<br />
		<table border="0" cellpadding="0" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td>
										<img src="http://www.ibm.com/i/v14/rules/blue_rule.gif" alt="" height="1" width="100%" />
										<br />
										<img alt="" src="http://www.ibm.com/i/c.gif" border="0" height="6" width="8" />
								</td>
						</tr>
				</tbody>
		</table>
		<table class="no-print" align="right" cellpadding="0" cellspacing="0">
				<tbody>
						<tr align="right">
								<td>
										<img src="http://www.ibm.com/i/c.gif" alt="" height="4" width="100%" />
										<br />
										<br />
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<br />
		<p>
				<a name="N1029B">
						<span class="atitle">结束语</span>
				</a>
		</p>
		<p> 如您所见，当所需要的功能相当简单并且需要尽快完成时，Groovlet 和 GSP 是进行服务器端开发的当然之选。
这两个框架都特别灵活，并且其代码到视图的转化时间事实上是无可匹敌的。</p>
		<p>不过，需要强调的是，Groovlet 不是 Strut 的替代品。GSP 框架不是<i>直接</i> 在速度上与其他产品竞争。GroovySql
不是 Hibernate 的替代品。而 Groovy 也不是 Java 语言的替代品。</p>
		<p>无论如何，这些技术是补充，在大多数情况下，Groovy 是快速开发的更简单的一种选择。
就像 GroovySql 是直接使用 JDBC 的替代方法一样，Groovlet 和 GSP 实际上是直接使用 Servlet
API 的替代品。</p>
		<p>下个月，我将探讨 GroovyMarkup 的奇妙世界。</p>
<img src ="http://www.blogjava.net/JafeLee/aggbug/128673.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/JafeLee/" target="_blank">Jafe</a> 2007-07-06 21:04 <a href="http://www.blogjava.net/JafeLee/articles/128673.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>实战 Groovy: 使用 Groovy 模板进行 MVC 编程</title><link>http://www.blogjava.net/JafeLee/articles/128672.html</link><dc:creator>Jafe</dc:creator><author>Jafe</author><pubDate>Fri, 06 Jul 2007 13:03:00 GMT</pubDate><guid>http://www.blogjava.net/JafeLee/articles/128672.html</guid><wfw:comment>http://www.blogjava.net/JafeLee/comments/128672.html</wfw:comment><comments>http://www.blogjava.net/JafeLee/articles/128672.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/JafeLee/comments/commentRss/128672.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/JafeLee/services/trackbacks/128672.html</trackback:ping><description><![CDATA[
		<p>
				<a href="http://www.ibm.com/developerworks/cn/java/j-pg02155/index.html#author">Andrew Glover</a> (<a href="mailto:aglover@vanwardtechnologies.com?subject=%E4%BD%BF%E7%94%A8%20Groovy%20%E6%A8%A1%E6%9D%BF%E8%BF%9B%E8%A1%8C%20MVC%20%E7%BC%96%E7%A8%8B">aglover@vanwardtechnologies.com</a>), CTO, Vanward Technologies<br /></p>
		<p>2005 年  2 月  15 日</p>
		<blockquote>视图是 MVC 编程的一个重要部分，而 MVC 编程本身又是企业应用程序开发的一个重要组件。在这篇实战 Groovy 的文章中，Andrew Glover 向您介绍了 Groovy 的模板引擎框架是如何用来简化视图编程的，并如何使您的代码更加经久容易维护。</blockquote>
		<!--START RESERVED FOR FUTURE USE INCLUDE FILES-->
		<!-- include java script once we verify teams wants to use this and it will work on dbcs and cyrillic characters -->
		<!--END RESERVED FOR FUTURE USE INCLUDE FILES-->
		<p>在最近的 <i>实战 Groovy</i> 系列中，我们已经介绍过 Groovy 是构建报表统计程序的一个非常好的工具。我们使用了一个校验和报表统计应用程序的例子向您介绍了 <a href="http://www.ibm.com/developerworks/cn/java/j-pg12144.html">使用 Groovy 编写 Ant 脚本</a> 和一个数据库报表统计来展示 <a href="http://www.ibm.com/developerworks/cn/java/j-pg01115.html">使用 GroovySql 进行 JDBC 编程</a>。这两个示例统计报表都是在 Groovy 脚本中生成的，而且都具有一个相关的“视图”。</p>
		<p>在
校验和统计报表的例子中，视图代码有些混乱。更糟糕的是，它可能会对维护造成一些困难：如果我曾经希望修改视图的某个特定方面，就必须修改脚本中的代码。
因此在本月的文章中，我将向您展示如何使用 Groovy 模板引擎和上一篇文章中的统计报表应用程序来对统计报表进行简化。</p>
		<p>模
板引擎与 XSLT 很类似，可以产生模板定义的任何格式，包括 XML、HTML、SQL 和 Groovy 代码。与 JSP
类似，模板引擎会简化将视图关注的内容分隔成单独的实体，例如 JSP 或模板文件。例如，如果一个报表希望的输出是 XML，那么您就可以创建一个
XML
模板，它可以包含一些占位符，在运行时替换为实际的值。模板引擎然后可以通过读取该模板并在这些占位符和运行时的值之间建立映射来实现对模板的转换。这个
过程的输出结果是一个 XML 格式的文档。</p>
		<table align="right" border="0" cellpadding="0" cellspacing="0" width="40%">
				<tbody>
						<tr>
								<td width="10">
										<img alt="" src="http://www.ibm.com/i/c.gif" height="1" width="10" />
								</td>
								<td>
										<br />
								</td>
						</tr>
				</tbody>
		</table>
		<p>在开始介绍 Groovy 模板之前，我想首先来回顾一下 Groovy 中 <code>String</code> 类型的概念。所有的脚本语言都试图使字符串的使用变得异常简单。再次声明，Groovy 并不是让我们的技能逐步退化。在开始之前，请点击本页面顶部或底部的 <b>Code</b> 图标（或者参阅 <a href="http://www.ibm.com/developerworks/cn/java/j-pg02155/index.html#download">下载</a> 一节的内容），下载本文的源代码。</p>
		<p>
				<a name="N10088">
						<span class="atitle">不能获得充足的 Strings</span>
				</a>
		</p>
		<p>不幸的是，Java™ 代码中的 Strings 非常有限，不过 Java 5.0 应用程序承诺将有一些引人注目的新特性。现在，Groovy 解决了两个最差的 Java <code>String</code> 限制，简化了编写多行字符串和进行运行时替换的功能。有一些简单的例子可以对 Groovy <code>String</code> 类型进行加速，在本文中我们将使用这些例子。</p>
		<p>如果您在普通的 Java 代码中编写一个多行的 <code>String</code> 类型，就会最终要使用很多讨厌的 <code>+</code> 号，对吗？但是在清单 1 中您可以看到，Groovy 不用再使用这些 <code>+</code> 号了，这使您可以编写更加清晰、简单的代码。</p>
		<br />
		<br />
		<a name="code1">
				<b>清单 1. Groovy 中的多行字符串</b>
		</a>
		<br />
		<table border="0" cellpadding="0" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td class="code-outline">
										<pre class="displaycode">String example1 = "This is a multiline<br />  string which is going to<br />  cover a few lines then<br />  end with a period."<br /></pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>Groovy 还支持 here-docs 的概念，如清单 2 所示。<i>here-doc</i> 是创建格式化 <code>String</code>（例如 HTML 和 XML）的一种便利机制。注意 here-doc 语法与普通的 <code>String</code> 声明并没有很大的不同，不过它需要类 Python 的三重引号。</p>
		<br />
		<br />
		<a name="code2">
				<b>清单 2. Groovy 中的 Here-docs</b>
		</a>
		<br />
		<table border="0" cellpadding="0" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td class="code-outline">
										<pre class="displaycode">itext =<br />"""<br />This is another multiline String<br />that takes up a few lines. Doesn't<br />do anything different from the previous one.<br />"""<br /></pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>Groovy 使用 <code>GString</code> 来简化运行时替换。如果您不知道 GString 是什么，我可以确信您之前肯定见过它，而且还可能使用过它。简单来说，<code>GString</code> 允许您使用 <i>与 bash 类似的</i><code>${}</code> 语法进行替换。<code>GString</code> 的优势是您从来都不需要知道自己正在使用的是 <code>GString</code> 类型；只需要在 Groovy 中简单地编写 <code>String</code> 即可，就仿佛是在 Java 代码中一样。</p>
		<table align="right" border="0" cellpadding="0" cellspacing="0" width="40%">
				<tbody>
						<tr>
								<td width="10">
										<img alt="" src="http://www.ibm.com/i/c.gif" height="1" width="10" />
								</td>
								<td>
										<table border="1" cellpadding="5" cellspacing="0" width="100%">
												<tbody>
														<tr>
																<td bgcolor="#eeeeee">
																		<a name="N100EC">
																				<b>关于模板引擎</b>
																		</a>
																		<br />
																		<p>模
板引擎已经存在很长一段时间了，几乎在每个现代语言中都可以找到。普通的 Java 语言具有 Velocity 和
FreeMarker；Python 有 Cheetah 和 Ruby ERB；Groovy
也有自己的引擎。要学习更多有关模板引擎的内容，请参阅 <a href="http://www.ibm.com/developerworks/cn/java/j-pg02155/index.html#resources">参考资料</a>。</p>
																</td>
														</tr>
												</tbody>
										</table>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<br />
		<a name="code3">
				<b>清单 3. Groovy 中的 GString</b>
		</a>
		<br />
		<table border="0" cellpadding="0" cellspacing="0" width="500">
				<tbody>
						<tr>
								<td class="code-outline">
										<pre class="displaycode">lang = "Groovy"<br />println "Uncle man, Uncle man, I dig ${lang}."<br /></pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>在清单 3 中，我们创建了一个名为 <code>lang</code> 的变量，并将其值设置为“Groovy”。我们打印了一个 <code>GString</code> 类型的 <code>String</code>，并要求将单词 “dig” 后面的内容替换为 <code>${lang}</code> 的值。如果实际运行一下，这段代码会打印“Uncle man, Uncle man, I dig Groovy.” 一切都不错，不是吗？</p>
		<p>运行时替换实际上是动态语言的一个通用特性；与其他情况一样，Groovy 还会更进一步。Groovy 的 <code>GString</code> 允许您对替换的值调用 <i>autocall</i> 方法，当开始构建动态文本时，这会产生很多变化。例如，在清单 4 中，我可以对指定的变量按照 <code>String</code> 对象类型调用一个方法（在本例中是 <code>length()</code> 方法）。</p>
		<br />
		<br />
		<a name="code5">
				<b>清单 4. GString 自动调用</b>
		</a>
		<br />
		<table border="0" cellpadding="0" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td class="code-outline">
										<pre class="displaycode">lang = "Groovy"<br />println "I dig any language with ${lang.length()} characters in its name!"<br /></pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>清单 4 中的代码会打印出“I dig any language with 6 characters in its name!”在下一节中，我将向您展示如何使用 Groovy 的自动调用特性在您的模板中启用一些复杂的特性。</p>
		<br />
		<table border="0" cellpadding="0" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td>
										<img src="http://www.ibm.com/i/v14/rules/blue_rule.gif" alt="" height="1" width="100%" />
										<br />
										<img alt="" src="http://www.ibm.com/i/c.gif" border="0" height="6" width="8" />
								</td>
						</tr>
				</tbody>
		</table>
		<table class="no-print" align="right" cellpadding="0" cellspacing="0">
				<tbody>
						<tr align="right">
								<td>
										<img src="http://www.ibm.com/i/c.gif" alt="" height="4" width="100%" />
										<br />
										<br />
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<br />
		<p>
				<a name="N10138">
						<span class="atitle">Groovy 模板</span>
				</a>
		</p>
		<p>对
模板的使用可以分解为两个主要的任务：首先，创建模板；其次，提供映射代码。使用 Groovy 模板框架创建模板与创建 JSP
非常类似，因为您可以重用 JSP 中见过的语法。创建这些模板的关键在于对那些运行时要替换的变量的定义。例如，在清单 5 中，我们为创建 <code>GroovyTestCase</code> 定义了一个模板。 </p>
		<br />
		<br />
		<a name="code5">
				<b>清单 5. 一个创建 GroovyTestCase 的模板</b>
		</a>
		<br />
		<table border="0" cellpadding="0" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td class="code-outline">
										<pre class="displaycode">import groovy.util.GroovyTestCase<br />class &lt;%=test_suite %&gt; extends GroovyTestCase {<br />  &lt;% for(tc in test_cases) {<br />     println "\tvoid ${tc}() { } "<br />  }%&gt;<br />}<br /></pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>清单 5 中的模板就类似于一个 JSP 文件，因为我们使用了 <code>&lt;%</code> 和 <code>&lt;%=</code> 语法。然而，由于 Groovy 的灵活性很好，因此您并不局限于使用 JSP 语法。您还可以自由使用 Groovy 中杰出的 <code>GString</code>，如清单 6 所示。</p>
		<br />
		<br />
		<a name="code6">
				<b>清单 6. GString 的使用</b>
		</a>
		<br />
		<table border="0" cellpadding="0" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td class="code-outline">
										<pre class="displaycode">&lt;person&gt;<br />  &lt;name first="${p.fname}" last="${p.lname}"/&gt;<br />&lt;/person&gt;<br /></pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>在清单 6 中，我创建了一个简单的模板，它表示一个定义 <code>person</code> 元素集合的 XML 文档。您可以看到这个模板期望一个具有 <code>fname</code> 和 <code>lname</code> 属性、名为 <code>p</code> 的对象。</p>
		<p>在 Groovy 中定义模板相当简单，其实应该就是这样简单才对。Groovy 模板并不是火箭科学，它们只不过是一种简化从模型中分离视图过程的手段。下一个步骤是编写运行时的映射代码。</p>
		<br />
		<table border="0" cellpadding="0" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td>
										<img src="http://www.ibm.com/i/v14/rules/blue_rule.gif" alt="" height="1" width="100%" />
										<br />
										<img alt="" src="http://www.ibm.com/i/c.gif" border="0" height="6" width="8" />
								</td>
						</tr>
				</tbody>
		</table>
		<table class="no-print" align="right" cellpadding="0" cellspacing="0">
				<tbody>
						<tr align="right">
								<td>
										<img src="http://www.ibm.com/i/c.gif" alt="" height="4" width="100%" />
										<br />
										<br />
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<br />
		<p>
				<a name="N10180">
						<span class="atitle">运行时映射</span>
				</a>
		</p>
		<p>既然已经定义了一个模板，我们就可以通过在已定义的变量和运行时值之间建立映射来使用这个模板了。与 Groovy 中常见的一样，有些看来似乎很复杂的东西实际上是非常简单的。我所需要的是一个 <code>映射</code>，其关键字是模板中的变量名，键值是运行时的值。</p>
		<p>例如，如果一个简单的模板有一个名为 <code>favlang</code> 的变量，我就需要与 <code>favlang</code> 键值建立一个 <code>映射</code>。这个键值可以是根据我自己的喜好选择的任何脚本语言（在本例中，当然是 Groovy）。</p>
		<p>在清单 7 中，我们定义了这样一个简单的模板，在清单 8 中，我将向您展示对应的映射代码。</p>
		<br />
		<br />
		<a name="code7">
				<b>清单 7. 用来展示映射的简单代码</b>
		</a>
		<br />
		<table border="0" cellpadding="0" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td class="code-outline">
										<pre class="displaycode">My favorite dynamic language is ${favlang}<br /></pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>清单 8 显示了一个简单的类，它一共做了 5 件事，其中有 2 件是很重要的。您可以说出它们是什么吗？</p>
		<br />
		<br />
		<a name="code8">
				<b>清单 8. 为一个简单的模板映射值</b>
		</a>
		<br />
		<table border="0" cellpadding="0" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td class="code-outline">
										<pre class="displaycode">package com.vanward.groovy.tmpl<br />import groovy.text.Template<br />import groovy.text.SimpleTemplateEngine<br />import java.io.File<br />class SimpleTemplate{<br />  static void main(args) {<br />    fle = new File("simple-txt.tmpl")<br />    binding = ["favlang": "Groovy"]<br />    engine = new SimpleTemplateEngine()<br />    template = engine.createTemplate(fle).make(binding)<br />    println template.toString()<br />  }<br />}<br /></pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>在清单 8 中为这个简单的模板映射值简单得令人吃惊。</p>
		<p>首先，我创建了一个 <code>File</code> 实例，它指向模板 <code>simple-txt.tmpl</code>。</p>
		<p>然后创建了一个 <code>binding</code> 对象；实际上，这就是一个 <code>映射</code>。我将在模板中找到的值 <code>favlang</code> 映射到 <code>String</code> Groovy 上。这种映射是在 Groovy 中使用模板最重要的步骤，或者说在任何具有模板引擎的语言中都是如此。</p>
		<p>接下来，我创建了一个 <code>SimpleTemplateEngine</code> 实例，在 Groovy 中，它恰巧就是模板引擎框架的一个具体实现。然后我将模板（<code>simple-txt.tmpl</code>）和 <code>binding</code> 对象传递给这个引擎实例。在清单 8 中，第二个重要的步骤是将模板及其 <code>binding</code> 对象绑定在一起，这也是使用模板引擎的关键所在。从内部来说，框架将在从 <code>binding</code> 对象中找到的值与对应模板中的名字之间建立映射。</p>
		<p>清单 8 中的最后一个步骤是打印进程的输出信息。正如您可以看到的一样，创建一个 <code>binding</code> 对象并提供正确的映射是件轻而易举的小事，至少在我们这个简单的例子中是如此。在下一节中，我们将会使用一个更加复杂的例子对 Groovy 模板引擎进行测试。</p>
		<br />
		<table border="0" cellpadding="0" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td>
										<img src="http://www.ibm.com/i/v14/rules/blue_rule.gif" alt="" height="1" width="100%" />
										<br />
										<img alt="" src="http://www.ibm.com/i/c.gif" border="0" height="6" width="8" />
								</td>
						</tr>
				</tbody>
		</table>
		<table class="no-print" align="right" cellpadding="0" cellspacing="0">
				<tbody>
						<tr align="right">
								<td>
										<img src="http://www.ibm.com/i/c.gif" alt="" height="4" width="100%" />
										<br />
										<br />
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<br />
		<p>
				<a name="N101F7">
						<span class="atitle">更复杂的模板</span>
				</a>
		</p>
		<p>在清单 9 中，我已经创建了一个 <code>Person</code> 类来表示在 <a href="http://www.ibm.com/developerworks/cn/java/j-pg02155/index.html#code6">清单 6</a> 中定义的 <code>person</code> 元素。</p>
		<br />
		<br />
		<a name="code9">
				<b>清单 9. Groovy 中的 Person 类</b>
		</a>
		<br />
		<table border="0" cellpadding="0" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td class="code-outline">
										<pre class="displaycode">class Person{<br /> age<br /> fname<br /> lname<br /> String toString(){<br />  return "Age: " + age + " First Name: " + fname + " Last Name: " + lname<br /> }<br />}<br /></pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>在清单 10 中，您可以看到对上面定义的 <code>Person</code> 类的实例进行映射的代码。</p>
		<br />
		<br />
		<a name="code10">
				<b>清单 10. 在 Person 类与模板之间建立映射</b>
		</a>
		<br />
		<table border="0" cellpadding="0" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td class="code-outline">
										<pre class="displaycode">import java.io.File<br />import groovy.text.Template<br />import groovy.text.SimpleTemplateEngine<br />class TemplatePerson{<br />  static void main(args) {<br />    pers1 = new Person(age:12, fname:"Sam", lname:"Covery")<br />    fle = new File("person_report.tmpl")<br />    binding = ["p":pers1]<br />    engine = new SimpleTemplateEngine()<br />    template = engine.createTemplate(fle).make(binding)<br />    println template.toString()<br />  }<br />}<br /></pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>上面的代码看起来很熟悉，不是吗？实际上，它与 <a href="http://www.ibm.com/developerworks/cn/java/j-pg02155/index.html#code8">清单 8</a> 非常类似，不过增加了一行创建 <code>pers1</code> 实例的代码。现在，再次快速查看一下 <a href="http://www.ibm.com/developerworks/cn/java/j-pg02155/index.html#code6">清单 6</a> 中的代码。您看到模板是如何引用属性 <code>fname</code> 和 <code>lname</code> 的了吗？我所做的操作是创建一个 <code>Person</code> 实例，其 <code>fname</code> 属性设置为“Sam”，属性 <code>lname</code> 设置为“Covery”。 </p>
		<p>在运行清单 10 中的代码时，输出结果是 XML 文件，用来定义 <code>person</code> 元素，如清单 11 所示。</p>
		<br />
		<br />
		<a name="code11">
				<b>清单 11. Person 模板的输出结果</b>
		</a>
		<br />
		<table border="0" cellpadding="0" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td class="code-outline">
										<pre class="displaycode">&lt;person&gt;<br />  &lt;name first="Sam" last="Covery"/&gt;<br />&lt;/person&gt;<br /></pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>
				<a name="N1025E">
						<span class="smalltitle">映射一个列表</span>
				</a>
		</p>
		<p>在 <a href="http://www.ibm.com/developerworks/cn/java/j-pg02155/index.html#code5">清单 5</a> 中，我为 <code>GroovyTestCase</code> 定义了一个模板。现在如果您看一下这个模板，就会注意到这个定义有一些逻辑用于在一个集合上迭代。在清单 12 中，您将看到一些非常类似的代码，不过这些代码的逻辑是用来映射一个测试用例 <code>列表</code>的。</p>
		<br />
		<br />
		<a name="code12">
				<b>清单 12. 映射测试用例列表</b>
		</a>
		<br />
		<table border="0" cellpadding="0" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td class="code-outline">
										<pre class="displaycode">fle = new File("unit_test.tmpl")<br />coll = ["testBinding", "testToString", "testAdd"]<br />binding = ["test_suite":"TemplateTest", "test_cases":coll]<br />engine = new SimpleTemplateEngine()<br />template = engine.createTemplate(fle).make(binding)<br />println template.toString()<br /></pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>查看一下 <a href="http://www.ibm.com/developerworks/cn/java/j-pg02155/index.html#code5">清单 5</a>，它显示了模板期望一个名为“test_cases”的 <code>列表</code> —— 在清单 12 中它定义为 <code>coll</code>，包含 3 个元素。我简单地将 <code>coll</code> 设置为“test_cases”绑定对象中的键值，现在代码就准备好运行了。</p>
		<p>现在应该十分清楚了，Groovy 模板非常容易使用。它还可以促进无所不在的 MVC 模式的使用；更重要的是，它们可以通过表示视图来支持转换为 MVC 代码。在下一节中，我将向您展示如何对上一篇文章中的一个例子应用本文中所学到的知识。
</p>
		<br />
		<table border="0" cellpadding="0" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td>
										<img src="http://www.ibm.com/i/v14/rules/blue_rule.gif" alt="" height="1" width="100%" />
										<br />
										<img alt="" src="http://www.ibm.com/i/c.gif" border="0" height="6" width="8" />
								</td>
						</tr>
				</tbody>
		</table>
		<table class="no-print" align="right" cellpadding="0" cellspacing="0">
				<tbody>
						<tr align="right">
								<td>
										<img src="http://www.ibm.com/i/c.gif" alt="" height="4" width="100%" />
										<br />
										<br />
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<br />
		<p>
				<a name="N10294">
						<span class="atitle">使用模板重构之前的例子</span>
				</a>
		</p>
		<p>在使用 Groovy 编写 Ant 脚本的专栏中，我曾经编写了一个简单的工具，它对类文件产生校验和报告。如果您还记得，我当时笨拙地使用 <code>println</code> 语句来产生 XML 文件。尽管我只能接受这段代码，但它是如此地晦涩，这您只需要看一下清单 13 就会一目了然。</p>
		<br />
		<br />
		<a name="code13">
				<b>清单 13. 糟糕的代码
</b>
		</a>
		<br />
		<table border="0" cellpadding="0" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td class="code-outline">
										<pre class="displaycode">nfile.withPrintWriter{ pwriter |<br />  pwriter.println("&lt;md5report&gt;")<br />    for(f in scanner){<br />       f.eachLine{ line |<br />         pwriter.println("&lt;md5 class='" + f.path + "' value='" + line + "'/&gt;")<br />       }<br />    }<br />  pwriter.println("&lt;/md5report&gt;")<br />}<br /></pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>为了帮您回顾一下有关这段内容的记忆，清单 13 中的代码使用了一些数据，并使用 <code>PrintWriter</code> 将其写入一个文件中（<code>nfile</code> 实例）。注意我是如何将报告的视图组件（XML）硬编码在 <code>println</code> 中的。这种方法的问题是它不够灵活。之后，如果我需要进行一些修改，就只能进入到 Groovy 脚本的逻辑中进行修改。在更糟糕的情况下，设想一下一个非程序员想要进行一些修改会是什么样子。Groovy 代码会受到很大的威胁。
</p>
		<p>将该脚本中的视图部分移动到模板中可以使维护更加方便，因为修改模板是任何人都会涉及的一个过程，因此我在此处也会这样做。</p>
		<p>
				<a name="N102BE">
						<span class="smalltitle">定义模板</span>
				</a>
		</p>
		<p>现在我将开始定义模板了 —— 它看起来更加类似于想要的输出结果，采用了一些逻辑来循环遍历一组类。</p>
		<br />
		<br />
		<a name="code14">
				<b>清单 14. 为原来的代码应用模板</b>
		</a>
		<br />
		<table border="0" cellpadding="0" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td class="code-outline">
										<pre class="displaycode">&lt;md5report&gt;<br />&lt;% for(clzz in clazzes) {<br />  println "&lt;md5 class=\"${clzz.name}\" value=\"${clzz.value}\"/&gt;"<br />}%&gt;<br />&lt;/md5report&gt;<br /></pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>清单 14 中定义的模板与为 <code>GroovyTestCase</code> 定义的模板类似，其中包括循环遍历一个集合的逻辑。还要注意我在此处混合使用了 JSP 和 <code>GString</code> 的语法。</p>
		<p>
				<a name="N102DD">
						<span class="smalltitle">编写映射代码</span>
				</a>
		</p>
		<p>定义好模板之后，下一个步骤是编写运行时的映射代码。我需要将原来的写入文件的逻辑替换为下面的代码：构建一个 <code>ChecksumClass</code> 对象集合，然后将这些对象放到 <code>binding</code> 对象中。</p>
		<p>这个模型然后就会变成清单 15 中定义的 <code>ChecksumClass</code>。</p>
		<br />
		<br />
		<a name="code15">
				<b>清单 15. 在 Groovy 中定义的 CheckSumClass</b>
		</a>
		<br />
		<table border="0" cellpadding="0" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td class="code-outline">
										<pre class="displaycode">class CheckSumClass{<br />  name<br />  value<br />  String toString(){<br />   return "name " + name + " value " + value<br />  }<br />}<br /></pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>Groovy 中类的定义非常简单，不是吗？</p>
		<p>
				<a name="N10303">
						<span class="smalltitle">创建集合</span>
				</a>
		</p>
		<p>接下来，我需要重构刚才写入文件的那段代码 —— 这一次采用一定的逻辑使用 <code>ChecksumClass</code> 构造一个列表，如清单 16 所示。</p>
		<br />
		<br />
		<a name="code16">
				<b>清单 16. 重构代码创建一个 ChecksumClass 的集合
</b>
		</a>
		<br />
		<table border="0" cellpadding="0" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td class="code-outline">
										<pre class="displaycode">clssez = []<br />for(f in scanner){<br />  f.eachLine{ line |<br />   iname = formatClassName(bsedir, f.path)<br />   clssez &lt;&lt; new CheckSumClass(name:iname, value:line)<br />  }<br />}<br /></pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>清单 16 显示了使用类 Ruby 的语法将对象添加到 <code>列表</code> 中是多么简单 —— 这就是 <i>奇妙的</i> groovy。我首先使用 <code>[]</code> 语法创建 <code>清单</code>。然后使用简短的 <code>for</code> 循环，后面是一个带有闭包的迭代器。这个闭包接受每一个 <code>line</code>（在本例中是一个校验和值），并创建一个新定义的 <code>CheckSumClass</code> 实例（使用 Groovy 的自动生成的构造函数），并将二者添加到集合中。还不错 —— 这样编写起来也很有趣。</p>
		<p>
				<a name="N10339">
						<span class="smalltitle">添加模板映射</span>
				</a>
		</p>
		<p>我需要做的最后一件事情是添加模板引擎特定的代码。这段代码将执行运行时映射，并将对应的格式化后的模板写入原始的文件中，如清单 17 所示。</p>
		<br />
		<br />
		<a name="code17">
				<b>清单 17. 使用模板映射重构原来的代码</b>
		</a>
		<br />
		<table border="0" cellpadding="0" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td class="code-outline">
										<pre class="displaycode">fle = new File("report.tmpl")<br />binding = ["clazzes": clzzez]<br />engine = new SimpleTemplateEngine()<br />template = engine.createTemplate(fle).make(binding)<br />nfile.withPrintWriter{ pwriter |<br />  pwriter.println template.toString()<br />}<br /></pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>现在，清单 17 中的代码对您来说太陈旧了。我利用了清单 16 中的 <code>列表</code>，并将其放入 <code>binding</code> 对象。然后读取 <code>nfile</code> 对象，并将相应的输出内容从 <a href="http://www.ibm.com/developerworks/cn/java/j-pg02155/index.html#code14">清单 14</a> 中的映射模板写入文件中。 </p>
		<p>在将这些内容都放入清单 18 之前，您可能希望返回 <a href="http://www.ibm.com/developerworks/cn/java/j-pg02155/index.html#code13">清单 13</a> 最后看一眼开始时使用的那段蹩脚的代码。下面是新的代码，您可以进行比较一下：</p>
		<br />
		<br />
		<a name="code18">
				<b>清单 18. 看，新的代码！</b>
		</a>
		<br />
		<table border="0" cellpadding="0" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td class="code-outline">
										<pre class="displaycode">/**<br /> *<br /> */<br />buildReport(bsedir){<br /> ant = new AntBuilder()<br /> scanner = ant.fileScanner {<br />   fileset(dir:bsedir) {<br />     include(name:"**/*class.md5.txt")<br />   }<br /> }<br /> rdir = bsedir + File.separator + "xml" + File.separator<br /> file = new File(rdir)<br /> if(!file.exists()){<br />   ant.mkdir(dir:rdir)<br /> }<br /> nfile = new File(rdir + File.separator + "checksum.xml")<br /> clssez = []<br /> for(f in scanner){<br />   f.eachLine{ line |<br />    iname = formatClassName(bsedir, f.path)<br />    clssez &lt;&lt; new CheckSumClass(name:iname, value:line)<br />   }<br /> }<br /> fle = new File("report.tmpl")<br /> binding = ["clazzes": clzzez]<br /> engine = new SimpleTemplateEngine()<br /> template = engine.createTemplate(fle).make(binding)<br /> nfile.withPrintWriter{ pwriter |<br />   pwriter.println template.toString()<br /> }<br />}<br /></pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>现在，虽然我没有声明要编写非常漂亮的代码，但是这些代码当然不会像原来的代码一样 <i>糟糕</i> 了。回顾一下，我所干的事情不过是将一些蹩脚的 <code>println</code> 替换成 Groovy 的更精巧的模板代码。（一些熟悉重构的人可能会说我应该使用 <i>Extract Method</i> 进一步对代码进行优化。）</p>
		<br />
		<table border="0" cellpadding="0" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td>
										<img src="http://www.ibm.com/i/v14/rules/blue_rule.gif" alt="" height="1" width="100%" />
										<br />
										<img alt="" src="http://www.ibm.com/i/c.gif" border="0" height="6" width="8" />
								</td>
						</tr>
				</tbody>
		</table>
		<table class="no-print" align="right" cellpadding="0" cellspacing="0">
				<tbody>
						<tr align="right">
								<td>
										<img src="http://www.ibm.com/i/c.gif" alt="" height="4" width="100%" />
										<br />
										<br />
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<br />
		<p>
				<a name="N1037F">
						<span class="atitle">结束语</span>
				</a>
		</p>
		<p>在本月的教程中，我希望已经向您展示了 Groovy 的 <i>视图</i>。更<i>明确地</i> 说，当您需要快速开发一些需要视图的简单程序时，Groovy 的模板框架是普通 Java 编码的一种很好的替代品。模板是很好的一种抽象，如果使用正确，它可以极大地降低应用程序的维护成本。</p>
		<p>下一个月，我将向您展示如何使用 Groovy 来构建使用 Groovlets 的 Web 应用程序。现在，享受使用 Groovy 的模板开发吧！</p>
<img src ="http://www.blogjava.net/JafeLee/aggbug/128672.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/JafeLee/" target="_blank">Jafe</a> 2007-07-06 21:03 <a href="http://www.blogjava.net/JafeLee/articles/128672.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>实战 Groovy: 用 Groovy 进行 JDBC 编程</title><link>http://www.blogjava.net/JafeLee/articles/128671.html</link><dc:creator>Jafe</dc:creator><author>Jafe</author><pubDate>Fri, 06 Jul 2007 13:01:00 GMT</pubDate><guid>http://www.blogjava.net/JafeLee/articles/128671.html</guid><wfw:comment>http://www.blogjava.net/JafeLee/comments/128671.html</wfw:comment><comments>http://www.blogjava.net/JafeLee/articles/128671.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/JafeLee/comments/commentRss/128671.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/JafeLee/services/trackbacks/128671.html</trackback:ping><description><![CDATA[
		<p>
				<a href="http://www.ibm.com/developerworks/cn/java/j-pg01115.html#author">Andrew Glover</a> (<a href="mailto:aglover@vanwardtechnologies.com?subject=%E7%94%A8%20Groovy%20%E8%BF%9B%E8%A1%8C%20JDBC%20%E7%BC%96%E7%A8%8B">aglover@vanwardtechnologies.com</a>), CTO, Vanward Technologies<br /></p>
		<p>2005 年  1 月  11 日</p>
		<blockquote>这
个月，随着 Andrew Glover 向您演示如何用 GroovySql 构建简单的数据报告应用程序，您对 Groovy
的实用知识会更进一步。GroovySql 结合利用闭包（closure）和迭代器（iterator），把资源管理的负担转移到 Groovy
框架本身，从而简化了 Java 数据库连通性（Java Database Connectivity，JDBC）的编程。</blockquote>
		<!--START RESERVED FOR FUTURE USE INCLUDE FILES-->
		<!-- include java script once we verify teams wants to use this and it will work on dbcs and cyrillic characters -->
		<!--END RESERVED FOR FUTURE USE INCLUDE FILES-->
		<p>在 
        <i>实战 Groovy</i> 系列的前几期中，您已经了解了 Groovy 的一些非常优美的特性。在 
        <a href="http://www.ibm.com/developerworks/java/library/j-pg11094/?S_TACT=105AGX52&amp;S_CMP=cn-a-j">第 1 期</a> 中，学习了如何用 Groovy 对普通的 Java™ 代码进行更简单、更迅速的单元测试。在 
        <a href="http://www.ibm.com/developerworks/library/j-pg12144.html?S_TACT=105AGX52&amp;S_CMP=cn-a-j">第 2 期</a> 中，看到了 Groovy 能够给 Ant 构建带来的表现能力。这一次您会发现 Groovy 的另一个实际应用，即如何用它迅速地构建基于 SQL 的报告应用程序。
      </p>
		<p>脚
本语言对于迅速地构建报告应用程序来说是典型的优秀工具，但是构建这类应用程序对于 Groovy 来说特别容易。Groovy 轻量级的语法可以消除
Java 语言的 JDBC 的一些繁冗之处，但是它真正的威力来自闭包，闭包很优雅地把资源管理的责任从客户机转移到框架本身，因此更容易举重若轻。</p>
		<p>在本月的文章中，我先从 GroovySql 的概述开始，然后通过构建一个简单的数据报告应用程序，向您演示如何将它们投入工作。为了从讨论中得到最大收获，您应当熟悉 Java 平台上的 JDBC 编程。您可能还想回顾 
        <a href="http://www.ibm.com/developerworks/library/j-pg12144.html?S_TACT=105AGX52&amp;S_CMP=cn-a-j">上个月对 Groovy 中闭包的介绍</a>，因为它们在这里扮演了重要的角色。但是，本月关注的重点概念是迭代（iteration），因为迭代器在 Groovy 对 JDBC 的增强中扮演着重要角色。所以，我将从 Groovy 中迭代器的概述开始。
      </p>
		<p>
				<a name="N1005D">
						<span class="atitle">进入迭代器</span>
				</a>
		</p>
		<p>迭代是各种编程环境中最常见、最有用的技术。
        <i>迭代器</i> 是某种代码助手，可以让您迅速地访问任何集合或容器中的数据，每次一个数据。Groovy 把迭代器变成隐含的，使用起来更简单，从而改善了 Java 语言的迭代器概念。在清单 1 中，您可以看到使用 Java 语言打印 
        <code>String</code> 集合的每个元素需要做的工作。
      </p>
		<br />
		<br />
		<a name="code1">
				<b>清单 1. 普通 Java 代码中的迭代器</b>
		</a>
		<br />
		<table border="0" cellpadding="0" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td class="code-outline">
										<pre class="displaycode">import java.util.ArrayList;<br />import java.util.Collection;<br />import java.util.Iterator;<br />public class JavaIteratorExample {<br />  public static void main(String[] args) {<br />     Collection coll = new ArrayList();<br />     coll.add("JMS");<br />     coll.add("EJB");<br />     coll.add("JMX");<br />     for(Iterator iter = coll.iterator(); iter.hasNext();){<br />        System.out.println(iter.next());<br />     }<br />  }<br />}<br /></pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>在清单 2 中，您可以看到 Groovy 如何简化了我的工作。在这里，我跳过了 
        <code>Iterator</code> 接口，直接在集合上使用类似迭代器的方法。而且，
Groovy 的迭代器方法接受闭包，每个迭代中都会调用闭包。清单 2 显示了前面基于 Java 语言的示例用 Groovy 转换后的样子。
      </p>
		<br />
		<br />
		<a name="code3">
				<b>清单 2. Groovy 中的迭代器</b>
		</a>
		<br />
		<table border="0" cellpadding="0" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td class="code-outline">
										<pre class="displaycode">class IteratorExample1{<br />   static void main(args) {<br />     coll = ["JMS", "EJB", "JMX"]<br />     coll.each{ item | println item }<br />   }<br />}<br /></pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>您可以看到，与典型的 Java
代码不同，Groovy 在允许我传递进我需要的行为的同时，控制了特定于迭代的代码。使用这个控制，Groovy
干净漂亮地把资源管理的责任从我手上转移到它自己身上。让 Groovy 负责资源管理是极为强大的。它还使编程工作更加容易，从而也就更迅速。 </p>
		<table align="right" border="0" cellpadding="0" cellspacing="0" width="40%">
				<tbody>
						<tr>
								<td width="10">
										<img alt="" src="http://www.ibm.com/i/c.gif" height="1" width="10" />
								</td>
								<td>
										<br />
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<table border="0" cellpadding="0" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td>
										<img src="http://www.ibm.com/i/v14/rules/blue_rule.gif" alt="" height="1" width="100%" />
										<br />
										<img alt="" src="http://www.ibm.com/i/c.gif" border="0" height="6" width="8" />
								</td>
						</tr>
				</tbody>
		</table>
		<table class="no-print" align="right" cellpadding="0" cellspacing="0">
				<tbody>
						<tr align="right">
								<td>
										<img src="http://www.ibm.com/i/c.gif" alt="" height="4" width="100%" />
										<br />
										<br />
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<br />
		<p>
				<a name="N1009F">
						<span class="atitle">GroovySql 简介</span>
				</a>
		</p>
		<p>Groovy
的 SQL 魔力在于一个叫做 GroovySql 的精致的 API。使用闭包和迭代器，GroovySql 干净漂亮地把 JDBC
的资源管理职责从开发人员转移到 Groovy 框架。这么做之后，就消除了 JDBC 编程的繁琐，从而使您可以把注意力放在查询和查询结果上。</p>
		<p>如果您忘记了普通的 Java JDBC 编程有多麻烦，我会很高兴提醒您！在清单 3 中，您可以看到用 Java 语言进行的一个简单的 JDBC 编程示例。</p>
		<br />
		<br />
		<a name="code3">
				<b>清单 3. 普通 Java 的 JDBC 编程</b>
		</a>
		<br />
		<table border="0" cellpadding="0" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td class="code-outline">
										<pre class="displaycode">import java.sql.Connection;<br />import java.sql.DriverManager;<br />import java.sql.ResultSet;<br />import java.sql.SQLException;<br />import java.sql.Statement;<br />public class JDBCExample1 {<br />  public static void main(String[] args) {<br />    Connection con = null;<br />    Statement stmt = null;<br />    ResultSet rs = null;<br />    try{<br />      Class.forName("org.gjt.mm.mysql.Driver");<br />      con = DriverManager.getConnection("jdbc:mysql://localhost:3306/words",<br />           "words", "words");<br />      stmt = con.createStatement();<br />      rs = stmt.executeQuery("select * from word");<br />      while (rs.next()) {<br />        System.out.println("word id: " + rs.getLong(1) +<br />            " spelling: " + rs.getString(2) +<br />            " part of speech: " + rs.getString(3));<br />      }<br />    }catch(SQLException e){<br />      e.printStackTrace();<br />    }catch(ClassNotFoundException e){<br />      e.printStackTrace();<br />    }finally{<br />      try{rs.close();}catch(Exception e){}<br />      try{stmt.close();}catch(Exception e){}<br />      try{con.close();}catch(Exception e){}<br />   }<br />  }<br />}<br /></pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>哇。清单 3 包含近 40
行代码，就是为了查看表中的内容！如果用 GroovySql，您猜要用多少行？如果您猜超过 10 行，那么您就错了。请看清单 4
中，Groovy 替我处理底层资源，从而非常漂亮地让我把注意力集中在手边的任务 —— 执行一个简单的查询。</p>
		<br />
		<br />
		<a name="code4">
				<b>清单 4. 欢迎使用 GroovySql！</b>
		</a>
		<br />
		<table border="0" cellpadding="0" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td class="code-outline">
										<pre class="displaycode">import groovy.sql.Sql<br />class GroovySqlExample1{<br />  static void main(args) {<br />    sql = Sql.newInstance("jdbc:mysql://localhost:3306/words", "words",<br />           "words", "org.gjt.mm.mysql.Driver")<br />    sql.eachRow("select * from word"){ row |<br />       println row.word_id + " " + row.spelling + " " + row.part_of_speech<br />    }<br />  }<br />}<br /></pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p> 真不错。只用了几行，我就编码出与清单 3 相同的行为，不用关闭 
        <code>Connection</code>，也不用关闭 
        <code>ResultSet</code>，或者在 JDBC 编程中可以找到的任何其他熟悉的重要特性。这是多么激动人心的事情啊，并且还是如此容易。现在让我来仔细介绍我是如何做到的。
      </p>
		<br />
		<table border="0" cellpadding="0" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td>
										<img src="http://www.ibm.com/i/v14/rules/blue_rule.gif" alt="" height="1" width="100%" />
										<br />
										<img alt="" src="http://www.ibm.com/i/c.gif" border="0" height="6" width="8" />
								</td>
						</tr>
				</tbody>
		</table>
		<table class="no-print" align="right" cellpadding="0" cellspacing="0">
				<tbody>
						<tr align="right">
								<td>
										<img src="http://www.ibm.com/i/c.gif" alt="" height="4" width="100%" />
										<br />
										<br />
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<br />
		<p>
				<a name="N100CD">
						<span class="atitle">执行简单的查询</span>
				</a>
		</p>
		<p>在 
        <a href="http://www.ibm.com/developerworks/cn/java/j-pg01115.html#code4">清单 4</a> 的第一行中，我创建了 Groovy 的 
        <code>Sql</code> 类的实例，用它来连接指定的数据库。在这个例子中，我创建了 
        <code>Sql</code> 实例，指向在我机器上运行的 MySQL 数据库。到现在为止都非常基本，对么？真正重要的是一下部分，迭代器和闭包一两下就显示出了它们的威力。
      </p>
		<p>请把 
        <code>eachRow</code> 方法当成传进来的查询生成的结果上的迭代器。在底层，您可以看到返回了 JDBC 
        <code>ResultSet</code> 对象，它的内容被传递进 
        <code>for</code> 循环。所以，每个迭代都要执行我传递进去的闭包。如果在数据库中找到的 
        <code>word</code> 表只有三行，那么闭包就会执行三次 —— 打印出 
        <code>word_id</code>、
        <code>spelling</code> 和
        <code>part_of_speech</code> 的值。 
      </p>
		<p>如果将等式中我指定的变量 
        <code>row</code> 去掉，而使用 Groovy 的一个隐含变量 
        <code>it</code>（它恰好就是迭代器的实例），代码可以进一步简化。如果我这样做，那么前面的代码就可以写成清单 5 所示的这样：
      </p>
		<br />
		<br />
		<a name="code5">
				<b>清单 5. GroovySql 中的 
        it 变量
      </b>
		</a>
		<br />
		<table border="0" cellpadding="0" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td class="code-outline">
										<pre class="displaycode">import groovy.sql.Sql<br />class GroovySqlExample1{<br />  static void main(args) {<br />    sql = Sql.newInstance("jdbc:mysql://localhost:3306/words", "words",<br />           "words", "org.gjt.mm.mysql.Driver")<br />    sql.eachRow("select * from word"){ println it.spelling +  " ${it.part_of_speech}"}<br />  }<br />}<br /></pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>在这个代码中，我可以删除 
        <code>row</code> 变量，用 
        <code>it</code> 代替。而且，我还能在 
        <code>String</code> 语句中引用 
        <code>it</code> 变量，就像我在 
        <code>${it.part_of_speech}</code> 中所做的那样。 
      </p>
		<br />
		<table border="0" cellpadding="0" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td>
										<img src="http://www.ibm.com/i/v14/rules/blue_rule.gif" alt="" height="1" width="100%" />
										<br />
										<img alt="" src="http://www.ibm.com/i/c.gif" border="0" height="6" width="8" />
								</td>
						</tr>
				</tbody>
		</table>
		<table class="no-print" align="right" cellpadding="0" cellspacing="0">
				<tbody>
						<tr align="right">
								<td>
										<img src="http://www.ibm.com/i/c.gif" alt="" height="4" width="100%" />
										<br />
										<br />
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<br />
		<p>
				<a name="N10131">
						<span class="atitle">执行更复杂的查询</span>
				</a>
		</p>
		<p>前面的例子相当简单，但是 GroovySql 在处理更复杂的数据操纵查询（例如 
        <code>insert</code>、
        <code>update</code> 和 
        <code>delete</code> 查询）时，也是非常可靠的。 对于这些查询，您没有必要用迭代器，所以 Groovy 的 
        <code>Sql</code> 对象另外提供了 
        <code>execute</code> 和 
        <code>executeUpdate</code> 方法。这些方法让人想起普通的 JDBC 
        <code>statement</code> 类，它也有 
        <code>execute</code> 和 
        <code>executeUpdate</code> 方法。
      </p>
		<p>在清单 6 中，您看到一个简单的 
        <code>insert</code>，它再次以 
        <code>${}</code> 语法使用变量替换。这个代码只是向 
        <code>word</code> 表插入一个新行。 
      </p>
		<br />
		<br />
		<a name="code6">
				<b>清单 6. 用 GroovySql 进行插入 </b>
		</a>
		<br />
		<table border="0" cellpadding="0" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td class="code-outline">
										<pre class="displaycode"> wid = 999<br /> spelling = "Nefarious"<br /> pospeech = "Adjective"<br /> sql.execute("insert into word (word_id, spelling, part_of_speech) <br />   values (${wid}, ${spelling}, ${pospeech})")<br /></pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>Groovy 还提供 
        <code>execute</code> 方法的一个重载版本，它接收一列值，这些值与查询中发现的 
        <code>?</code> 元素对应。在清单 7 中，我简单地查询了 
        <code>word</code> 表中的某个行。在底层，GroovySql 创建了普通 Java 语言 
        <code>java.sql.PreparedStatement</code> 的一个实例。
      </p>
		<br />
		<br />
		<a name="code7">
				<b>清单 7. 用 GroovySql 创建 PreparedStatement 的实例</b>
		</a>
		<br />
		<table border="0" cellpadding="0" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td class="code-outline">
										<pre class="displaycode">val = sql.execute("select * from word where word_id = ?", [5])<br /></pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>更新的方式基本相同，也使用 
        <code>executeUpdate</code> 方法。还请注意，在清单 8 中 
        <code>executeUpdate</code> 方法接收一列值，与查询中的 
        <code>?</code> 元素对应。
      </p>
		<br />
		<br />
		<a name="code8">
				<b>清单 8. 用 GroovySql 进行更新</b>
		</a>
		<br />
		<table border="0" cellpadding="0" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td class="code-outline">
										<pre class="displaycode"> nid = 5<br /> spelling = "Nefarious"<br /> sql.executeUpdate("update word set word_id = ? where spelling = ?", [nid, spelling])<br /></pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>删除实际上与插入相同，当然，语法不同，如清单 9 所示。</p>
		<br />
		<br />
		<a name="code9">
				<b>清单 9. 用 GroovySql 进行删除</b>
		</a>
		<br />
		<table border="0" cellpadding="0" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td class="code-outline">
										<pre class="displaycode"> sql.execute("delete from word where word_id = ?" , [5])<br /></pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<br />
		<table border="0" cellpadding="0" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td>
										<img src="http://www.ibm.com/i/v14/rules/blue_rule.gif" alt="" height="1" width="100%" />
										<br />
										<img alt="" src="http://www.ibm.com/i/c.gif" border="0" height="6" width="8" />
								</td>
						</tr>
				</tbody>
		</table>
		<table class="no-print" align="right" cellpadding="0" cellspacing="0">
				<tbody>
						<tr align="right">
								<td>
										<img src="http://www.ibm.com/i/c.gif" alt="" height="4" width="100%" />
										<br />
										<br />
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<br />
		<p>
				<a name="N101BA">
						<span class="atitle">简化数据操纵</span>
				</a>
		</p>
		<p>任何想简化 JDBC 编程的 API 或工具最好有一些好的数据操纵特性，在这一节中，我要向您再介绍三个。</p>
		<p>
				<a name="N101C3">
						<span class="smalltitle">数据集(DataSet)</span>
				</a>
		</p>
		<p>构建于 GroovySql 简单性的基础之上，GroovySql 支持 
        <code>DataSet</code> 类型的概念，这基本上是数据库表的对象表示。使用 
        <code>DataSet</code>，您可以在行中遍历，也可以添加新行。实际上，用数据集是方便地表示表格的公共数据集合的方式。 
      </p>
		<p>但是，目前 GroovySql 
        <code>DataSet</code> 类型的不足之处是它们没有代表关系；它们只是与数据库表的一对一映射。在清单 10 中，我创建了一个来自 
        <code>word</code> 表的 
        <code>DataSet</code>。
      </p>
		<br />
		<br />
		<a name="code10">
				<b>清单 10. 用 GroovySql 创建数据集</b>
		</a>
		<br />
		<table border="0" cellpadding="0" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td class="code-outline">
										<pre class="displaycode">import groovy.sql.Sql<br />class GroovyDatasetsExample1{<br />  static void main(args) {<br />    sql = Sql.newInstance("jdbc:mysql://localhost:3306/words", "words",<br />          "words", "org.gjt.mm.mysql.Driver")<br />    words = sql.dataSet("word")<br />    words.each{ word |<br />     println word.word_id + " " + word.spelling<br />    }<br />    words.add(word_id:"9999", spelling:"clerisy", part_of_speech:"Noun")<br />  }<br />}<br /></pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>您可以看到，GroovySql 的 
        <code>DataSet</code> 类型可以容易地用 
        <code>each</code> 方法对表的内容进行遍历，容易地用 
        <code>add</code> 方法添加新行，
        <code>add</code> 方法接受一个 
        <code>map</code> 表示需要的数据。
      </p>
		<p>
				<a name="N10204">
						<span class="smalltitle">使用存储过程和负索引</span>
				</a>
		</p>
		<p>存储过程调用和负索引（negative indexing）可能是数据操纵的重要方面。GroovySql 使存储过程调用简单得就像在 
        <code>Sql</code> 类上使用  
        <code>call</code> 方法一样。对于负索引， GroovySql 提供了自己增强的 
        <code>ResultSet</code> 类型，它工作起来非常像 Groovy 中的  
        <i>collections</i>。例如，如果您想获取结果集中的最后一个项目，您可以像清单 11 所示的那样做：
      </p>
		<br />
		<br />
		<a name="code11">
				<b>清单 11. 用 GroovySql 进行负索引</b>
		</a>
		<br />
		<table border="0" cellpadding="0" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td class="code-outline">
										<pre class="displaycode"> sql.eachRow("select * from word"){ grs |<br />   println "-1  = " + grs.getAt(-1) //prints spelling<br />   println "2  = " + grs.getAt(2) //prints spelling<br /> }<br /></pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>您在清单 11 中可以看到，提取结果集的最后一个元素非常容易，只要用 -1 作索引就可以。如果想试试，我也可以用索引 2 访问同一元素。</p>
		<p>这些例子非常简单，但是它们能够让您很好地感觉到 GroovySql 的威力。我现在要用一个演示目前讨论的所有特性的实际例子来结束本月的课程。</p>
		<br />
		<table border="0" cellpadding="0" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td>
										<img src="http://www.ibm.com/i/v14/rules/blue_rule.gif" alt="" height="1" width="100%" />
										<br />
										<img alt="" src="http://www.ibm.com/i/c.gif" border="0" height="6" width="8" />
								</td>
						</tr>
				</tbody>
		</table>
		<table class="no-print" align="right" cellpadding="0" cellspacing="0">
				<tbody>
						<tr align="right">
								<td>
										<img src="http://www.ibm.com/i/c.gif" alt="" height="4" width="100%" />
										<br />
										<br />
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<br />
		<p>
				<a name="N1022C">
						<span class="atitle">编写一个简单的报告应用程序</span>
				</a>
		</p>
		<p>报告应用程序通常要从数据库拖出信息。在典型的业务环境中，可能会要求您编写一个报告应用程序，通知销售团队当前的 Web 销售情况，或者让开发团队对系统某些方面（例如系统的数据库）的性能进行日常检测。 </p>
		<p>为
了继续这个简单的例子，假设您刚刚部署了一个企业范围的 Web 应用程序。当然，因为您在编写代码时还（用
Groovy）编写了充足的单元测试，所以它运行得毫无问题；但是您还是需要生成有关数据库状态的报告，以便调优。您想知道客户是如何使用应用程序的，这
样才能发现性能问题并解决问题。</p>
		<p> 通常，时间约束限制了您在这类应用程序中能够使用的提示信息的数量。但是您新得到的 GroovySql 知识可以让您轻而易举地完成这个应用程序，从而有时间添加更多您想要的特性。
</p>
		<p>
				<a name="N1023B">
						<span class="smalltitle">细节</span>
				</a>
		</p>
		<p>在这个例子中，您的目标数据库是 MySQL，它恰好支持用查询发现状态信息这一概念。以下是您有兴趣的状态信息：</p>
		<ul>
				<li>运行时间。</li>
				<li>处理的全部查询数量。</li>
				<li>特定查询的比例，例如 
          <code>insert</code>、
          <code>update</code> 和 
          <code>select</code>。
        </li>
		</ul>
		<p>用 GroovySql 从 MySQL 数据库得到这个信息太容易了。由于您正在为开发团队构建状态信息，所以您可能只是从一个简单的命令行报告开始，但是您可以在后面的迭代中把报告放在 Web 上。这个报告例子的用例看起来可能像这样：</p>
		<table>
				<tbody>
						<tr>
								<td>1.</td>
								<td>连接到我们的应用程序的活动数据库。</td>
						</tr>
						<tr>
								<td>2.</td>
								<td>发布 
            <code>show status</code> 查询并捕获：
          </td>
						</tr>
						<tr>
								<td>
										<br />
								</td>
								<td>a. 运行时间</td>
						</tr>
						<tr>
								<td>
										<br />
								</td>
								<td>b. 全部查询数</td>
						</tr>
						<tr>
								<td>
										<br />
								</td>
								<td>c. 全部 
            <code>insert</code> 数
          </td>
						</tr>
						<tr>
								<td>
										<br />
								</td>
								<td>d. 全部 
            <code>update</code> 数
          </td>
						</tr>
						<tr>
								<td>
										<br />
								</td>
								<td>e. 全部 
            <code>select</code> 数
          </td>
						</tr>
						<tr>
								<td>3.</td>
								<td>使用这些数据点，计算：</td>
						</tr>
						<tr>
								<td>
										<br />
								</td>
								<td>a. 每分钟查询数</td>
						</tr>
						<tr>
								<td>
										<br />
								</td>
								<td>b. 全部 
            <code>insert</code> 查询百分比
          </td>
						</tr>
						<tr>
								<td>
										<br />
								</td>
								<td>c. 全部 
            <code>update</code> 查询百分比
          </td>
						</tr>
						<tr>
								<td>
										<br />
								</td>
								<td>d. 全部 
            <code>select</code> 查询百分比
          </td>
						</tr>
				</tbody>
		</table>
		<p> 在清单 12 中，您可以看到最终结果：一个将会报告所需数据库统计信息的应用程序。代码开始的几行获得到生产数据库的连接，接着是一系列 
        <code>show status</code> 查询，让您计算每分钟的查询数，并按类型把它们分开。请注意像 
        <code>uptime</code> 这样的变量如何在定义的时候就创建。
      </p>
		<br />
		<br />
		<a name="code12">
				<b>清单 12. 用 GroovySql 进行数据库状态报告</b>
		</a>
		<br />
		<table border="0" cellpadding="0" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td class="code-outline">
										<pre class="displaycode">import groovy.sql.Sql<br />class DBStatusReport{<br />  static void main(args) {<br />     sql = Sql.newInstance("jdbc:mysql://yourserver.anywhere/tiger", "scott",<br />        "tiger", "org.gjt.mm.mysql.Driver")<br />     sql.eachRow("show status"){ status |<br />        if(status.variable_name == "Uptime"){<br />           uptime =  status[1]<br />        }else if (status.variable_name == "Questions"){<br />           questions =  status[1]<br />        }<br />     }<br />     println "Uptime for Database: " + uptime<br />     println "Number of Queries: " + questions<br />     println "Queries per Minute = " + Integer.valueOf(questions) / Integer.valueOf(uptime)<br />     sql.eachRow("show status like 'Com_%'"){ status |<br />        if(status.variable_name == "Com_insert"){<br />           insertnum =  Integer.valueOf(status[1])<br />        }else if (status.variable_name == "Com_select"){<br />           selectnum =  Integer.valueOf(status[1])<br />        }else if (status.variable_name == "Com_update"){<br />           updatenum =  Integer.valueOf(status[1])<br />       }<br />    }<br />    println "% Queries Inserts = " + 100 * (insertnum / Integer.valueOf(uptime))<br />    println "% Queries Selects = " + 100 * (selectnum / Integer.valueOf(uptime))<br />    println "% Queries Updates = " + 100 * (updatenum / Integer.valueOf(uptime))<br />    }<br />}<br /></pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<br />
		<table border="0" cellpadding="0" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td>
										<img src="http://www.ibm.com/i/v14/rules/blue_rule.gif" alt="" height="1" width="100%" />
										<br />
										<img alt="" src="http://www.ibm.com/i/c.gif" border="0" height="6" width="8" />
								</td>
						</tr>
				</tbody>
		</table>
		<table class="no-print" align="right" cellpadding="0" cellspacing="0">
				<tbody>
						<tr align="right">
								<td>
										<img src="http://www.ibm.com/i/c.gif" alt="" height="4" width="100%" />
										<br />
										<br />
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<br />
		<p>
				<a name="N102F6">
						<span class="atitle">结束语</span>
				</a>
		</p>
		<p>在 
        <i>实战 Groovy</i>
本月的这一期文章中，您看到了 GroovySql 如何简化 JDBC 编程。这个干净漂亮的 API 把闭包和迭代器与 Groovy
轻松的语法结合在一起，有助于在 Java 平台上进行快速数据库应用程序开发。最强大的是，GroovySql
把资源管理任务从开发人员转移到底层的 Groovy
框架，这使您可以把精力集中在更加重要的查询和查询结果上。但是不要只记住我这句话。下次如果您被要求处理 JDBC 的麻烦事，那时可以试试小小的
GroovySql 魔力。然后给我发封电子邮件告诉我您的体会。 </p>
		<p>在 
        <i>实战 Groovy</i> 下一月的文章中，我要介绍 Groovy 模板框架的细节。您会发现，用这个更加聪明的框架创建应用程序的视图组件简直就是小菜一碟。
      </p>
<img src ="http://www.blogjava.net/JafeLee/aggbug/128671.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/JafeLee/" target="_blank">Jafe</a> 2007-07-06 21:01 <a href="http://www.blogjava.net/JafeLee/articles/128671.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>实战 Groovy: 用 Groovy 进行 Ant 脚本编程</title><link>http://www.blogjava.net/JafeLee/articles/128669.html</link><dc:creator>Jafe</dc:creator><author>Jafe</author><pubDate>Fri, 06 Jul 2007 12:59:00 GMT</pubDate><guid>http://www.blogjava.net/JafeLee/articles/128669.html</guid><wfw:comment>http://www.blogjava.net/JafeLee/comments/128669.html</wfw:comment><comments>http://www.blogjava.net/JafeLee/articles/128669.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/JafeLee/comments/commentRss/128669.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/JafeLee/services/trackbacks/128669.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: Andrew Glover (aglover@vanwardtechnologies.com), CTO, Vanward Technologies		2004 年  12 月  14 日		Ant和 Maven 两者在构建处理工具的世界中占统治地位。但是 XML 却凑巧是一种非常没有表现力的配置格式。在“实战Groovy”这个新系列的第 2 期中，Andrew Glover 将介...&nbsp;&nbsp;<a href='http://www.blogjava.net/JafeLee/articles/128669.html'>阅读全文</a><img src ="http://www.blogjava.net/JafeLee/aggbug/128669.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/JafeLee/" target="_blank">Jafe</a> 2007-07-06 20:59 <a href="http://www.blogjava.net/JafeLee/articles/128669.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>实战 Groovy: 用 Groovy 更迅速地对 Java 代码进行单元测试</title><link>http://www.blogjava.net/JafeLee/articles/128668.html</link><dc:creator>Jafe</dc:creator><author>Jafe</author><pubDate>Fri, 06 Jul 2007 12:53:00 GMT</pubDate><guid>http://www.blogjava.net/JafeLee/articles/128668.html</guid><wfw:comment>http://www.blogjava.net/JafeLee/comments/128668.html</wfw:comment><comments>http://www.blogjava.net/JafeLee/articles/128668.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/JafeLee/comments/commentRss/128668.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/JafeLee/services/trackbacks/128668.html</trackback:ping><description><![CDATA[
		<p>级别: 初级</p>
		<p>
				<a href="http://www.ibm.com/developerworks/cn/java/j-pg11094/index.html#author">Andrew Glover</a> (<a href="mailto:aglover@vanwardtechnologies.com?subject=%E7%94%A8%20Groovy%20%E6%9B%B4%E8%BF%85%E9%80%9F%E5%9C%B0%E5%AF%B9%20Java%20%E4%BB%A3%E7%A0%81%E8%BF%9B%E8%A1%8C%E5%8D%95%E5%85%83%E6%B5%8B%E8%AF%95">aglover@vanwardtechnologies.com</a>), CTO, Vanward Technologies<br /></p>
		<p>2004 年  11 月  09 日</p>
		<blockquote>不久以前，developerWorks 的作者 Andrew Glover 撰写了一篇介绍 Groovy 的文章，该文章是
      <i>alt.lang.jre</i>
系列的一部分，而 Groovy 是一个新提议的用于 Java
平台的标准语言。读者对这篇文章的反应非常热烈，所以我们决定开办这个专栏，提供使用这项热门新技术的实用指导。本文是第一期，将介绍使用
Groovy 和 JUnit 对 Java 代码进行单元测试的一个简单策略。 </blockquote>
		<!--START RESERVED FOR FUTURE USE INCLUDE FILES-->
		<!-- include java script once we verify teams wants to use this and it will work on dbcs and cyrillic characters -->
		<!--END RESERVED FOR FUTURE USE INCLUDE FILES-->
		<p>开始之前，我首先要招认：我是一个单元测试狂。实际上，我总是无法编写足够的单元测试。如果我相当长一段时间都在进行开发，而
        <i>没有</i>编写相应的单元测试，我就会觉得紧张。单元测试给我信心，让我相信我的代码能够工作，而且我只要看一下，可以修改它，就不会害怕它会崩溃。
      </p>
		<p>而且，作为一个单元测试狂，我喜欢编写多余的测试用例。但是，我的兴奋不是来自
        <i>编写</i>测试用例，而是
        <i>看着</i>它们生效。所以，如果我能用更快的方式编写测试，我就能更迅速地看到它们的结果。这让我感觉更好。更快一些！
      </p>
		<p>后
来，我找到了
Groovy，它满足了我的单元测试狂，而且至今为止，对我仍然有效。这种新语言给单元测试带来的灵活性，非常令人兴奋，值得认真研究。本文是介绍
Groovy 实践方面的新系列的第一部分，在文中，我将向您介绍使用 Groovy 进行单元测试的快乐。我从概述开始，概述 Groovy 对
Java 平台上的开发所做的独特贡献，然后转而讨论使用 Groovy 和 JUnit 进行单元测试的细节，其中重点放在 Groovy 对
JUnit 的 <code>TestCase</code> 类的扩展上。最后，我用一个实用的示例进行总结，用第一手材料向您展示如何把 
        <i>groovy</i> 的这些特性与 Eclipse 和 Maven 集成在一起。
      </p>
		<p>
				<a name="N1005E">
						<span class="atitle">不要再坚持 Java 纯粹主义了！</span>
				</a>
		</p>
		<p>在
我开始介绍用 Groovy 进行单元测试的实际经验之前，我认为先谈谈一个更具一般性的问题 ——
它在您的开发工具箱中的位置，这非常重要。事实是，Groovy 不仅是运行在 Java 运行时环境（JRE）中的脚本语言，它还被提议作为用于
Java 平台的标准语言。正如您们之中的人已经从 <i>alt.lang.jre</i> 系列（请参阅
        <a href="http://www.ibm.com/developerworks/cn/java/j-pg11094/index.html#resources">参考资料</a>）中学习到的，在为 Java 平台进行脚本编程的时候，有无数的选择，其中大多数是面向快速应用程序开发的高度灵活的环境。
      </p>
		<p>虽然有这么丰富的选择，但还是有许多开发人选择坚持自己喜欢的、最熟悉的范式：Java 语言。虽然大多数情况下，Java 编程都是很好的选择，但是它有一个非常重要的缺点，蒙住了只看见 Java 的好处的这些人的眼睛。正如一个智者曾经指出的：
        <i>如果您仅有的一个工具是一把锤子，那么您看每个问题时都会觉得它像是钉子</i>。我认为这句谚语道出了适用于软件开发的许多事实。
      </p>
		<p>虽然我希望用这个系列说服您 Java 不是也不应当是开发应用程序的惟一选择，但该脚本确实既有适用的地方也有不适用的地方。专家和新手的区别在于：知道什么时候
        <i>运用</i>该脚本，什么时候
        <i>避免</i>使用它。
      </p>
		<table align="right" border="0" cellpadding="0" cellspacing="0" width="40%">
				<tbody>
						<tr>
								<td width="10">
										<img alt="" src="http://www.ibm.com/i/c.gif" height="1" width="10" />
								</td>
								<td>
										<table border="1" cellpadding="5" cellspacing="0" width="100%">
												<tbody>
														<tr>
																<td bgcolor="#eeeeee">
																		<a name="N1007F">
																				<b>关于本系列</b>
																		</a>
																		<br />
																		<p>把工具整合到开发实践中的关键是了解什么时候使用它，以及什么时候把它留在工具箱中。脚本语言能够成为工具包中极为强大的附件，但是只有正确地应用在适当的场合时才是这样。为了实现
          <i>实战 Groovy</i> 系列文章这个目标，我专门研究了 Groovy 的一些实战，教给您什么时候怎样才能成功地应用它们。
        </p>
																</td>
														</tr>
												</tbody>
										</table>
								</td>
						</tr>
				</tbody>
		</table>
		<p>例如，对于高性能、事务密集型、企业级应用程序，Groovy 脚本通常不太适合；在这些情况下，您最好的选择
        <i>可能</i>是
普通的 J2EE 系统。但另一方面，一些脚本 —— 特别是用 Groovy 编写的脚本 ——
会非常有用，因为它能迅速地为小型的、非常特殊的、不是性能密集型的应用程序（例如配置系统/生成系统）快速制作原型。对于报表应用程序来说，
Groovy 脚本也是近乎完美的选择，而最重要的是，对单元测试更是如此。 </p>
		<br />
		<br />
		<br />
		<br />
		<br />
		<table border="0" cellpadding="0" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td>
										<img src="http://www.ibm.com/i/v14/rules/blue_rule.gif" alt="" height="1" width="100%" />
										<br />
										<img alt="" src="http://www.ibm.com/i/c.gif" border="0" height="6" width="8" />
								</td>
						</tr>
				</tbody>
		</table>
		<table class="no-print" align="right" cellpadding="0" cellspacing="0">
				<tbody>
						<tr align="right">
								<td>
										<img src="http://www.ibm.com/i/c.gif" alt="" height="4" width="100%" />
										<br />
										<table border="0" cellpadding="0" cellspacing="0">
												<tbody>
														<tr>
																<td valign="middle">
																		<br />
																</td>
																<td align="right" valign="top">
																		<br />
																</td>
														</tr>
												</tbody>
										</table>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>
				<a name="N10092">
						<span class="atitle">为什么用 Groovy 进行单元测试？</span>
				</a>
		</p>
		<p>是
什么让 Groovy 比起其他脚本平台显得更具有吸引力呢？是它与Java 平台无缝的集成。还是因为它是基于 Java
的语言（不像其他语言，是对 JRE 的替代，因此可能基于旧版的处理器），对于 Java 开发人员来说，Groovy
意味着一条短得让人难以置信的学习曲线。而且一旦将这条学习曲线拉直，Groovy 就能提供一个无与伦比的快速开发平台。</p>
		<p>从这个角度来说，Groovy 成功的秘密，在于它的语法
        <i>就是</i> Java 语法，但是规则更少。例如，Groovy 不要求使用分号，变量类型和访问修饰符也是可选的。而且，Groovy 利用了标准的 Java 库，这些都是您已经很熟悉的，包括 
        <code>Collections</code> 和 
        <code>File/IO</code>。而且，您还可以利用任何 Groovy 提供的 Java 库，包括 JUnit。
      </p>
		<p>事实上，令人放松的类 Java 语法、对标准 Java 库的重用以及快捷的生成-运行周期，这些都使 Groovy 成为快速开发单元测试的理想替代品。但是会说的不如会做的，还是让我们在代码中看看它的实际效果！</p>
		<br />
		<table border="0" cellpadding="0" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td>
										<img src="http://www.ibm.com/i/v14/rules/blue_rule.gif" alt="" height="1" width="100%" />
										<br />
										<img alt="" src="http://www.ibm.com/i/c.gif" border="0" height="6" width="8" />
								</td>
						</tr>
				</tbody>
		</table>
		<table class="no-print" align="right" cellpadding="0" cellspacing="0">
				<tbody>
						<tr align="right">
								<td>
										<img src="http://www.ibm.com/i/c.gif" alt="" height="4" width="100%" />
										<br />
										<table border="0" cellpadding="0" cellspacing="0">
												<tbody>
														<tr>
																<td valign="middle">
																		<br />
																</td>
																<td align="right" valign="top">
																		<br />
																</td>
														</tr>
												</tbody>
										</table>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<br />
		<p>
				<a name="N100AC">
						<span class="atitle">JUnit 和 Groovy</span>
				</a>
		</p>
		<p>用
Groovy 对 Java 代码进行单元测试简单得不能再简单了，有很多入门选择。最直接的选择是沿袭行业标准 —— JUnit。Unit
的简单性和其功能的强大都是无与伦比的，作为非常有帮助的 Java 开发工具，它的普遍性也是无与伦比的，而且没有什么能够阻挡 JUnit 和
Groovy 结合，所以为什么多此一举呢？实际上，只要您看过 JUnit 和 Groovy
在一起工作，我敢打赌您就永远再也不会回头！在这里，要记住的关键的事，您在 Java 语言中能用 JUnit 做到的事，在 Groovy 中用
JUnit 也全都能做到；但是需要的代码要少得多。</p>
		<p>
				<a name="N100B5">
						<span class="smalltitle">入门</span>
				</a>
		</p>
		<p>在您下载了 JUnit 和 Groovy（请参阅
        <a href="http://www.ibm.com/developerworks/cn/java/j-pg11094/index.html#resources">参考资料</a>）之后，您将有两个选择。第一个选择是编写普通的 JUnit 测试用例，就像以前一直做的那样，扩展 JUnit 令人称赞的 
        <code>TestCase</code>。第二个选择是应用 Groovy 简洁的 
        <code>GroovyTestCase</code> 扩展，它会扩展 JUnit 的 
        <code>TestCase</code>。第一个选项是您最快的成功途径，它拥有最多
        <i>与 Java 类似的</i>相似性。而另一方面，第二个选择则把您推进了 Groovey 的世界，这个选择有最大的敏捷性。
      </p>
		<p>开始的时候，我们来想像一个 Java 对象，该对象对指定的
        <code>string</code> 应用了一个过滤器，并根据匹配结果返回 
        <code>boolean</code> 值。该过滤器可以是简单的 
        <code>string</code> 操作，例如
        <code>indexOf()</code>，也可以更强大一些，是正则表达式。可能要通过 
        <code>setFilter()</code> 方法在运行时设置将使用的过滤器，
        <code>apply()</code> 方法接受要过滤的 
        <code>string</code>。清单 1 用普通的 Java 代码显示了这个示例的 
        <code>Filter</code> 接口：
      </p>
		<br />
		<br />
		<a name="code16">
				<b>清单 1. 一个简单的 Java Filter 接口</b>
		</a>
		<br />
		<table border="0" cellpadding="0" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td class="code-outline">
										<pre class="displaycode">public interface Filter {<br />  void setFilter(String fltr);  <br />  boolean applyFilter(String value);<br />}<br /></pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>我们的想法是用这个特性从大的列表中过滤掉想要的或者不想要的包名。所以，我建立了两个实现：
        <code>RegexPackageFilter</code> 和 
        <code>SimplePackageFilter</code>。
      </p>
		<p>把 Groovy 和 JUnit 的强大功能与简单性结合在一起，就形成了如清单 2 所示的简洁的测试套件：</p>
		<br />
		<br />
		<a name="code16">
				<b>清单 2. 用 JUunit 制作的 Groovy RegexFilterTest </b>
		</a>
		<br />
		<table border="0" cellpadding="0" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td class="code-outline">
										<pre class="displaycode">import junit.framework.TestCase<br />import com.vanward.sedona.frmwrk.filter.impl.RegexPackageFilter<br />class RegexFilterTest extends TestCase {  <br />  void testSimpleRegex() {<br />    fltr = new RegexPackageFilter()<br />    fltr.setFilter("java.*")<br />    val = fltr.applyFilter("java.lang.String")		<br />    assertEquals("value should be true", true, val)		<br />  }<br />}<br /></pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>不管您是否熟悉 Groovy，清单 2 中的代码对您来说应当很面熟，因为它只不过是没有分号、访问修饰符或变量类型的 Java 代码而已！上面的 JUnit 测试中有一个测试用例 
        <code>testSimpleRegex()</code>，它试图断言 
        <code>RegexPackageFilter</code> 用正则表达式 
        <code>"java.*"</code> 正确地找到了与 “
        <code>java.lang.String</code>”匹配的对象。
      </p>
		<br />
		<table border="0" cellpadding="0" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td>
										<img src="http://www.ibm.com/i/v14/rules/blue_rule.gif" alt="" height="1" width="100%" />
										<br />
										<img alt="" src="http://www.ibm.com/i/c.gif" border="0" height="6" width="8" />
								</td>
						</tr>
				</tbody>
		</table>
		<table class="no-print" align="right" cellpadding="0" cellspacing="0">
				<tbody>
						<tr align="right">
								<td>
										<img src="http://www.ibm.com/i/c.gif" alt="" height="4" width="100%" />
										<br />
										<table border="0" cellpadding="0" cellspacing="0">
												<tbody>
														<tr>
																<td valign="middle">
																		<br />
																</td>
																<td align="right" valign="top">
																		<br />
																</td>
														</tr>
												</tbody>
										</table>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<br />
		<p>
				<a name="N1012D">
						<span class="atitle">Groovy 扩展了 JUnit</span>
				</a>
		</p>
		<p>扩展 JUnit 的 
        <code>TestCase</code> 类，加入附加特性，实际上是每个 JUnit 扩展通常采用的技术。例如，DbUnit 框架（请参阅
        <a href="http://www.ibm.com/developerworks/cn/java/j-pg11094/index.html#resources">参考资料</a>）提供了一个方便的
        <code>DatabaseTestCase</code> 类，能够比以往任何时候都更容易地管理数据库的状态，还有重要的 
        <code>MockStrutsTestCase</code>（来自 StrutsTestCase 框架；请参阅
        <a href="http://www.ibm.com/developerworks/cn/java/j-pg11094/index.html#resources">参考资料</a>），它生成虚拟的 
        <code>servlet</code> 容器，用来执行  struts 代码。这两个强大的框架都极好地扩展了 JUnit，提供了 JUnit 核心代码中所没有的其他特性；而现在 Groovy 来了，它也是这么做的！
      </p>
		<p>与 StrutsTestCase 和 DbUnit 一样，Groovy 对 JUnit 的 
        <code>TestCase</code> 的扩展给您的工具箱带来了一些重要的新特性。这个特殊的扩展允许您通过 
        <code>groovy</code> 命令运行测试套件，而且提供了一套新的 
        <code>assert</code> 方法。可以用这些方法很方便地断言脚本的运行是否正确，以及断言各种数组类型的长度和内容等。
      </p>
		<br />
		<table border="0" cellpadding="0" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td>
										<img src="http://www.ibm.com/i/v14/rules/blue_rule.gif" alt="" height="1" width="100%" />
										<br />
										<img alt="" src="http://www.ibm.com/i/c.gif" border="0" height="6" width="8" />
								</td>
						</tr>
				</tbody>
		</table>
		<table class="no-print" align="right" cellpadding="0" cellspacing="0">
				<tbody>
						<tr align="right">
								<td>
										<img src="http://www.ibm.com/i/c.gif" alt="" height="4" width="100%" />
										<br />
										<table border="0" cellpadding="0" cellspacing="0">
												<tbody>
														<tr>
																<td valign="middle">
																		<br />
																</td>
																<td align="right" valign="top">
																		<br />
																</td>
														</tr>
												</tbody>
										</table>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<br />
		<p>
				<a name="N1015D">
						<span class="atitle">享受 GroovyTestCase 的快乐</span>
				</a>
		</p>
		<p>了解 
        <code>GroovyTestCase</code> 的能力最好的办法，莫过于实际看到它的效果。在清单 3 中，我已经编写了一个新的  
        <code>SimpleFilterTest</code>，但是这次我要扩展 
        <code>GroovyTestCase</code> 来实现它：
      </p>
		<br />
		<br />
		<a name="code16">
				<b>清单 3. 一个真正的 GroovyTestCase</b>
		</a>
		<br />
		<table border="0" cellpadding="0" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td class="code-outline">
										<pre class="displaycode">import groovy.util.GroovyTestCase<br />import com.vanward.sedona.frmwrk.filter.impl.SimplePackageFilter<br />class SimpleFilterTest extends GroovyTestCase {<br /><br />  void testSimpleJavaPackage() {<br />    fltr = new SimplePackageFilter()<br />    fltr.setFilter("java.")		<br />    val = fltr.applyFilter("java.lang.String")		<br />    assertEquals("value should be true", true, val)<br />  }	<br />}<br /></pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>请注意，可以通过命令行来运行该测试套件，没有运行基于 Java 的 JUnit 测试套件所需要的 
        <code>main()</code> 方法。实际上，如果我用 Java 代码编写上面的 
        <code>SimpleFilterTest</code>，那么代码看起来会像清单 4 所示的那样：
      </p>
		<br />
		<br />
		<a name="code16">
				<b>清单 4. 用 Java 代码编写的同样的测试用例</b>
		</a>
		<br />
		<table border="0" cellpadding="0" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td class="code-outline">
										<pre class="displaycode">import junit.framework.TestCase;<br />import com.vanward.sedona.frmwrk.filter.Filter;<br />import com.vanward.sedona.frmwrk.filter.impl.SimplePackageFilter;<br />public class SimplePackageFilterTest extends TestCase {       <br />   public void testSimpleRegex() {<br />	Filter fltr = new SimplePackageFilter();<br />	fltr.setFilter("java.");<br />	boolean val = fltr.applyFilter("java.lang.String");<br />	assertEquals("value should be true", true, val);<br />   }<br /><br />   public static void main(String[] args) {<br /> 	junit.textui.TestRunner.run(SimplePackageFilterTest.class);<br />   }<br />}<br /></pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>
				<a name="N10193">
						<span class="smalltitle">用断言进行测试</span>
				</a>
		</p>
		<p>除了可以让您通过命令行运行测试之外，
        <code>GroovyTestCase</code> 还向您提供了一些特别方便的 
        <code>assert</code> 方法。例如，
        <code>assertArrayEquals</code>，它可以检查两个数据中对应的每一个值和各自的长度，从而断言这两个数据是否相等。从清单 5 的示例开始，就可以看到 Groovy 断言的实际效果，清单 5 是一个简洁的基于 Java 的方法，它把 
        <code>string</code> 分解成数组。（请注意，我可能使用了 Java 1.4 中新添加的 
        <code>string</code> 特性编写以下的示例类。我采用 Jakarta Commons 
        <code>StringUtils</code> 类来确保与 Java 1.3 的后向兼容性。）
      </p>
		<br />
		<br />
		<a name="code16">
				<b>清单 5. 定义一个 Java StringSplitter 类</b>
		</a>
		<br />
		<table border="0" cellpadding="0" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td class="code-outline">
										<pre class="displaycode">import org.apache.commons.lang.StringUtils;<br />public class StringSplitter {<br />  public static String[] split(final String input, final String separator){<br />   return StringUtils.split(input, separator);<br />  }<br />}<br /></pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>清单 6 展示了用 Groovy 测试套件及其对应的 
        <code>assertArrayEquals</code> 方法对这个类进行测试是多么简单：
      </p>
		<br />
		<br />
		<a name="code16">
				<b>清单 6. 使用 GroovyTestCase 的 assertArrayEquals 方法</b>
		</a>
		<br />
		<table border="0" cellpadding="0" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td class="code-outline">
										<pre class="displaycode">import groovy.util.GroovyTestCase<br />import com.vanward.resource.string.StringSplitter<br />class StringSplitTest extends GroovyTestCase {<br /><br />  void testFullSplit() {<br />    splitAr = StringSplitter.split("groovy.util.GroovyTestCase", ".")		<br />    expect = ["groovy", "util", "GroovyTestCase"].toArray()<br />    assertArrayEquals(expect, splitAr)		<br />  }	<br />}<br /></pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<br />
		<table border="0" cellpadding="0" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td>
										<img src="http://www.ibm.com/i/v14/rules/blue_rule.gif" alt="" height="1" width="100%" />
										<br />
										<img alt="" src="http://www.ibm.com/i/c.gif" border="0" height="6" width="8" />
								</td>
						</tr>
				</tbody>
		</table>
		<table class="no-print" align="right" cellpadding="0" cellspacing="0">
				<tbody>
						<tr align="right">
								<td>
										<img src="http://www.ibm.com/i/c.gif" alt="" height="4" width="100%" />
										<br />
										<table border="0" cellpadding="0" cellspacing="0">
												<tbody>
														<tr>
																<td valign="middle">
																		<br />
																</td>
																<td align="right" valign="top">
																		<br />
																</td>
														</tr>
												</tbody>
										</table>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<br />
		<p>
				<a name="N101D1">
						<span class="atitle">其他方法</span>
				</a>
		</p>
		<p>Groovy 可以让您单独或成批运行测试。使用 
        <code>GroovyTestCase</code> 扩展，运行单个测试毫不费力。只要运行 
        <code>groovy</code> 命令，后面跟着要运行的测试套件即可，如清单 7 所示：
      </p>
		<br />
		<br />
		<a name="code16">
				<b>清单 7. 通过 groovy 命令运行 GroovyTestCase 测试用例</b>
		</a>
		<br />
		<table border="0" cellpadding="0" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td class="code-outline">
										<pre class="displaycode">$./groovy test/com/vanward/sedona/frmwrk/filter/impl/SimpleFilterTest.groovy<br />.<br />Time: 0.047<br />OK (1 test)<br /></pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>Groovy 还提供了一个标准的 JUnit 测试套件，叫作 
        <code>GroovyTestSuite</code>。只要运行该测试套件，把脚本的路径传给它，它就会运行脚本，就像 
        <code>groovy</code> 命令一样。这项技术的好处是，它可以让您在 IDE 中运行脚本。例如，在 Eclipse 中，我只是为示例项目建立了一个新的运行配置（一定要选中 “Include external jars when
searching for a main class”），然后找到主类 
        <code>groovy.util.GroovyTestSuite</code>，如图 1 所示：
      </p>
		<br />
		<br />
		<a name="N101FE">
				<b>图 1. 用 Eclipse 运行 GroovyTestSuite</b>
		</a>
		<br />
		<img alt="图 1. 用 Eclipse 运行 GroovyTestSuite" src="http://www.ibm.com/developerworks/cn/java/j-pg11094/pic1.jpg" height="387" width="600" />
		<br />
		<p>在图 2 中，您可以看到当点击 Arguments 标签，写入脚本的路径时，会发生了什么：</p>
		<br />
		<br />
		<a name="N10212">
				<b>图 2. 在 Eclipse 中指定脚本的路径</b>
		</a>
		<br />
		<img alt="图 2. 在 Eclipse 中指定脚本的路径" src="http://www.ibm.com/developerworks/cn/java/j-pg11094/pic2.jpg" height="389" width="600" />
		<br />
		<p>运行一个自己喜欢的 JUnit Groovy 脚本，实在是很简单，只要在 Eclipse 中找到对应的运行配置就可以了。</p>
		<br />
		<table border="0" cellpadding="0" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td>
										<img src="http://www.ibm.com/i/v14/rules/blue_rule.gif" alt="" height="1" width="100%" />
										<br />
										<img alt="" src="http://www.ibm.com/i/c.gif" border="0" height="6" width="8" />
								</td>
						</tr>
				</tbody>
		</table>
		<table class="no-print" align="right" cellpadding="0" cellspacing="0">
				<tbody>
						<tr align="right">
								<td>
										<img src="http://www.ibm.com/i/c.gif" alt="" height="4" width="100%" />
										<br />
										<table border="0" cellpadding="0" cellspacing="0">
												<tbody>
														<tr>
																<td valign="middle">
																		<br />
																</td>
																<td align="right" valign="top">
																		<br />
																</td>
														</tr>
												</tbody>
										</table>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<br />
		<p>
				<a name="N10224">
						<span class="atitle">用 Ant 和 Maven 进行测试</span>
				</a>
		</p>
		<p>这
个像 JUnit 一样的框架的美妙之处还在于，它可以把整套测试作为 build
的一部分运行，不需要人工进行干预。随着越来越多的人把测试用例加入代码基（code
base），整体的测试套件日益增长，形成一个极好的回归平台（regression platform）。更妙的是，Ant 和 Maven 这样的
build 框架已经加入了报告特性，可以归纳 Junit 批处理任务运行的结果。</p>
		<p>把一组 Groovy
测试用例整合到某一个构建中的最简单的方法是把它们编译成普通的 Java 字节码，然后把它们包含在 Ant 和 Maven 提供的标准的
Junit 批命令中。幸运的是，Groovy 提供了一个 Ant 标签，能够把未编译的 Groovy
脚本集成到字节码中，这样，把脚本转换成有用的字节码的处理工作就变得再简单不过。例如，如果正在使用 Maven
进行构建工作，那么只需在maven.xml 文件中添加两个新的目标、在 project.xml 中添加两个新的相关性、在
build.properties 文件中添加一个简单的标志就可以了。</p>
		<p>我要从更新 maven.xml 文件开始，用新的目标来编译示例脚本，如清单 8 所示：</p>
		<br />
		<br />
		<a name="code16">
				<b>清单 8. 定义 Groovyc 目标的新 maven.xml 文件</b>
		</a>
		<br />
		<table border="0" cellpadding="0" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td class="code-outline">
										<pre class="displaycode"> &lt;goal name="run-groovyc" prereqs="java:compile,test:compile"&gt;<br /><br />   &lt;path id="groovy.classpath"&gt;<br />     &lt;pathelement path="${maven.build.dest}"/&gt;<br />     &lt;pathelement path="target/classes"/&gt;<br />     &lt;pathelement path="target/test-classes"/&gt;<br />     &lt;path refid="maven.dependency.classpath"/&gt;<br />   &lt;/path&gt;<br /> &lt;taskdef name="groovyc" classname="org.codehaus.groovy.ant.Groovyc"&gt;<br />    &lt;classpath refid="groovy.classpath"/&gt;<br /> &lt;/taskdef&gt;<br /> &lt;groovyc destdir="${basedir}/target/test-classes" srcdir="${basedir}/test/groovy" <br />          listfiles="true"&gt;<br />	&lt;classpath refid="groovy.classpath"/&gt;<br /> &lt;/groovyc&gt;<br /> &lt;/goal&gt;<br /></pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>上面代码中发生了以下几件事。第一，我定义一个名为 
        <code>run-groovyc</code> 的新目标。该目标有两个前提条件，
        <code>java:compile</code> 编译示例源代码，
        <code>test:compile</code> 编译普通的 Java-JUnit 类。我还用 
        <code>&lt;path&gt;</code> 标签创建了一个 classpath。在该例中，classpath 把 build 目录（保存编译后的源文件）和与它相关的所有依存关系（即 JAR 文件）整合在一起。接着，我还用 
        <code>&lt;taskdef&gt;</code> Ant 标签定义了 
        <code>groovyc</code> 任务。
      </p>
		<p>而且，请您注意我在 classpath 中是如何告诉 Maven 到哪里去找 
        <code>org.codehaus.groovy.ant.Groovyc</code> 这个类。在示例的最后一行，我定义了 
        <code>&lt;groovyc&gt;</code> 标签，它会编译在 
        <code>test/groovy</code> 目录中发现的全部 Groovy 脚本，并把生成的 
        <i>.class</i> 文件放在 
        <code>target/test-classes</code> 目录中。
      </p>
		<p>
				<a name="N1026F">
						<span class="smalltitle">一些重要细节</span>
				</a>
		</p>
		<p>为了编译 Groovy 脚本，并运行生成的字节码，我必须要通过 project.xml 文件定义两个新的依存关系（
        <i>groovy</i> 和 
        <i>asm</i>），如清单 9 所示：
      </p>
		<br />
		<br />
		<a name="code16">
				<b>清单 9. project.xml 文件中的新的依存关系</b>
		</a>
		<br />
		<table border="0" cellpadding="0" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td class="code-outline">
										<pre class="displaycode">  &lt;dependency&gt;<br />    &lt;groupId&gt;groovy&lt;/groupId&gt;<br />    &lt;id&gt;groovy&lt;/id&gt;<br />    &lt;version&gt;1.0-beta-6&lt;/version&gt;<br />  &lt;/dependency&gt;<br />  &lt;dependency&gt;<br />    &lt;groupId&gt;asm&lt;/groupId&gt;<br />    &lt;id&gt;asm&lt;/id&gt;<br />    &lt;version&gt;1.4.1&lt;/version&gt;<br />  &lt;/dependency&gt;<br /></pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>一旦将脚本编译成普遍的 Java
字节码，那么任何标准的 JUnit 运行器就都能运行它们。因为 Ant 和 Maven 都拥有 JUnit 运行器标签，所以下一步就是让
JUnit 挑选新编译的 Groovy 脚本。而且，因为 Maven 的 JUnit 运行器使用模式匹配来查找要运行的测试套件，所以需要在
build.properties 文件中添加一个特殊标记，如清单 10 所示，该标记告诉 Maven 去搜索类而不是搜索 .java 文件。</p>
		<br />
		<br />
		<a name="code16">
				<b>清单 10. Maven 项目的 build.properties 文件</b>
		</a>
		<br />
		<table border="0" cellpadding="0" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td class="code-outline">
										<pre class="displaycode"> maven.test.search.classdir = true<br /></pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>最后，我在 maven.xml 文件中定义了一个测试目标（
        <code>goal</code>），如清单 11 所示。这样做可以确保 在单元测试运行之前，使用新的 
        <code>run-groovyc</code> 目标编译 Groovy 脚本。
      </p>
		<br />
		<br />
		<a name="code16">
				<b>清单 11. maven.xml 的新目标</b>
		</a>
		<br />
		<table border="0" cellpadding="0" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td class="code-outline">
										<pre class="displaycode">  &lt;goal name="test"&gt;<br />    &lt;attainGoal name="run-groovyc"/&gt;<br />    &lt;attainGoal name="test:test"/&gt;    	<br />  &lt;/goal&gt;<br /></pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>
				<a name="N102AD">
						<span class="smalltitle">最后一个，但并非最不重要</span>
				</a>
		</p>
		<p>有了新定义的两个目标（一个用来编译脚本，另外一个用来运行 Java 和 Groovy 组合而成的单元测试），剩下的事就只有运行它们，检查是不是每件事都顺利运行！</p>
		<p>在清单 12 中，您可以看到，当我运行 Maven，给 
        <code>test</code> 传递目标之后，会发生了什么，它首先包含 
        <code>run-groovyc</code> 目标（而该目标恰好还包含
        <code>java:compile</code> 和 
        <code>test:compile</code> 这两个目标），然后包含 Maven 中自带的标准的 
        <code>test:test</code> 目标。请注意观察目标 
        <code>test:test</code> 是如何处理新生成的 Groovy 脚本（在该例中，是新
        <i>编译的</i>
Groovy 脚本）
        <i>以及</i>普通的 Java JUnit 测试。
      </p>
		<br />
		<br />
		<a name="code16">
				<b>清单 12. 运行新的测试目标</b>
		</a>
		<br />
		<table border="0" cellpadding="0" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td class="code-outline">
										<pre class="displaycode">$ ./maven test<br />test:<br />java:compile:<br />    [echo] Compiling to /home/aglover/dev/target/classes<br />    [javac] Compiling 15 source files to /home/aglover/dev/target/classes<br />test:compile:<br />    [javac] Compiling 4 source files to /home/aglover/dev/target/test-classes<br />run-groovyc:<br />    [groovyc] Compiling 2 source files to /home/aglover/dev/target/test-classes<br />    [groovyc] /home/aglover/dev/test/groovy/test/RegexFilterTest.groovy<br />    [groovyc] /home/aglover/dev/test/groovy/test/SimpleFilterTest.groovy<br />test:test:    <br />    [junit] Running test.RegexFilterTest<br />    [junit] Tests run: 1, Failures: 0, Errors: 0, Time elapsed: 0.656 sec    <br />    [junit] Running test.SimpleFilterTest<br />    [junit] Tests run: 1, Failures: 0, Errors: 0, Time elapsed: 0.609 sec<br />    [junit] Running test.SimplePackageFilterTest<br />    [junit] Tests run: 1, Failures: 0, Errors: 0, Time elapsed: 0.578 sec    <br />BUILD SUCCESSFUL<br />Total time: 42 seconds<br />Finished at: Tue Sep 21 17:37:08 EDT 2004<br /></pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<br />
		<table border="0" cellpadding="0" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td>
										<img src="http://www.ibm.com/i/v14/rules/blue_rule.gif" alt="" height="1" width="100%" />
										<br />
										<img alt="" src="http://www.ibm.com/i/c.gif" border="0" height="6" width="8" />
								</td>
						</tr>
				</tbody>
		</table>
		<table class="no-print" align="right" cellpadding="0" cellspacing="0">
				<tbody>
						<tr align="right">
								<td>
										<img src="http://www.ibm.com/i/c.gif" alt="" height="4" width="100%" />
										<br />
										<table border="0" cellpadding="0" cellspacing="0">
												<tbody>
														<tr>
																<td valign="middle">
																		<br />
																</td>
																<td align="right" valign="top">
																		<br />
																</td>
														</tr>
												</tbody>
										</table>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>
				<a name="N102E2">
						<span class="atitle">结束语</span>
				</a>
		</p>
		<p>在
        <i>实战 Groovy</i> 系列的第一期中，您学习了 Groovy 这个令人兴奋的脚本语言最实用的应用当中的一个。对于越来越多开发人员而言，单元测试是开发过程的重要组成部分；而使用 Groovy 和 JUnit 对 Java 代码进行测试就变成了轻而易举的事情。
      </p>
		<p>Groovy 简单的语法、内部的灵活性，使其成为迅速编写有效的 JUnit 测试、将测试整合到自动编译中的一个优秀平台。对于像我一样为代码质量发狂的人来说，这种组合极大地减少了我的
        <i>神经紧张</i>，还让我可以得到我想做得最好的东西：编写“防弹”软件。快点行动吧。
      </p>
		<p>因为这是一个新的系列，所以我非常希望您能一起来推动它前进。如果您对 Groovy 有什么想了解的事情，请 
        <a href="mailto:aglover@vanwardtechnologies.com">发邮件给我</a>，让我知道您的要求！我希望您会继续支持本系列的下一期，在下期中，我将介绍用 Groovy 进行 Ant 脚本编程。
      </p>
<img src ="http://www.blogjava.net/JafeLee/aggbug/128668.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/JafeLee/" target="_blank">Jafe</a> 2007-07-06 20:53 <a href="http://www.blogjava.net/JafeLee/articles/128668.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>