Groovy 学习手册(3)
五. Groovy 的设计模式
设计模式是一种非常好的方式,可以使你的代码变得实用,可读又具有扩展性。跟 Java 相比,在 Groovy 里使用设计模式使代码更加简洁和容易。
1. 策略模式
设想一下,下面有三个不同方法用来计算数字相加的总和:
def totalPricesLessThan10(prices) {
int total = 0
for (int price : prices)
if (price < 10) total += price
total
}
def totalPricesMoreThan10(prices) {
int total = 0
for (int price : prices)
if (price > 10) total += price
total
}
def totalPrices(prices) {
int total = 0
for (int price : prices)
total += price
total
}
上面的代码充满了大量的冗余,每个方法之间只有很少不同的改动。在 Groovy 中,你可以使用闭包作为参数,从而减少三个方法的冗余。
def totalPrices(prices, selector) {
int total = 0
for (int price : prices)
if (selector(price)) total += price
total
}
现在,你就剩下一个方法了,这里的selector
是闭包的参数名,如果闭包参数是方法里面最后一个参数,你可以把你的闭包实现放在方法的外面,所以,你可以用下面的代码来实现上面三个方法的功能:
totalPrices(prices) { it < 10 }
totalPrices(prices) { it > 10 }
totalPrices(prices) { true }
这样的代码看起来不仅简洁,而且可读性和扩展性都非常好。
2. 元编程
Groovy里的元编程意味着可以为运行时的类增加方法。这样,你就可以为一些通用类添加一些帮助方法使你的代码更加简洁和可读。
(1) 元类
例如,你在编写javax.servlet.Filter
类,你需要获取和设置多个session
的属性,你可以这样做:
HttpSession.metaClass.getAt = { key -> delegate.getAttribute(key) }
HttpSession.metaClass.putAt = {
key, value -> delegate.setAttribute(key, value)
}
这里的delegate
是闭包里才存在的对象,在上面的代码中它指的就是HttpSession
。
接下来你可以这样:
def session = request.session
session['my_id'] = '123'
def id = session['my_id']
(2) Category
Category 是 Groovy 里元编程技术中的一个。Category 是一个用来给已经存在的类增加功能的类。如果你不想把一个类影响整个应用程序,而只是给部分代码给予特殊对待的话,Category 是非常有用的。
使用 Category 的话,你需要创建静态方法,并且要至少有一个特殊类型的形参(例如,Integer),当这个 Category 被使用时,那这个形参类型的对象也一下子有了除了它本身的方法以外,又增加了先前定义的静态方法。调用该方法的对象作为第一个参数。
例如,Groovy 有一个内置的TimeCategory
, 用来操作时间和日期,这允许你添加和减去任意长度的时间。例如,
import groovy.time.TimeCategory
def now = new Date()
println now
use(TimeCategory) {
nextWeekPlusTenHours = now + 1.week + 10.hours - 30.seconds
}
println nextWeekPlusTenHours
这时,TimeCategory 添加了很多方法应用于Integer 类上,例如,一些方法的签名如下所示:
static Duration getDays(Integer self)
static TimeDuration getHours(Integer self)
static TimeDuration getMinutes(Integer self)
static DatumDependentDuration getMonths(Integer self)
static TimeDuration getSeconds(Integer self)
Tip
关于TimeCategory API 供你参考。
3. 不存在的方法
在Groovy中你可以拦截不存在方法(调用的方法不是传统意义上的定义),可以使用methodMissing
方法。这是一个非常有用的设计模式,当你想在运行是动态定义方法并且使用一个灵活的方法和签名。你写的methodMissing
签名如下:
def methodMissing(String name, args)
参数中的name
就是不存在方法的名字,args
可以接收所有传递这个方法的参数值。使用这两个参数,你可以编写想让这个方法拥有的任何功能。
下一步,实现非常高效,你可以拦截,缓存,调用这个方法,例如
def methodMissing(String name, args) {
impl = { /* your code */ }
getMetaClass()."$name" = impl
impl()
}
以上实现了缺失的功能,然后将其添加到当前类的元类中,以便将来的调用直接转到实现的方法而不是不存在的方法。 如果您希望多次调用同一个不存在的方法,这可能很有用。
4. 委托机制
委派是当一个类在方法中直接调用(方法签名是唯一的)另一个类的方法。 这在Java中很难实现,因为向类中添加方法是很困难和耗时的。
在Groovy 2.0中使用新的@Delegate注解会非常容易, 这就像编译期间的元编程。 它会自动将委托类的方法添加到当前类中。例如:
public class Person {
def eatDonuts() { println("yummy") }
}
public class RoboCop {
@Delegate final Person person
public RoboCop(Person person) { this.person = person }
public RoboCop() { this.person = new Person() }
def crushCars() {
println("smash")
}
}
尽管RoboCop
没有eatDonuts
方法,但是所有Person
类的方法都添加给了RoboCop
类,并且委派了person
变量,下面的使用是没有问题的:
def person = new RoboCop()
person.eatDonuts()
person.crushCars()