Groovy 学习手册(3)

摘要:
上面的代码prices)total+=pricetotal}充满冗余。2.Groovy中的元编程意味着向运行时类添加方法。您可以在一些常规类中添加一些帮助方法,以使代码更简洁和可读。代表getAttribute(key)}HttpSession。元类。putAt={key,value)}这里的委托是一个只存在于闭包中的对象。

Groovy

五. 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()

免责声明:文章转载自《Groovy 学习手册(3)》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇Android应用中使用百度地图API定位自己的位置(二)jmeter远程多机负载进行性能测试下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

XAML: 在 MVVM 模式中,关于绑定的几处技巧

    以下会提到三个绑定的技巧,分别是 在 ListView 中为 ListViewItem 的 MenuFlyout 绑定 Command; 在 ListView 的 事件中绑定所选择项目,即其 SelectedItem属性; 处理文本控件与数值属性绑定中默认值0的问题; 一、在 ListView 中为列表项的 MenuFlyout 绑定 Comm...

IDEA内置常用代码模板和DUG模式

/**IDEA中代码模板 psvm 调用main方法 sout 调用输出语句 soutp :可以打印形参 soutm :打印方法名 soutv:打印变量fori:for循环 iter:增强for循环 ifn 或者 XX.null: if (XX == null) {} inn 或者 XX.nn : if (XX != null) {}prsf :...

JNI数据类型(转)

  本文原创,转载请注明出处:http://blog.csdn.net/qinjuning     在Java存在两种数据类型: 基本类型 和 引用类型 ,大家都懂的 。     在JNI的世界里也存在类似的数据类型,与Java比较起来,其范围更具严格性,如下:         1、primitive types ----基本数据类型,如:int、 flo...

【java】Java组件概览(2)— 基本库

1、Math Math相关的库包括包括浮点库(java.lang.Math和java.lang.StrictMath)和任意精度数学(java.math包)。 (1)java.lang.Math   该类包含执行基本数值运算的方法,如基本指数、对数、平方根、三角函数、弧度/角度、四舍五入以及最大、最小和绝对值。 另外,还有两个常量无理数E(e)和PI(π)...

JavaScript中科学计数法转化为数值字符串形式

原文地址:https://www.css88.com/archives/9318 (受益匪浅) JavaScript 中经常会碰到数值计算问题,偶尔会在不经意间报一个不是bug的bug。今天来说说一个特殊的例子。我以0.0011BTC 价格买入 0.0002CZR 计算出了的金额是 0.00000022BTC,而 JavaScript 计算出来的金额是 2...

八、设置HTTP应答头 (基础教程8)

八、设置HTTP应答头   作 者 : 仙人掌工作室            8.1 HTTP应答头概述         Web服务器的HTTP应答一般由以下几项构成:一个状态行,一个或多个应答头,一个空行,内容文档。设置HTTP应答头往往和设置状态行中的状态代码结合起来。例如,有好几个表示“文档位置已经改变”的状态代码都伴随着一个Location头,而40...