Groovy探索 Visitor模式
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模式也很容易擴充套件它的被訪問者。就像上面的例子那樣。
相關文章
- Visitor模式加深理解模式
- Visitor模式和Observer觀察者模式模式Server
- 看visitor模式的感受模式
- 設計模式、用Delphi描述-->Visitor模式 (轉)設計模式
- Groovy探索 使用集合方法,寫出更加Groovy風格的程式碼
- C++設計模式 - 訪問器模式(Visitor)C++設計模式
- Groovy探索之Gpath和List的結合 更加Groovy風格的程式碼
- C#設計模式系列:訪問者模式(Visitor)C#設計模式
- 設計模式--訪問者模式Visitor(行為型)設計模式
- JAVA設計模式之 訪問者模式【Visitor Pattern】Java設計模式
- 九、GO 程式設計模式:K8S VISITOR 模式Go程式設計設計模式K8S
- 設計模式的征途—16.訪問者(Visitor)模式設計模式
- Java Tip: 用Reflection實現Visitor模式 (轉)Java模式
- Groovy探索 DSL在Calendar類上的實踐 一
- 完成C++不能做到的事 - Visitor模式C++模式
- 【設計模式】詳解訪問者(Visitor)模式-有多段程式碼出沒設計模式
- groovy
- Kafka KRaft模式探索KafkaRaft模式
- 訪問者(Visitor)
- 提高Groovy品質 Groovy 1.5.2釋出
- Groovy and SoapUIUI
- Groovy 2.0.6和Groovy 2.1 beta版本釋出
- Visitor Pattern Introduction (轉)
- [Groovy]Groovy指令碼的5種執行方式指令碼
- groovy安裝
- 深入探索Factory模式與Prototype模式的異同 (轉)模式
- Groovy初學者指南
- Groovy閉包理解
- Groovy動態解析
- Parse CSV file with Groovy
- groovy : 隨機數隨機
- Groovy 2.0釋出
- Groovy 2.0.4 釋出
- 我的一個visitor實作
- Xxx專案敏捷模式探索敏捷模式
- 專案管理建設模式探索(轉)專案管理模式
- Java和groovy相互呼叫Java
- groovy之範圍特性