首先申明下,本文为笔者学习《Groovy 程序设计》的笔记,并加入笔者自己的理解和归纳总结。
1. 分类注入
Groovy使用use()
来注入方法,但该方法必须是静态的,并且第一个参数必须是目标对象,注入的方法在该代码块内生效。
class IntegerUtil {
// 如果想要限制为Integer类型,可以使用isEven(Integer self)
def static isEven(self) {
self % 2 == 0
}
}
use(IntegerUtil) {
println 5.isEven()
println 8L.isEven()
}
try {
5.isEven()
} catch (ex) {
println ex
}
返回
false
true
groovy.lang.MissingMethodException: ...
Category
注解将静态方法转变为实例方法。
@Category(Integer)
class IntegerUtilAnnotated {
def isEven() {
this % 2 == 0
}
}
use(IntegerUtilAnnotated) {
println 5.isEven()
println 8.isEven()
}
返回
false
true
注入的方法可以使用类或闭包作为参数。
class IntegerOperationUtil {
def static operation(Integer self, closure) {
closure(self, 5)
}
}
use(IntegerOperationUtil) {
println 20.operation { sum, num -> sum + num }
}
返回
25
use()
方法支持多个分类注入,如果存在方法名冲突时,最后一个分类优先级最高。
class IntegerOperation2Util {
def static operation(Integer self, closure) {
closure(self, 3)
}
}
use(IntegerUtil, IntegerOperationUtil, IntegerOperation2Util) {
arr = [5, 8, 12, 15, 20]
println arr.findAll { it.isEven() }
println arr.collect { it.operation { sum, num -> sum + num } }
}
返回
[8, 12, 20]
[8, 11, 15, 18, 23]
注入的方法会拦截原有方法
class IntegerInterceptedUtil {
def static toString(Integer self) {
println "Intercepted"
def method = self.metaClass.methods.find { it.name == 'toString' }
method.invoke(self) + ".00"
}
}
use(IntegerInterceptedUtil) {
println 12.toString()
}
返回
Intercepted
12.00
2. ExpandoMetaClass注入
通过往类的MetaClass
中添加方法,可以向类中注入方法。
class AGroovyClass {
}
obj = new AGroovyClass()
AGroovyClass.metaClass.add = { val1, val2 -> val1 + val2 }
try {
obj.add(11, 13)
} catch (ex) {
println ex // add方法添加在obj初始化之后,obj没有add方法
}
obj = new AGroovyClass()
println obj.add(11, 13) // 24
println obj.add("Hello ", "World!") // Hello World!
如果父类的metaClass
中注入了该方法,子类中也能调用。
class A extends AGroovyClass {
}
class B extends AGroovyClass {
}
println new A().add(11, 13) // 24
println new B().add("Hello ", "World!") // Hello World!
静态方法注入。
AGroovyClass.metaClass.'static'.add = { val1, val2 -> val1 + val2 }
println AGroovyClass.add(11, 13) // 24
println AGroovyClass.add("Hello ", "World!") // Hello World!
构造方法注入,添加一个构造函数,使用<<
操作符。覆盖一个构造函数,使用=
操作符。在添加的构造函数内一定返回一个AGroovyClass
对象。
class AGroovyClass {
AGroovyClass() {
println "AGroovyClass construct"
}
}
// 使用<<
AGroovyClass.metaClass.constructor << { int val ->
println "AGroovyClass construct(integer)"
new AGroovyClass()
}
new AGroovyClass(1)
// 需要使用=
AGroovyClass.metaClass.constructor = {
println "AGroovyClass construct()"
con = AGroovyClass.class.getConstructor(null)
con.newInstance(null)
}
new AGroovyClass()
返回
AGroovyClass construct(integer)
AGroovyClass construct
AGroovyClass construct()
AGroovyClass construct
EMC分组语法,整合所有的方法。
class AGroovyClass {
AGroovyClass() {
println "AGroovyClass construct"
}
}
AGroovyClass.metaClass {
add = { val1, val2 ->
val1 + val2
}
'static' {
add = { val1, val2 -> val1 + val2 }
del = { -> "in del function" }
}
constructor = { int val ->
println "AGroovyClass construct(integer)"
new AGroovyClass()
}
constructor = {
println "AGroovyClass construct()"
con = AGroovyClass.class.getConstructor(null)
con.newInstance(null)
}
}
3. ExpandoMetaClass实例注入
每个ExpandoMetaClass
实例都有一个MetaClass
,修改实例的MetaClass
可以不影响其他实例。使用ExpandoMetaClass
向实例注入。
class AGroovyClass {
}
objA = new AGroovyClass() // 实例对象A
objB = new AGroovyClass() // 实例对象B
emc = new ExpandoMetaClass(AGroovyClass)
emc.add = { val1, val2 ->
val1 + val2
}
emc.initialize()
objA.metaClass = emc // 向A注入方法
println objA.add(11, 13)
try {
objB.add(11, 13) // B中未注入方法,报错
} catch (ex) {
println ex
}
返回
24
groovy.lang.MissingMethodException: ...
直接使用metaClass
,添加方法。
class AGroovyClass {
}
objA = new AGroovyClass() // 实例对象A
objB = new AGroovyClass() // 实例对象B
objA.metaClass.add = { val1, val2 ->
val1 + val2
}
println objA.add(11, 13)
try {
objB.add(11, 13) // B中未注入方法,报错
} catch (ex) {
println ex
}
EMC分组语法。
class AGroovyClass {
}
obj = new AGroovyClass()
obj.metaClass {
add = { ->
"In add function"
}
del = { ->
"In del function"
}
}
println obj.add() // In add function
println obj.del() // In del function
4. Mixin注入
Mixin
在可以在运行时将其他类的实现导入进来。
通过Mixin
注解。
class Helper {
def work() {
println "$name is working"
}
}
@Mixin(Helper)
class AGroovyClass {
def getName() { "AGroovyClass" }
}
new AGroovyClass().work() // AGroovyClass is working
调用类的mixin
方法。
class Helper {
def work() {
println "$name is working"
}
}
class AGroovyClass {
def getName() { "AGroovyClass" }
}
AGroovyClass.mixin Helper
new AGroovyClass().work() // AGroovyClass is working
在类的metaClass
中调用mixin
方法。
AGroovyClass.metaClass.mixin Helper
new AGroovyClass().work() // AGroovyClass is working
多个类mixin
。
class Num {
def add(val1, val2) {
println val1 + val2
}
}
AGroovyClass.mixin Helper
AGroovyClass.mixin Num
// AGroovyClass.metaClass.mixin Helper
// AGroovyClass.metaClass.mixin Num
new AGroovyClass().work() // AGroovyClass is working
new AGroovyClass().add(11, 12) // 23