五. 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)的更多相关文章

  1. Groovy 学习手册(7)

    10. Groovy GPars GPars 一开始在 Groovy 中作为一个单独的项目,同时带来了很多并发的机制.它包含了很多并行的map/redue,Actors,以及其他很多并发的模块. 1. ...

  2. Groovy 学习手册(6)

    9. 不可变特性 不可变特性和函数式编程在一起就像是花生酱和果酱在一起一样.虽然没有必要非要在一起使用,但他们相处得很好. 在纯正的函数式语言中,每个函数对本身之外没有影响,即没有副作用.这意味着每次 ...

  3. Groovy 学习手册(5)

    8. 函数式编程 函数式编程(FP)是一种编程风格,侧重于函数和最小化状态的变化(使用不可变的数据结构).它更接近于用数学来表达解决方案,而不是循序渐进的操作. 在函数式编程里,其功能应该是" ...

  4. Groovy 学习手册(4)

    6. 领域特定语言 Groovy 有许多特性,使它非常适合写DSL(领域特定语言).这些特性包活: 具有委托机制的闭包: 点号(.)和语句末尾的分号(;)是可选的: 运算符的重载(例如,加号,减号等) ...

  5. Groovy 学习手册(2)

    二. 工具 1. 控制台 groovyConsole: Groovy 控制台是一个非常易于使用和简单的轻量级的编辑器.你可以在里面做很多事情. 在编辑器里面可以书写代码,Windows 下,按下Ctr ...

  6. Groovy 学习手册(1)

    1. 需要安装的软件 Java / Groovy 对应 Java 和 Groovy,你需要安装以下软件: Java JDK,例如 JDK 8 IDE,例如 Eclipse,NetBeans 8 Gro ...

  7. Kotlin强化实战!这份学习手册让你的面试稳如泰山

    一.引言 正如官网的slogan所描述:kotlin,是一门让程序员写代码时更有幸福的现代语言. 同时,也正如维基百科里介绍: JetBrains公司希望Kotlin能够推动IntelliJ IDEA ...

  8. Redis学习手册(目录)

    为什么自己当初要选择Redis作为数据存储解决方案中的一员呢?现在能想到的原因主要有三.其一,Redis不仅性能高效,而且完全免费.其二,是基于C/C++开发的服务器,这里应该有一定的感情因素吧.最后 ...

  9. git学习手册

    #git学习手册 git: Git是一个开源的分布式版本控制系统,可以有效.高速的处理从很小到非常大的项目版本管理.[2] Git 是 Linus Torvalds 为了帮助管理 Linux内核开发而 ...

随机推荐

  1. android中实现拨号功能

    1.要实现拨号功能,首先需要开启拨号权限 修改AndroidManifest.xml文件,添加如下内容: <uses-permission android:name="android. ...

  2. jQuery clearQueue

    clearQueue()方法与clearQueue()方法结合: .clearQueue()可用于删除通过.queue()方法添加到通用jQuery序列的任何函数. 示例: <!DOCTYPE ...

  3. LintCode: Number of Airplanes in the Sky

    C++ (1)把interval数组中的所有start和所有end放在同一个数组中,然后进行排序,遇到start就起飞一架飞机,遇到一架end就降落一架飞机,所以start有个+1属性,end有个-1 ...

  4. ReactNative踩坑日志——使用async/await语法解决网络请求的异步导致的指令执行顺序错乱问题

    转载请注明原文地址: ReactNative的fetch是天然的异步请求,因此,如果你在一个代码块中使用了fetch,那么在执行的时候程序不会等待网络响应结束才执行下一条代码,而是会直接按顺序执行完整 ...

  5. 如何在MyEclipse配置Gradle

    1.首先下载gradle gdk http://services.gradle.org/distributions 选一个bin或者all的下载即可 2.配置path GRADLE_HOME  D:\ ...

  6. Oracle Data Integrator 12c----包(Package)

    1 创建"包" Designer->项目->ODI_Exercise ->第一个文件夹->包,右键"新建程序包": "定义&q ...

  7. java byte数组与String互转

      java byte数组与String互转 CreationTime--2018年7月6日14点53分 Author:Marydon 1.String-->byte[] 方法:使用String ...

  8. urllib2特点--urllib2.build_opener对象接口

    # -*- coding: cp936 -*- #python 27 #xiaodeng #urllib2特点--urllib2.build_opener对象接口 import urllib2 imp ...

  9. Spring Cloud Dalston.SR5 BUG一记

    使用Dalston.SR5版本的Zuul时, 发现Ribbon重试不能切换服务实例, 换成Edgware.SR3,同样的配置可以切换实例进行重试 还有个不升级所有Spring Cloud组件的方法,仅 ...

  10. foxmail怎么设置个性签名

    foxmail是我们日常使用的邮件客户端之一,相信很多的朋友都在使用.那么,我们在发邮件的时候,很多朋友都会使用一个个性签名,那么对于foxmail的邮件签名怎么来设置呢?今天笔者就来给大家分享一下, ...