Groovy探索 Visitor模式
Groovy语言中的Visitor模式的实现,其实也跟闭包有很大的、直接的关系。当然,你也可以完全不用闭包来实现Visitor模式,就像Java语言那样来实现。但使用了闭包的Visitor模式更加简单,更加易于扩展。所以,我们在Groovy语言中,倾向于使用闭包来实现Visitor模式。这也是我很久以来,都想把这篇文字放在《Groovy探索 闭包》系列中的原因,但由于Visitor模式的复杂性,使得我倾向于以模式的观点来说明它,以利于我们的理解。
Java语言实现的Visitor模式一向是难于理解的一个模式,它的实现基本上有两大类的接口,众多的实体实现。在这里我不多说,有兴趣的看官或者没有学过Java语言Visitor模式的,可以在网上找资料来看。
其实,Visitor模式的目的非常简单,就是把被访问者的数据结构和访问者的动作分离,有利于访问者的扩展。这里,值得注意的是:该模式强调的是被访问者要有一定的确定性,访问者才是可以扩展的。
在Groovy语言中,我们的访问者被简化成一个个的闭包,不再需要一个Visitor接口,让我们从一个简单得不能再简单的例子说起。
比如,我们有如下的一个被访问者对象:
def visitable = [1,2,3,4,5]
这是一个简单的数组对象,现在,我们的第一个访问者希望打印出被访问者的所有元素来。我们就可以这样来定义一个访问者:
def visitor1 = {
println it
}
现在,我们让访问者去访问被访问者:
visitable.each(visitor1)
运行结果为:
1
2
3
4
5
当然,我们使用Visitor模式的目的,就是要扩展访问者,现在,我们就可以扩展另外一个访问者了。
def total = 0
def visitor2 = {
total += it
}
我们也让这个访问者来访问被访问者:
visitable.each(visitor2)
println total
运行结果为:
15
通过上面的例子,我们可以看到,在使用Groovy语言实现的Visitor模式中,我们是如何使用闭包来实现Visitor接口的实现的。正是通过闭包,我们在Groovy语言实现的Visitor模式中,就再也找不到Visitor接口了。
现在,我们再理解Java语言实现的Visitor模式的Visitor接口,其实就是让访问者动作有一个实体类可以存在,因为在Java语言中,方法是不能独立存在的。而在Groovy语言中,方法能够以闭包的形式独立存在,所以就用不着Visitor接口了。
理解了这一层关系以后,我们上面的代码就可以进一步简化成如下的样子了:
visitable.each{
println it
}
visitable.each{
total += it
}
println total
在这里,我们连声明一个Visitor对象都省了,但它们实现的也是Visitor模式。
上面是一个最简单不过的例子,不能显示出Visitor模式的复杂性来。下面,我们就来说说一个相对复杂一点的例子来,进一步的分析Visitor模式。
这个例子说的是,我们在优惠期间到电脑店去买电脑及周边产品。电脑店在优惠期间是这样买商品的:电脑打九折,光盘是买5送1。现在,我们要买一台电脑,12张光盘,想知道我们花了多少钱。
现在,我们就来模拟这个场景。
首先,我们定义的是被访问者和访问者之间的接口类:
class Goods {
def accept(Closure doAction)
{
doAction(this)
}
}
这个Goods类的目的很简单,就是让访问者对象能够访问到被访问者对象,如果没有这个Goods类,那么上面的"accept"方法就要分布在各个被访问者类中。而"accept"方法中的输入参数"doAction",就是访问者对象了。
现在,该我们的Computer类出场了:
class Computer extends Goods{
def amount
def price
def static DISCOUNT = 0.9
def totalPrice()
{
price*amount*DISCOUNT
}
def totalDiscount()
{
price*amount*(1-DISCOUNT)
}
}
它也很简单:有两个输入属性分别用来定义购买的数量和单价,一个常量属性用来定义折扣。两个方法分别来获取总价和总的折扣价。
同样的功能是Disk类,现在由它出场:
class Disk extends Goods{
def amount
def price
def totalPrice()
{
(amount-(amount/5 as int))*price
}
def totalDiscount()
{
(amount/5 as int)*price
}
}
它实现的是买五送一的活动。下面的Sales类来定义我们买了多少东西:
class Sales {
List goods
def accept(Closure doAction)
{
goods.each{
it.accept(doAction)
}
}
}
它的"accept"方法用来使得访问者能够访问我们所买的所有东西。当然,该方法的"doAction"就是我们的访问者对象了。
现在,一切就绪,我们就可以来访问被访问者了。
首先,我们想知道我们总共花了多少钱?
def mySales = new Sales(goods:[new Computer(amount:1,price:500),new Disk(amount:12,price:2)])
上面的初始化,我们共买了单价为500的电脑一台,单价为2的光盘12张。我们定义一个变量来存取我们所花的钱:
def totalPrice = 0
我们来计算我们总共花了多少钱:
mySales.accept{
totalPrice += it.totalPrice()
}
println "my total price is ${totalPrice}"
结果为:
my total price is 470.0
这样,一个稍微复杂一点的Visitor模式就全部实现了。
你可能要问了,我的访问者对象不是可以扩展吗?你扩展一个给我看看,好,我们现在来计算我们总共省了多少钱。
def totalDiscount = 0
mySales.accept{
totalDiscount += it.totalDiscount()
}
println "my total discount is ${totalDiscount}"
运行结果为:
my total discount is 54.0
使用闭包实现的Visitor模式还有一个好处是能够扩展被访问者,使用在Java语言中实现的Visitor所难以做到的,如果要做到,一般要用到反射技术。而在Groovy语言闭包所实现的Visitor中,我们可以很轻松的扩展被访问者。
比如,我们现在还想买一个鼠标,它没有折扣,如下:
class Mouse extends Goods{
def amount
def price
def totalPrice()
{
amount*price
}
def totalDiscount()
{
0
}
}
现在,我们的客户端就可以这样使用:
def mySales = new Sales(goods:[new Computer(amount:1,price:500),new Disk(amount:12,price:2),
new Mouse(amount:1,price:10)])
def totalPrice = 0
mySales.accept{
totalPrice += it.totalPrice()
}
println "my total price is ${totalPrice}"
def totalDiscount = 0
mySales.accept{
totalDiscount += it.totalDiscount()
}
println "my total discount is ${totalDiscount}"
运行结果为:
my total price is 480.0
my total discount is 54.0
可以看出,在Groovy语言中使用闭包实现的Visitor是非常好理解的,简单到你没有意识到你是在使用Visitor模式,而且,这个Visitor模式也很容易扩展它的被访问者。就像上面的例子那样。
分享到:
相关推荐
Groovy是Java平台的一个崭新的语言,它为Java带来了许多使Ruby流行的特征。《Groovy in Action》是Groovy编程的综合指南,它向Java开发者介绍了...Groovy专家可以获得一个对他们进行全面和创造性Groovy探索的可靠参考。
apache-groovy-3.0.8.zip apache官网的groovy3.0.8版本,希望大家多多下载,apache-groovy-3.0.8.zip apache官网的groovy3.0.8版本,希望大家多多下载,apache-groovy-3.0.8.zip apache官网的groovy3.0.8版本,希望...
赠送jar包:groovy-3.0.9.jar; 赠送原API文档:groovy-3.0.9-javadoc.jar; 赠送源代码:groovy-3.0.9-sources.jar; 赠送Maven依赖信息文件:groovy-3.0.9.pom; 包含翻译后的API文档:groovy-3.0.9-javadoc-API...
groovy入门经典,groovyeclipse 插件
Making Java Groovy is a practical handbook for developers who want to blend Groovy into their day to day work with Java It starts by introducing the key differences between Java and Groovy and how you...
Java调用Groovy,实时动态加载数据库groovy脚本,java读取mongoDB的groovy脚本,加载实时运行,热部署
Groovy
Groovy轻松入门—搭建Groovy开发环境 Groovy轻松入门—搭建Groovy开发环境
groovy
groovy-2.3.6-installer windows安装版本
什么是 Groovy? Groovy 是 JVM 的一个替代语言 — 替代 是指可以用 Groovy 在 Java 平台上进行 Java 编程,使用方式基本与使用 Java 代码的方式相同。在编写新应用程序时,Groovy 代码能够与 Java 代码很好地结合,...
groovy eclipse plugin2groovy eclipse plugin2groovy eclipse plugin2groovy eclipse plugin2groovy eclipse plugin2groovy eclipse plugin2groovy eclipse plugin2
groovy的帮助文档 !!!!!
Groovy in Action, Second Edition is the undisputed definitive reference on the Groovy language. Written by core members of the Groovy language team, this book presents Groovy like no other can—from ...
groovy 源码
Groovy jar包 3.0.
Groovy 教程。简单的groovy教程。
Groovy 调用 Java 类groovy 调用 Java class 十分方便,只需要在类前导入该 Java 类,在 Groovy 代码中就可以无缝使用该
Eclipse Groovy插件 Eclipse Groovy插件 Eclipse Groovy插件 Eclipse Groovy插件