[Learning-Groovy读书笔记]Groovy Design Pattern

tech2023-10-31  101

Groovy Design Pattern

Groovy Design Pattern策略模式Meta-ProgrammingMeta-ClassCategories(静态方法工具箱) Missing MethodsDelegation(委托)问题:

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 方法。
最新回复(0)