科技行者

行者学院 转型私董会 科技行者专题报道 网红大战科技行者

知识库

知识库 安全导航



ZDNet>软件频道>中间件-zhiding>Groovy高效编程——动态改变对象的能力

  • 扫一扫
    分享文章到微信

  • 扫一扫
    关注官方公众号
    至顶头条

从Groovy1.1beta-2开始,实现动态改变对象的能力变的十分简单。而从Groovy1.1beta-3开始,Groovy的动态性有了进一步的增强。

来源:蛟龍居 2007年11月18日

关键字:改变对象 编程 Groovy

从Groovy1.1beta-2开始,实现动态改变对象的能力变的十分简单:

一开始,我们有这样一个类:

class Person {
String name
}

该类的实例都是哑巴,不能说话,作为造物主的我们该完善它们,使它们能自我介绍(添加实例方法):

class Person {
String name
}

// 添加自我介绍的行为
Person.metaClass.introduce << {println "I'm $name"}


现在让我们看看,它们到底是否真的能够开口自我介绍了呢:

class Person {
String name
}

// 添加自我介绍的行为
Person.metaClass.introduce << {println "I'm $name"}
def person = new Person(name:"山风小子")
person.introduce()

运行结果:
I'm 山风小子

嗯~人类改造成功~

但人应该有性别吧,嗯~对的,加个性别属性sex(添加属性):

class Person {
String name
}

// 添加自我介绍的行为
Person.metaClass.introduce << {println "I'm $name"}
// 添加性别属性,默认为男(Male)
Person.metaClass.sex = "Male"
def person = new Person(name:"山风小子")
person.introduce()
println person.sex

运行结果:
I'm 山风小子
Male


但做男人累啊~为了买房,娶妻拼命赚钱,做女人算了,做变性手术:

class Person {
String name
}

// 添加自我介绍的行为
Person.metaClass.introduce << {println "I'm $name"}
// 添加性别属性,默认为男(Male)
Person.metaClass.sex = "Male"
def person = new Person(name:"山风小子")
person.introduce()
println person.sex
// 做变性手术,变为女的(Female)
person.sex = "Female"
println person.sex

运行结果:
I'm 山风小子
Male
Female

作为造物主的我们考虑到手术的风险性,为了让其他人知道自己现在是个女的,在介绍中添加性别说明:

class Person {
String name
}

// 添加自我介绍的行为
Person.metaClass.introduce << {println "I'm $name"}
// 添加性别属性,默认为男(Male)
Person.metaClass.sex = "Male"
// 修改之前自我介绍行为,添加性别说明
Person.metaClass.introduce << {println "I'm $name, $sex"}
def person = new Person(name:"山风小子")
person.introduce()
// 做变性手术,变为女的(Female)
person.sex = "Female"
person.introduce()

运行结果:
I'm 山风小子, Male
I'm 山风小子, Female

为了造人方便点,搞个工厂方法(添加类方法,即静态方法):

class Person {
String name
}
// 添加自我介绍的行为
Person.metaClass.introduce << {println "I'm $name"}
// 添加性别属性,默认为男(Male)
Person.metaClass.sex = "Male"
// 修改之前自我介绍行为,添加性别说明
Person.metaClass.introduce << {println "I'm $name, $sex"}
def person = new Person(name:"山风小子")
person.introduce()
// 做变性手术,变为女的(Female)
person.sex = "Female"
person.introduce()
// 工厂方法,造人方便点
Person.metaClass.'static'.createPerson = { name, sex ->
Person p = new Person()
p.name = name
p.sex = sex
return p
}
def bluesun = Person.createPerson("山风小子", "Male")
bluesun.introduce()

运行结果:
I'm 山风小子, Male
I'm 山风小子, Female
I'm 山风小子, Male

为了方便实例化Person,添加一个构造方法(添加构造方法):

class Person {
String name
}
// 添加自我介绍的行为
Person.metaClass.introduce << {println "I'm $name"}
// 添加性别属性,默认为男(Male)
Person.metaClass.sex = "Male"
// 修改之前自我介绍行为,添加性别说明
Person.metaClass.introduce << {println "I'm $name, $sex"}
def person = new Person(name:"山风小子")
person.introduce()
// 做变性手术,变为女的(Female)
person.sex = "Female"
person.introduce()
// 工厂方法,造人方便点
Person.metaClass.'static'.createPerson = { name, sex ->
Person p = new Person()
p.name = name
p.sex = sex
return p
}
def bluesun = Person.createPerson("山风小子", "Male")
bluesun.introduce()
// 方便实例化Person,添加一个构造方法
Person.metaClass.constructor << { name, sex ->
new Person(name:name, sex:sex)
}
def daniel = new Person("Daniel", "Male")
daniel.introduce()

运行结果:
I'm 山风小子, Male
I'm 山风小子, Female
I'm 山风小子, Male
I'm Daniel, Male

最后,引用一个官方例子swapCase来展示一下Groovy是如何增强既有类的能力的(演示如何使用delegate,注意演示的是final类:String)

String.metaClass.swapCase = {->
def sb = new StringBuffer()
// delegate与this类似,引用当前正被‘改造’的对象
delegate.each {
sb << (Character.isUpperCase(it as char) ? Character.toLowerCase(it as char) :
Character.toUpperCase(it as char))
}
sb.toString()
}

String s = "Hello, world!"
println s.swapCase()

运行结果:
hELLO, WORLD!

<<用于添加方法(如果方法已经存在,会发生groovy.lang.GroovyRuntimeException异常),=用于添加方法或覆盖既有方法

而从Groovy1.1beta-3开始,Groovy的动态性有了进一步的增强:

我们可以通过respondsTo和hasProperty方法来判断是否存在某个方法和某个属性:

class Person {
String name

public Person(name) {
this.name = name
}

def introduce() {
println "I'm $name"
}

def introduce(String name) {
println "She is $name"
}
}

def daniel = new Person('Daniel')

// 判断实例daniel是否有方法introduce()
if (daniel.metaClass.respondsTo(daniel, 'introduce')) {
daniel.introduce()
}

// 判断实例daniel是否有方法introduce(String)
if (daniel.metaClass.respondsTo(daniel, 'introduce', String)) {
daniel.introduce('Annie')
}

// 判断实例daniel是否有属性name
if (daniel.metaClass.hasProperty(daniel, 'name')) {
println daniel.name
}

运行结果:
I'm Daniel
She is Annie
Daniel


使用methodMissing方法来处理对那些不存在的方法的调用

class Person {
String name

public Person(name) {
this.name = name
}

def introduce() {
println "I'm $name"
}

def introduce(String name) {
println "She is $name"
}
}

Person.metaClass.methodMissing = { name, args ->
// 动态添加方法
Person.metaClass."$name" = { methodArgs ->
if ("hello".equals(name))
println "$methodArgs"
else {
def argList = Arrays.asList(methodArgs)
println "No method $name with ${argList*.class}"
}
}

delegate."$name"(args)
}

def daniel = new Person('Daniel')

daniel.hello("Leona")
daniel.hi("Annie", "Leona")

运行结果:
{"Leona"}
No method hi with [class java.lang.String, class java.lang.String]


类似地,使用propertyMissing方法来处理对那些不存在的属性的引用

class Person {
String name

public Person(name) {
this.name = name
}

def introduce() {
println "I'm $name"
}

def introduce(String name) {
println "She is $name"
}
}

Person.metaClass.propertyMissing = { String name, value ->
// 动态添加属性
Person.metaClass."$name" = value
}

def daniel = new Person('Daniel')
daniel.sex = 'Male'
println daniel.sex

运行结果:
Male

查看本文来源

推广二维码
邮件订阅

如果您非常迫切的想了解IT领域最新产品与技术信息,那么订阅至顶网技术邮件将是您的最佳途径之一。

重磅专题