Groovy 学习手册(4)

6. 领域特定语言
Groovy 有许多特性,使它非常适合写DSL(领域特定语言)。这些特性包活:
- 具有委托机制的闭包;
- 点号(.)和语句末尾的分号(;)是可选的;
- 运算符的重载(例如,加号,减号等);
- methodMissing和- propertyMissing方法
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 指的是“-”运算符。

除了next 和 previous 运算符没有参数外,其他的运算符都有一个参数。下面的例子我们来创建Logic 类包含 一个boolean 类型的变量,来定义and 和 or 方法。
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}" // true
println "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 wiz
wiz << 'Harry'
println wiz
wiz - 'Harry'
println wiz
输出结果为:
Wizards: [Gandolf]
Wizards: [Gandolf, Harry]
Wizards: [Gandolf]
你也可以实现 Map 风格的getAt和putAt方法的重载,这允许你使用括号的语法方式,如下:
def value = object[parameter] // uses getAt
object[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.H2O
println water
println water.weight
这是试图访问一个属性为H2O,会触发 propertyMissing 方法调用。
通过使用静态 exec 方法,该DSL通过将化学实例作为闭包的委托来实现其全部潜力,这允许以下示例:
Chemistry.exec {
        def water = H2O
        println water
        println water.weight
}
这是通过调用Chemistry的propertyMissing 方法相同的效果来创建 H2O 组件。
Tip
Chemisty 的完整代码,请访问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? true
cargo bay: 100
Taxi Take off!
Taxi Landing!
Groovy 学习手册(4)的更多相关文章
- Groovy 学习手册(7)
		10. Groovy GPars GPars 一开始在 Groovy 中作为一个单独的项目,同时带来了很多并发的机制.它包含了很多并行的map/redue,Actors,以及其他很多并发的模块. 1. ... 
- Groovy 学习手册(6)
		9. 不可变特性 不可变特性和函数式编程在一起就像是花生酱和果酱在一起一样.虽然没有必要非要在一起使用,但他们相处得很好. 在纯正的函数式语言中,每个函数对本身之外没有影响,即没有副作用.这意味着每次 ... 
- Groovy 学习手册(5)
		8. 函数式编程 函数式编程(FP)是一种编程风格,侧重于函数和最小化状态的变化(使用不可变的数据结构).它更接近于用数学来表达解决方案,而不是循序渐进的操作. 在函数式编程里,其功能应该是" ... 
- Groovy 学习手册(3)
		五. Groovy 的设计模式 设计模式是一种非常好的方式,可以使你的代码变得实用,可读又具有扩展性.跟 Java 相比,在 Groovy 里使用设计模式使代码更加简洁和容易. 1. 策略模式 设想一 ... 
- Groovy 学习手册(2)
		二. 工具 1. 控制台 groovyConsole: Groovy 控制台是一个非常易于使用和简单的轻量级的编辑器.你可以在里面做很多事情. 在编辑器里面可以书写代码,Windows 下,按下Ctr ... 
- Groovy 学习手册(1)
		1. 需要安装的软件 Java / Groovy 对应 Java 和 Groovy,你需要安装以下软件: Java JDK,例如 JDK 8 IDE,例如 Eclipse,NetBeans 8 Gro ... 
- Kotlin强化实战!这份学习手册让你的面试稳如泰山
		一.引言 正如官网的slogan所描述:kotlin,是一门让程序员写代码时更有幸福的现代语言. 同时,也正如维基百科里介绍: JetBrains公司希望Kotlin能够推动IntelliJ IDEA ... 
- Redis学习手册(目录)
		为什么自己当初要选择Redis作为数据存储解决方案中的一员呢?现在能想到的原因主要有三.其一,Redis不仅性能高效,而且完全免费.其二,是基于C/C++开发的服务器,这里应该有一定的感情因素吧.最后 ... 
- git学习手册
		#git学习手册 git: Git是一个开源的分布式版本控制系统,可以有效.高速的处理从很小到非常大的项目版本管理.[2] Git 是 Linus Torvalds 为了帮助管理 Linux内核开发而 ... 
随机推荐
- Discuz常见小问题-如何关闭验证码
			进入后台,在防灌水,验证设置中可以切换哪些情况下是否使用验证码 如果启用验证码,也客户修改验证码的难度,样式.最后点击提交,完成之后可以退出到前台,测试是否能够不用验证码自动登录 
- Discuz常见小问题-如何安装模板,使用模板
			点击应用,获取更多插件 在模板页面中选择需要的类型(需要注册一个账号) 找好一个模板之后,点击安装应用(一般也会有演示) 安装完成之后可以在界面-风格管理中选择安装好的模板,选中新的模板,点击提交即可 ... 
- PAT 1065 1066 1067 1068
			pat 1065 A+B and C 主要是注意一下加法溢出的情况,不要试图使用double,因为它的精度是15~16 ... 
- linux2.6.30.4内核移植(3)——yaffs文件系统移植
			内核源码:linux2.6.30.4 交叉编译工具:3.4.5 移植linux内核至:TQ2440 工作基础:http://www.cnblogs.com/nufangrensheng/p/36696 ... 
- 浅谈mysql中utf8和utf8mb4区别
			转自:http://ourmysql.com/archives/1402 实践过程中发现有时mysql的字符集会引起故障,所以需要了解下这个知识点. 一.简介 MySQL在5.5.3之后增加了这个u ... 
- 《React-Native系列》44、基于多个TextInput的键盘遮挡处理方案优化
			曾经写过两篇关于在ReactNative上处理键盘遮挡输入表单TextInput的情况.建议读者能够先看看 1.<React-Native系列>33. 键盘遮挡问题处理 2.<Rea ... 
- 你如何获取浏览器URL中查询字符串中的参数?
			测试地址为:http://www.runoob.com/jquery/misc-trim.html?channelid=12333&name=xiaoming&age=23 实例如下: ... 
- java 加密
			加密.大体上分为双向加密和单向加密,而双向加密又分为对称加密和非对称加密. 双向加密大体意思就是明文加密后形成密文,能够通过算法还原成明文. 单向加密仅仅是对信息进行了摘要计算,不能通过算法生成明文. ... 
- Sql server中依据存储过程中的部分信息查找存储过程名称的方法【视图和Function】
			1.查询的语句: select a.id,b.name,a.*,b.* from syscomments a join sysobjects b on a.id=b.id where b.xtype= ... 
- Java之创建对象>3.Enforce the singleton property with a private constructor or an enum type
			1. 通过一个公开的字段来获取单例 // Singleton with public final field public class Elvis { public static final Elv ... 
