Groovy Design Pattern
Groovy Design Pattern
策略模式
在Groovy中,函数是一等公民,所以和Java相比,实现策略模式时更加灵活。
策略模式的例子很多。这里省略
Meta-Programming
Meta-Class
Groovy可以通过"metaClass"属性来动态的为既有的Class添加属性或者方法。
注意:不可与@CompileStatic or @TypeChecked 联用。
String.metaClass.generator = "groovy"
String.metaClass.words = { -> split(/ +/)}
println "I like the groovy".generator
println "I like the groovy".words()
执行结果如下:
groovy
[I, like, the, groovy]
Categories(静态方法工具箱)
Category时Groovy提供的另一种扩充既有的Class,添加功能的方法。可以把Category想象成可以扩充既有Class的工具箱, 这些工具是一系列的静态方法,static 功能(扩充对象)。 当我们想使用这些工具时可以通过 use(category){} 打开这些工具箱。
例如:
class Slary{
int amount
Slary plus(Slary s){
amount += s.amount
this
}
Slary plus(Expend s){
amount -= s.amount
this
}
}
class Expend{ int amount}
class SlaryCategory{
static Slary getAsSlary(Integer self) {
new Slary(amount: self)
}
static Expend getAsExpend(Integer self) {
new Expend(amount: self)
}
}
use(SlaryCategory){
def balance = 300.asSlary + 100.asSlary + 50.asExpend
println balance.amount
}
执行结果如下:
350
Missing Methods
"按需分配"式的定义方法。通过 **def methodMissing(String name, args) ** 捕捉对于不存在的方法调用。可在该方法中定义方法并且执行。
class Slary{
int amount
def someMethod(args){
println "this:$this"
println "this.amount: ${this.amount}"
println "amount: $amount"
amount += args
}
def methodMissing(String name, args){
println "MethodMissing:$name"
def method = Slary.methods.find{ it.name === 'someMethod'}
Slary.metaClass."$name" = method
println "${name}(${args})"
return method.invoke(this, args)
}
}
def aSlary = new Slary()
def a = aSlary.plus(1000)
println aSlary
println a
def bSlary = new Slary()
println bSlary
def c =bSlary.plus(1000)
println c
执行结果如下:
MethodMissing:plus
plus([1000])
this:Slary@26d77d18
this.amount: 0
amount: 0
Slary@26d77d18
1000
Slary@5ed9bf80
MethodMissing:plus
plus([1000])
this:Slary@5ed9bf80
this.amount: 0
amount: 0
1000
Delegation(委托)
所谓委托:抽取其他类的Public方法接口作为本类的方法,但将方法的实现委托与其他类的实例。可以:
- 使用类的组合而非继承。
- 模拟多重继承。
- 践行迪米特法则(Law ofDemeter,LoD)
例如:
class Tank{
def runOnRoad(){println "As tank, can run on the road"}
}
class Boat {
def sailOnWater(){println "As boat, can sail on the water"}
}
class AmphibiousTank {
@Delegate final Tank tank
@Delegate final Boat boat
public AmphibiousTank(Tank tank, Boat boat) {
this.tank = tank
this.boat = boat
}
public AmphibiousTank() {
this.tank = new Tank()
this.boat = new Boat()
}
}
def amphibiousTank = new AmphibiousTank()
amphibiousTank.runOnRoad()
amphibiousTank.sailOnWater()
执行结果如下:
As tank, can run on the road
As boat, can sail on the water
问题:
- 下面这些代码被执行时,最后 new Slary().plus(1000) 语句会返回 5000.
class Slary{
int amount
def methodMissing(String name, args){
println ("enter methodMissing")
def impl = {
this.amount += args[0]
println "this:$this"
this
}
println "impl:$impl"
Slary.metaClass."$name" = impl
impl()
}
}
def a = new Slary().plus(1000)
println "a:$a, a.amount:${a.amount}"
def b = a.plus(1000)
println "b:$b, b.amount:${b.amount}"
def c = new Slary().plus(1000)
println "c:$c, c.amount: ${c.amount}"
执行结果如下:
enter methodMissing
this:Slary@7717ced9
impl:
this:Slary@7717ced9
a:Slary@7717ced9, a.amount:2000
enter methodMissing
this:Slary@7717ced9
impl:
this:Slary@7717ced9
b:Slary@7717ced9, b.amount:4000
this:Slary@7717ced9
c:Slary@7717ced9, c.amount: 5000
推测原因如下:
- println “impl:$impl” 将会执行impl Closure.
- 使用 Slary.metaClass."$name" = impl 将 impl Closure 设置为 Slary的 metaClass 方法之后,设置时的this或者amount会被“冻住”到memtaClass中,所以即使我们重新创建Slary实例,调用plus时,实际使用是第一个实例。
- 在添加 metaClass 方法之前创建的实例,无法看到新创建的方法。所以 a.plus(1000) 实际调用的还是 methodMissing 方法。