- 浏览: 5166518 次
- 性别:
- 来自: 天津
博客专栏
-
实战 Groovy
浏览量:29349
文章分类
- 全部博客 (639)
- 代码之谜 (6)
- JavaScript quirks (5)
- 程序员 (92)
- Java (93)
- BT编程 (7)
- html/css (64)
- Groovy&Grails (42)
- Android (20)
- C/C++ (5)
- PHP/Perl/Python (46)
- 经典文章 (51)
- CodeIgniter (14)
- JQuery (10)
- 笑话 (4)
- 其他 (32)
- javascript (69)
- 云计算 (0)
- html5 (7)
- 面试 (8)
- google (3)
- nosql (2)
- nodejs (11)
- go (5)
- erlang (1)
- 小常识 (3)
- 冷知识 (5)
- database (4)
- web (12)
- 架构 (12)
- Exception (0)
最新评论
-
jqw1992:
https://www.chromefor.com/libra ...
[福利] 开发者必备的 Chrome 插件——ChromeSnifferPlus -
litjerk:
初步算了一下,目前最最精简的Win98版是5M,他5个小时多敲 ...
让人目瞪口呆的三位世界级电脑大师 -
379855529:
。。似乎重点没说NIO啊,前面基础只是铺垫的很好的,可是我要的 ...
Java NIO与IO的详细区别(通俗篇) -
springmvc_springjpa:
spring mvc demo教程源代码下载,地址:http: ...
一步步开发 Spring MVC 应用 -
匡建武:
Good
四个程序员的一天
Groovy 简洁的语法将开发人员从那种需要进行代码编译但却无助于表达 什么 是程序真正想要实现的典型的 Java™ 结构中解放了出来。在实战 Groovy 系列的这一复兴篇中,Groovy 开发人员兼特约专栏作家 J. Scott Hickey 带您进行一系列对常规 Java 代码和 Groovy 代码的比较,展示这门令人兴奋的语言如何将您解放出来,让您能够专注于编码的重要方面。
通常,程序员们转而选择诸如 Groovy 之类的编程语言,是为了构建快速的实用程序,快速编写测试代码,甚至创建构成大型的 Java 应用程序的组件,而 Groovy 先天具有这样一种能力,它能够减少传统的基于 Java 系统所固有的许多冗余并降低其复杂度。Groovy 简洁而灵活的语法将开发人员从那种需要进行代码编译却无助于表达什么 是程序真正想要实现的典型的 Java 结构中解放出来。不仅如此,Groovy 轻松的类型通过减少一些接口和超类使代码不再复杂,这些接口和超类都是常规 Java 应用程序用以支持不同具体类型间的通用行为所需的。
为了举例说明 Groovy 如何减少 Java 应用程序所涉及的无用数据,我将使用 Bruce Tate 和 Justin Ghetland 的 Spring: A Developer's Notebook(参见 参考资料)中的样例代码,该书介绍了如何使用 Spring 进行控制反转。每当回顾一个 Java 样例,我都会将其与实现相同功能的相应的 Groovy 源代码进行比较,您将很快发现 Groovy 通过减少 Java 编程的不同方面(冗余且不必要地传递了应用程序的行为)而使应用程序代码变得多么地清晰。
在 Bruce 和 Justin 这本书的第一章中,创建了一个简单的自行车商店应用程序,其中包含有四个类。首先,我将向您展示一个简单的名为 Bike
的 JavaBean 类,该类代表了一辆库存的自行车。然后,我会考查自行车商店的类型,名为 RentABike
。它包含了一个 Bike
集。还有一个命名为 CommandLineView
的用于显示自行车列表的类,该类依赖于 RentABike
类型。最后,有一个用于集成这些部分以创建工作应用程序的类,该类利用 Spring 来传递完整地配置了 RentABike
类型的 CommandLineView
类 —— 免去了复杂的硬编码。
清单 1 中一个代表自行车的类在常规 Java 代码中被实现为一个简单的 JavaBean,它是 Java 开发人员可能已经编写好的成百上千的类的一个典型。通常来说,JavaBean 并没有什么特殊之处 —— 其属性被声明为 private
,且可通过 public
getter 和 setter 对其进行访问。
import java.math.BigDecimal; public class Bike { private String manufacturer; private String model; private int frame; private String serialNo; private double weight; private String status; private BigDecimal cost; public Bike(String manufacturer, String model, int frame, String serialNo, double weight, String status) { this.manufacturer = manufacturer; this.model = model; this.frame = frame; this.serialNo = serialNo; this.weight = weight; this.status = status; } public String toString() { return "com.springbook.Bike : " + "manufacturer -- " + manufacturer + "\n: model -- " + model + "\n: frame -- " + frame + "\n: serialNo -- " + serialNo + "\n: weight -- " + weight + "\n: status -- " + status + ".\n"; } public String getManufacturer() { return manufacturer; } public void setManufacturer(String manufacturer) { this.manufacturer = manufacturer; } public String getModel() { return model; } public void setModel(String model) { this.model = model; } public int getFrame() { return frame; } public void setFrame(int frame) { this.frame = frame; } public String getSerialNo() { return serialNo; } public void setSerialNo(String serialNo) { this.serialNo = serialNo; } public double getWeight() { return weight; } public void setWeight(double weight) { this.weight = weight; } public String getStatus() { return status; } public void setStatus(String status) { this.status = status; } public BigDecimal getCost() { return cost; } public void setCost(BigDecimal cost) { this.cost = cost.setScale(3,BigDecimal.ROUND_HALF_UP); } } |
清单 1 是一个只有一个构造方法和六个属性的小例子,但其代码却填满了浏览器的整个页面!清单 2 显示了在 Groovy 中定义的相同的 JavaBean:
class Bike { String manufacturer String model Integer frame String serialNo Double weight String status BigDecimal cost public void setCost(BigDecimal newCost) { cost = newCost.setScale(3, BigDecimal.ROUND_HALF_UP) } public String toString() { return """Bike: manufacturer -- ${manufacturer} model -- ${model} frame -- ${frame} serialNo -- ${serialNo} """ } } |
您认为哪一个没那么多冗余呢?
Groovy 版的代码要少很多很多,这是因为 Groovy 的默认属性语义用 public
访问器和存取器自动定义了 private
域。例如,上述 model
属性现在有了自动定义的 getModel()
方法和 setModel()
方法。可以看到,这项技术的好处是,不必在一种类型中按照属性手工定义两个方法!这也解释了 Groovy 中的一条反复强调的定律:使普通的编码规则变得简单。
|
另外,在 Groovy 中,类的默认函数表达得更为简洁,而在常规 Java 代码(如 清单 1)中该函数必须显式编码。当需要用构造函数或 getter 或 setter 来完成一些特殊任务时,Groovy 真的很出色,因为只需瞥一眼代码,其精彩的行为就会立即变得十分明显。例如,在 清单 2 中很容易看出,setCost()
方法会将 cost
属性换算为三个十进制的位。
将这段不太显眼的 Groovy 代码同 清单 1 中的 Java 源代码进行比较。第一次阅读这段代码时,您注意到 setCost()
方法中嵌入了特殊的函数了吗?除非仔细观察,否则太容易看漏了!
清单 3 中 Bike
类的测试用例展示了如何使用自动生成的访问器。同时,出于进一步简化通用编程任务的考虑,测试用例也使用了更为简便的 Groovy 点属性名 标记来访问属性。相应地,能够通过getModel()
方法或更为简洁的 b.model
形式来引用 model
属性。
class BikeTest extends GroovyTestCase { void testBike() { // Groovy way to initialize a new object def b = new Bike(manufacturer:"Shimano", model:"Roadmaster") // explicitly call the default accessors assert b.getManufacturer() == "Shimano" assert b.getModel() == "Roadmaster" // Groovier way to invoke accessors assert b.model == "Roadmaster" assert b.manufacturer == "Shimano" } } |
也注意到在上述 Groovy 例子中,不必定义一个如 清单 1 中定义的 Java 构造函数那样的能够接受全部六个属性的构造函数。同时,也不必要创建另一个 只含两个参数的构造函数来支持测试用例 —— 在对象创建过程中设置对象属性的 Groovy 的语义不需要这种冗余、烦人的构造函数(它们综合有多个参数但其作用却只是初始化变量)。
|
在前面的部分中,Bike
GroovyBean 利用了 Groovy 的属性和构造语义以减少源代码中的冗余。在这一部分中,Groovy 版的自行车商店也将受益于额外的冗余减少特性,如针对多态的 duck-typing、集合类的改进及操作符重载。
在 Java 自行车应用程序中,名为 RentABike
的接口是用来定义由自行车商店支持的 public
方法的。正如在清单 4 中说明的那样,RentABike
定义了一些简单的方法,这些方法用来返回商店中单个的 Bike
或所有 Bike
的列表。
import java.util.List; public interface RentABike { List getBikes(); Bike getBike(String serialNo); void setStoreName(String name); String getStoreName(); } |
此接口允许多态行为并在下面两种重要情况下提供了灵活性。其一,如果要决定将实现由 ArrayList
转变为数据库形式,余下的应用程序与该变化是隔绝的。其二,使用接口为单元测试提供灵活性。例如,如果要决定为应用程序使用数据库,可以轻易地创建一个该类型的模拟实现,而且它不依赖于实时数据库。
清单 5 是 RentABike
接口的 Java 实现,它使用 ArrayList
来存储多个 Bike
类:
import java.util.List; import java.util.ArrayList; import java.util.Iterator; public class ArrayListRentABike implements RentABike { private String storeName; final List bikes = new ArrayList(); public void setStoreName(String name) { this.storeName = name; } public String getStoreName() { return storeName; } public ArrayListRentABike(String storeName) { this.storeName = storeName; bikes.add(new Bike("Shimano", "Roadmaster", 20, "11111", 15, "Fair")); bikes.add(new Bike("Cannondale", "F2000 XTR", 18, "22222",12, "Excellent")); bikes.add(new Bike("Trek","6000", 19, "33333", 12.4,"Fair")); } public String toString() { return "com.springbook.RentABike: " + storeName; } public List getBikes() { return bikes; } public Bike getBike(String serialNo) { Iterator iter = bikes.iterator(); while(iter.hasNext()) { Bike bike = (Bike)iter.next(); if(serialNo.equals(bike.getSerialNo())) return bike; } return null; } } |
现在将 清单 4 和 5 中的 Java 代码同 清单 6 中的 Groovy 代码进行比较。Groovy 版的代码很灵巧地避免了对 RentABike
接口的需求。
清单 6. Groovy 的 ArrayListRentABike 实现
public class ArrayListRentABike { String storeName List bikes = [] public ArrayListRentABike(){ // add new instances of Bike using Groovy's initializer syntax bikes << new Bike(manufacturer:"Shimano", model:"Roadmaster", frame: 20, serialNo:"11111", weight:15, status:"Fair") bikes << new Bike(manufacturer:"Cannondale", model:"F2000", frame: 18, serialNo:"22222", weight:12, status:"Excellent") bikes << new Bike(manufacturer:"Trek", model:"6000", frame: 19, serialNo:"33333", weight:12.4, status:"Fair") } // Groovy returns the last value if no return statement is specified public String toString() { "Store Name:=" + storeName } // Find a bike by the serial number def getBike(serialNo) { bikes.find{it.serialNo == serialNo} } } |
Groovy 像其他动态语言(如 Smalltalk 或 Ruby)一样支持具有 “duck typing” 的多态 —— 在运行时,如果一个对象表现得像个 duck ,它就会被视为 duck ,从而支持无 接口的多态。有了 GroovyArrayListRentABike
实现,不但减少了成行的代码,而且由于少创建和维护一个模块,复杂性也降低了。那是非常重要的冗余减少!
除了 duck typing,清单 6 中的默认属性语法还简单地定义了两个普通属性,storeName
和 bikes
,如同拥有了 getter 和 setter 一样。这样做的好处和在 清单 1 和 2 中比较 JavaBean-GroovyBean 时所说明的好处是一样的。尤其是,清单 6 还阐明了另一个用以减少代码冗余的 Groovy 特性 —— 操作符重载。请注意如何使用 <<
操作符来代替 add()
方法。通过减少一层嵌套的括号使代码的可读性得以改善。这也是 Groovy 众多通过减少冗余而改善代码可读性的特性中的一种。
|
Groovy 中的 duck-typing 和属性语义通过减少代码行数来减少冗余;然而,也可以通过增加透明度来减少冗余。在 清单 6 中,请注意在 ArrayListRentABike
构造函数中创建新 Bike
对象的方式。Groovy 名称和值的初始化语法比 Java 版的略微详细,但这些额外的代码却使整个代码更为透明 —— 将这一点与 清单 5 中 Java 版的进行比较,哪个属性被初始化为哪个值会立即明显 起来。不回过头来看 Bike
JavaBean 源代码,您能记起哪个参数是 frame
,哪个是 new Bike("Shimano"、 "Roadmaster"、20、 "11111"、15、 "Fair")
的 weight
吗?尽管我刚写过,但我还是记不起来!
到目前为止,我将 Bike
和自行车商店类型在 Java 和 Groovy 下进行了比较。现在,到了更近距离地看一下自行车商店的视图 的时候了。在清单 7 中,该视图类具有一个 rentaBike
属性,该属性引用RentABike
接口并在行动上说明 Java 版的多态。由于 Java 要求所有类属性都必须是声明过的类型,而不是针对某个特定的实现进行编码,我向一个接口编程,该接口使这个类跟 RentABike
实现的改变分隔开来。这是很好的、扎实的 Java 编程实践。
public class CommandLineView { private RentABike rentaBike; public CommandLineView() {} public void setRentaBike(RentABike rentaBike) { this.rentaBike = rentaBike; } public RentABike getRentaBike() { return this.rentaBike; } public void printAllBikes() { System.out.println(rentaBike.toString()); Iterator iter = rentaBike.getBikes().iterator(); while(iter.hasNext()) { Bike bike = (Bike)iter.next(); System.out.println(bike.toString()); } } } |
将清单 7 中的 Java 视图与清单 8 中的 Groovy 视图进行比较,请注意我声明了带 def
关键字的 rentaBike
。这是 duck-typing 的实践,与 Java 版的很像。我正在实践好的软件设计,这是因为我还没有将视图和特定的实现耦合起来。但我也能够不 定义接口就实现解耦。
清单 8. Groovy 的 CommandLineView
public class CommandLineView { def rentaBike // no interface or concrete type required, duck typing in action def printAllBikes() { println rentaBike rentaBike.bikes.each{ println it} // no iterators or casting } } |
与 Bike
和自行车商店类型一样,Groovy 的 CommandLineView
没有了为 RentABike
属性所显式编写 的 getter 或 setter 的冗余。同样,在 printAllBikes()
方法中,通过使用 each
来打印在集合里找到的每辆自行车,我再一次利用了 Groovy 强大的集合功能的改进。
在前面的部分中,已经介绍了 Groovy 相比 Java 是如何定义自行车、自行车商店和自行车商店视图的。现在该介绍如何将整个应用程序组装起来并在命令行视图中使用 Spring 来显示库存自行车列表了。
在 Java 编程中,一旦定义了一个接口,就可以使用工厂模式将创建真实的实现类的责任委派给一个对象工厂。使用 Spring 作为一个工厂极大地减少了冗余,并在 Groovy 和 Java 中都能够使用,在最终的代码样例中,Spring 负责在 Java 和 Groovy 中创建一个 CommandLineView
类型的实例。
在清单 9 中,配置 Spring 是为了在返回一个 CommandLineView
实例前,创建并将自行车商店的 ArrayList
实现注入 CommandLineView
中。这意味着,不需要引用在 清单 7 和 8 的 Java 或是 Groovy 版的命令行视图中的 ArrayList
实现。在 Java 版中,被注入的类通常都会引用一个接口而不是实现。在 Groovy 中,由于使用 def
关键字,而允许利用 duck-typing。无论在哪个实例中,配置 Spring 的目的都是为了将自行车商店视图的实例和自行车商店类型的实例完整地配置起来!
<beans> <bean id="rentaBike" class="ArrayListRentABike"> <property name="storeName"><value>"Bruce's Bikes (spring bean)"</value></property> </bean> <bean id="commandLineView" class="CommandLineView"> <property name="rentaBike"><ref bean="rentaBike"/></property> </bean> </beans> |
在清单 10 和 11 中,自行车商店组装类型用清单 9 中的配置文件创建了一个 Spring 的 ClassPathXmlApplicationContext
实例,然后,请求自行车商店视图的实例:
清单 10. Java 版本下调用 Spring 创建自行车商店视图
import org.springframework.context.support.ClassPathXmlApplicationContext; public class RentABikeAssembler { public static final void main(String[] args) { // Create a Spring application context object ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("RentABike-context.xml"); // retrieve an object from Spring and cast to a specific type CommandLineView clv = (CommandLineView)ctx.getBean("commandLineView"); clv.printAllBikes(); } } |
请注意Java 版的清单 10 中,用以请求一个命令行视图实例的对 Spring 的调用要求向一个支持 printAllBikes()
方法的对象类型强制转换。在本例中,由 Spring 导出的对象将被强制转换为CommandLineView
。
有了 Groovy 及其对 duck-typing 的支持,将不再需要强制转换。只需确保由 Spring 返回的类能够对合适的方法调用(printAllBikes()
)作出响应。
import org.springframework.context.support.ClassPathXmlApplicationContext class RentABikeAssembler { public static final void main(String[] args) { // Create a Spring application context object def ctx = new ClassPathXmlApplicationContext("RentABike-context.xml") //Ask Spring for an instance of CommandLineView, with a //Bike store implementation set by Spring def clv = ctx.getBean("commandLineView") //duck typing again clv.printAllBikes() } } |
正如在清单 11 中看到的那样,在 Groovy 中,duck-typing 对减少冗余的贡献不仅体现在无需声明接口即可支持由 Spring 自动配置对象,其贡献还体现在简化了对完全配置的 bean 的使用(一旦它从 Spring 容器中返回)。
至此,希望我已经阐明了 Groovy 的强大功能及其如何能如此深远地改变源代码的性质。与上述 Java 样例相比,Groovy 代码更简短也更易理解。任何人,无论是经验丰富的 Java 架构师还是非 Java 程序员,都能轻易地掌握 Groovy 代码的意图。Groovy 及其对动态类型的支持减少了要管理的文件。总之,使用 Groovy 减少了在典型的 Java 程序中所常见的大量冗余。这实在是福音啊!
发表评论
-
实战 Groovy: 用 Groovy 打造服务器端
2010-07-10 11:07 2720Groovlet 和 GroovyServer P ... -
实战 Groovy: 用 Groovy 生成器作标记
2010-07-10 11:07 2060Groovy 生成器让您能够利用诸如 Swing 这样 ... -
实战 Groovy: for each 剖析
2010-07-10 11:07 18189在这一期的 实战 Groovy 中,Scott Davi ... -
实战 Groovy: 用 Groovy 进行 Ant 脚本编程
2010-07-10 11:07 2059Ant 和 Maven 两者在构建处理工具的世界中占统 ... -
实战 Groovy: 在 Java 应用程序中加一些 Groovy 进来
2010-07-10 11:06 4321您有没有想过在自己相对复杂的 Java 程序中嵌入 G ... -
实战 Groovy: Groovy 的腾飞
2010-07-10 11:06 2182随着 Groovy JSR-1(及其后续发行版本)的发 ... -
实战 Groovy: 用 curry 过的闭包进行函数式编程
2010-07-10 11:06 3250在 Groovy 中处处都是闭包,Groovy 闭包惟 ... -
实战 Groovy: 关于 MOP 和迷你语言
2010-07-10 11:06 2065将耳朵贴到地上仔细听 —— MOP 正在前进!了解一下 ... -
实战 Groovy: 用 Groovy 更迅速地对 Java 代码进行单元测试
2010-07-10 11:06 2302不久以前,developerWor ... -
实战 Groovy: 构建和解析 XML
2010-07-10 11:05 7116通过本文,您将了解 ... -
实战 Groovy: 用 Groovy 进行 JDBC 编程
2010-07-10 11:05 5183这个月,随着 Andrew G ... -
实战 Groovy: 美妙的操作符
2010-07-10 11:05 2284Java™ 取消了操作符重载,但是新兴的 Groovy ... -
实战 Groovy: 使用 Groovy 模板进行 MVC 编程
2010-07-10 11:04 2911视图是 MVC 编程的一个重要部分,而 MVC 编程本 ... -
实战 Groovy: Groovy:Java 程序员的 DSL
2010-07-10 11:04 3079Groovy 专家 Scott Davis 将重新开始 ... -
精通 Grails: 构建您的第一个 Grails 应用程序
2010-07-06 09:37 1646Java™ 程序员不需要 ... -
Grails 部署
2010-07-06 09:36 6071部署 Grails可以使用很多种方式来部署,每一种 ... -
Grails 脚手架
2010-07-05 08:20 4075脚手架 根据指定的领域类,脚手架为你自动生成 ... -
Grails Grails 与 Hibernate
2010-07-05 08:19 2699Grails 与 Hibernate 如果 GOR ... -
Grails Grails和 Spring
2010-07-05 08:19 7901Grails和 Spring 这一节适合于高级用户 ... -
Grails Web服务
2010-07-05 08:19 3957Web服务 Web服务就是让你的web应用提供一套 ...
相关推荐
### IBM实战Groovy知识点概览 #### 一、Groovy简介 **Groovy**是一种运行在Java平台上的灵活且强大的编程语言,它以其简洁、高效和面向对象的特点著称。Groovy是由James Strachan和Bob McWhirter创建的,并在2004年...
- **简洁性**:Groovy简化了许多Java中的冗余语法,如无需显式声明变量类型。 - **扩展性**:Groovy允许开发者通过元编程来扩展现有类的功能。 **2. Groovy语法基础** - **变量声明**:Groovy中的变量声明不需要...
1. **简洁的语法**:Groovy的语法比Java更加简洁明了,减少了冗余的代码量,提高了开发效率。例如,它可以省略分号和大括号,使代码更易读。 2. **动态类型**:Groovy支持动态类型,这意味着变量的类型可以在运行时...
4. **优化**:对AST进行优化,消除冗余代码,提高生成代码的效率。 5. **代码生成**:最后,将AST转换为目标机器语言或字节码,如Java字节码,以便在JVM上运行。 在这个项目中,我们可以学习到ANTLR4如何处理语法...
2. **简洁性**:Groovy的语法比Java更紧凑,减少了冗余代码,提高了开发效率。 3. **集成性**:Groovy可以直接调用Java库,与Java代码无缝集成,无需额外的桥接层。 4. **元编程**:Groovy支持元编程,可以方便地...
**项目概述** ...总的来说,`Project Lombok` 是一种强大的工具,可以帮助Java开发者提高生产力,减少代码冗余,同时保持代码整洁。不过,理解其工作原理和限制,才能更好地在项目中发挥它的优势。
1. **简洁的语法**:Groovy的语法比Java更为简洁,减少了冗余的括号和分号,使得代码更易读写。 2. **动态类型**:Groovy支持动态类型,这意味着变量的类型在运行时确定,减少了编译时期的错误检查。 3. **集成Java*...
这一过程中,Java代码的复杂性和冗余性暴露无遗。 - **解决方案**:介绍了函数式编程的核心概念,如映射(map)和过滤器(filter),并通过这些高级特性简化了常见的编程任务,使得代码更为简洁高效。 #### 如何在...
4. **静态导入**:允许将类中的静态成员直接引入到当前作用域,减少冗余的类名引用,如`import static java.lang.Math.PI;`。 5. **增强的for循环**(foreach):简化遍历数组和集合的代码,如`for (String str : ...
最后,作为一本面向实践的书籍,可能会包含大量的实例代码和实战案例,让读者能够直接应用到自己的项目中。这些案例可能涵盖了不同类型的软件项目,从Web应用到桌面应用,再到分布式系统,读者可以从中学习到如何...
Elasticsearch支持在查询和聚合过程中使用脚本,可以使用Painless或Groovy等语言编写,实现动态计算和逻辑判断。 八、安全与权限 Elasticsearch 5.x及之后的版本引入了Security插件,提供了用户认证、角色分配和...