程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> 更多編程語言 >> Groovy >> Groovy高效編程:動態改變對象的能力

Groovy高效編程:動態改變對象的能力

編輯: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

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved