Decorate模式相信大家都比較熟悉了,是一個"BangOfFour"中最常用的模式之一,實現起來也相當的簡單。如果有人不熟悉的話,可以看看《Groovy探索之Decorate模式》,那裡面有一個本篇要沿用的例子。
這個例子就是咖啡館裡買咖啡的經典例子,咖啡有原味咖啡,還有根據顧客口味不同進行各種添加,比如加冰、加奶和加糖等等。顧客可以選擇不加、加一樣或加多樣,各種加法的咖啡所買的價格也不一樣。
這個例子是Decorate模式實現的最經典的例子。我們在這裡希望使用自定義Range類來實現它。
我們首先要定義一個基類來實現自定義的Range,其他所有的咖啡類型都是它的子類,這樣,我們所有的咖啡類型就都擁有了Range類的特性。先來來看這個基類:
package range;
class Base implements Comparable{
static protected types = ['Coffee','Ice','Milk','Sugar']
protected int index = 0
protected type
protected getIndex()
{
this.index = this.types.indexOf(type)
}
def next()
{
Factory.getObject(types[(index+1)%types.size()])
}
def previous()
{
Factory.getObject(types[index-1])
}
int compareTo(Object other)
{
index<=>other.index
}
}
在這個基類中,變量"types"是所有的咖啡類型。其他的,如"index"變量,"next"、"previous"和"compareTo"方法,它們的邏輯都和一般的自定義Range類的那些變量和方法一樣。
"type"變量和"getIndex()"是為了方便"Base"類的子類而定義的,也就是說,在"Base"類的子類中,我們不用管下面的語句是干什麼用的:
this.index = this.types.indexOf(type)
因為子類的對象在"Base"類中不可預期,因此,我們使用了一個工廠方法來使得自定義的Range類能夠獲取到遍歷的子類對象。如下:
Factory.getObject(types[(index+1)%types.size()])
或者:
Factory.getObject(types[index-1])
下面,我們來看看工廠類:
package range;
class Factory {
static def getObject(type)
{
Class clazz = Class.forName("range.${type}")
return clazz.newInstance()
}
}
也很簡單,就是通過咖啡類型來獲取咖啡對象。
下面,就該輪到我們各個咖啡類出場了:
package range;
class Coffee extends Base{
def Coffee()
{
this.type = 'Coffee'
this.getIndex()
}
def description()
{
'Coffee'
}
def price()
{
10
}
}
上面是原味咖啡的類實現,它繼承了"Base"類,在構造器裡,它首先給"type"對象賦值"Coffee",然後調用"getIndex"方法,目的是設置該類的在Range中的當前位置。其他的兩個方法"description"和"price"方法,就與自定義的Range類沒有關系了,是我們的咖啡系列的邏輯要用到的方法。
其他的幾個咖啡類跟原味咖啡的實現一樣。下面的是"Ice"類:
package range;
class Ice extends Base{
def Ice()
{
this.type = 'Ice'
this.getIndex()
}
def description()
{
'with ice'
}
def price()
{
1
}
}
接著是"Milk"類:
package range;
class Milk extends Base{
def Milk()
{
this.type = 'Milk'
this.getIndex()
}
def description()
{
'with milk'
}
def price()
{
5
}
}
最後是"Sugar"類:
package range;
class Sugar extends Base{
def Sugar()
{
this.type = 'Sugar'
this.getIndex()
}
def description()
{
'with sugar'
}
def price()
{
3
}
}
這些類都很簡單,沒有多余的邏輯。
下面,我們就可以來使用這個自定義的Range類了,比如一個顧客希望他的咖啡加冰、加奶、加糖。那麼,我們就可以這樣實現了:
def coffee = new Coffee()
def sugar = new Sugar()
def description = ''
(coffee..sugar).each{
description += it.description()+' '
}
println description
運行結果為:
Coffee with ice with milk with sugar