博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Groovy 学习手册(4)
阅读量:4594 次
发布时间:2019-06-09

本文共 4492 字,大约阅读时间需要 14 分钟。

Groovy

6. 领域特定语言

Groovy 有许多特性,使它非常适合写DSL(领域特定语言)。这些特性包活:

  • 具有委托机制的闭包;
  • 点号(.)和语句末尾的分号(;)是可选的;
  • 运算符的重载(例如,加号,减号等);
  • methodMissingpropertyMissing 方法

Tip

关于 DSLs (Domain Specific Languages ),可以参考此书《DSLs In Action》。

特定领域语言可以用于许多目的,如允许领域专家阅读和编写代码,或澄清业务逻辑的含义。它们允许商业专家阅读或编写代码而不必是一名编程专家。

1. 委托

在 Groovy 中,可以将一个代码块(或闭包)作为参数,然后使用一个局部变量作为委托调用它。例如,下面的代码用来发送短信:

class SMS {      def from(String fromNumber) {            // set the from      }      def to(String toNumber) {            // set the to       }      def body(String body) {            // set the body of text     }     def send() {           // send the text.     }}

但是,在 Java 中你需要使用如下的方式:

SMS m = new  SMS();m.from("555-432-1234");m.to("555-678-4321");m.body("Hey there!");m.send();

在 Groovy 中可以定义用来发送短信的静态方法,按照 DSL 风格的使用方式,代码块通常作为一个闭包)。

def static send(block) {    SMS m = new SMS()    block.delegate = m    block()    m.send()}

这将 SMS 对象设置为代码块的委托,以便将方法转发给它。 有了这个,你现在可以执行以下操作:

SMS.send {    from '555-432-1234'    to '555-678-4321'    body 'Hey there!'}

关于 delegate, 个人理解,闭包中的 delegate 类似于类中的 this.

2. 重载运算符

在 Groovy 中,你可以使用运算符的英文单词来重载对应的运算符,例如,plus 指的是“+”运算符,minus 指的是“-”运算符。

运算符

除了nextprevious 运算符没有参数外,其他的运算符都有一个参数。下面的例子我们来创建Logic类包含 一个boolean 类型的变量,来定义andor 方法。

class  Logic  {    boolean value    Logic(v) {this.value = v}        def and(Logic other) {        this.value && other.value    }    def or(Logic other) {        this.value || other.value    }}

我们可以使用这些方法,看是否和我们预想的一样。

def  pale = new Logic(true)def old = new Logic(false)// Notice that using the built-in && operator // uses “Groovy truth” and returns true // because both variables are non-null .println "groovy truth: ${pale && old}" // trueprintln "using and: ${pale & old}"  // false println "using or: ${pale | old}"  // true

下面的例子定义个重载<<- 的类。

class Wizards {    def list = []    def leftShift(person) { list.add person }    def  minus(person) { list.remove person }    String toString() { "Wizards: $list" }}def  wiz = new  Wizards()wiz << 'Gandolf'println wizwiz << 'Harry'println wizwiz - 'Harry'println wiz

输出结果为:

Wizards: [Gandolf]Wizards: [Gandolf, Harry]Wizards: [Gandolf]

你也可以实现 Map 风格的getAtputAt方法的重载,这允许你使用括号的语法方式,如下:

def value = object[parameter] // uses getAtobject[parameter] = value // uses putAt

3. 缺失的方法和属性

以前介绍过,Groovy在运行时提供methodMissing方法了来实现的功能的方式。

def methodMissing(String name, args)
然而,Groovy还提供了一种方法来拦截使用Groovy的属性语法访问缺失的属性。使用 propertyMissing(String name)来实现属性的访问,通过propertyMissing(String name, Object value)来修改属性。
看下面的例子,这里有一个化合物类的DSL片段描述:

class  Chemistry  {    public static void exec(Closure block) {        block.delegate = new  Chemistry()        block()    }        def propertyMissing(String name) {        def  comp = new  Compound(name)        (comp.elements.size() == 1 && comp.elements.values()[0]==1) ?            comp.elements.keySet()[0] : comp    }}

在这个例子中,propertyMissing 创建一个新的Compound对象并返回,如果Compound对象只有一个元素的话,则返回这个元素对象。这可以用来创建一个基于缺失属性的名字的Compound对象。看例子:

def  c = new  Chemistry()def water = c.H2Oprintln waterprintln water.weight

这是试图访问一个属性为H2O,会触发 propertyMissing 方法调用。

通过使用静态 exec 方法,该DSL通过将化学实例作为闭包的委托来实现其全部潜力,这允许以下示例:

Chemistry.exec {        def water = H2O        println water        println water.weight}

这是通过调用ChemistrypropertyMissing 方法相同的效果来创建 H2O 组件。

Tip

Chemisty 的完整代码,请访问;

7. trait 语法

trail 就像具有默认方法和属性的接口,Groovy中的trait 是受到Scale语言里的trait的启发。

在Java8中我们知道在接口里面可以有默认方法,trail跟Java8中的接口很像,但是具有修改状态(属性)的能力。这样会更加灵活,但是也要非常小心。

1. 定义trait

我们来定义一个trait:

trait Animal {    int hunger = 100    def  eat() { println "eating"; hunger -= 1 }    abstract int getNumberOfLegs()}

这个定义的trait具有方法,属性和抽象方法。如果一个类要实现他,必须实现对应的抽象方法。

2. 使用trait

要想实现trait,跟Java中的类实现接口一样,使用implements 关键字。

class Rocket  {    String name    def  launch() { println(name + " Take off!") }}trait MoonLander {    def land() { println("${getName()} Landing!") }    abstract String getName()}class  Apollo  extends  Rocket implements  MoonLander {}

你可以如下代码来使用它:

def  apollo = new  Apollo(name: "Apollo 12")apollo.launch()apollo.land()

输出结果为:

Apollo 12 Take off!Apollo 12 Landing!

你可以在一个类上实现多个trait,例如:

trait Shuttle {    boolean canFly() { true }    abstract int getCargoBaySize()  }class MoonShuttle  extends  Rocket    implements  MoonLander, Shuttle {    int getCargoBaySize() { 100 }}

然后可以如下使用:

MoonShuttle m = new  MoonShuttle(name: 'Taxi')println "${m.name} can fly? ${m.canFly()}"println "cargo bay: ${m.getCargoBaySize()}"m.launch()m.land()

输出结果为:

Taxi can fly? truecargo bay: 100Taxi Take off!Taxi Landing!

转载于:https://www.cnblogs.com/IcanFixIt/p/6652369.html

你可能感兴趣的文章
组合数据类型练习,英文词频统计实例上
查看>>
python入门知识
查看>>
为什么我在博客园开始写博客
查看>>
ES6数组的扩展
查看>>
xshell不能输入中文,显示为??
查看>>
[NGUI]NGUI图集Atlas制作
查看>>
vue的坑
查看>>
【原创】大数据基础之Airflow(2)生产环境部署airflow研究
查看>>
传说中的滑雪,巨丑勿拍(poj1088/tyvj1004)
查看>>
webpack——图片的路径与打包
查看>>
.net4.0注册到IIS ,重新注册IIS ,iis注册
查看>>
winform中devexpress bindcommand无效的解决方法
查看>>
SVN使用教程总结
查看>>
神经网络与机器学习 第一讲(1)——为什么需要机器学习
查看>>
算法入门
查看>>
SQL Server 2012 中 SSAS 多维数据浏览器已经废除
查看>>
codeforces 251 div2 C. Devu and Partitioning of the Array 模拟
查看>>
基于设计模式的学习之旅-----命令模式(附源码)
查看>>
ECMAScript6-let和const命令
查看>>
常见Jquery问题
查看>>