商讯信箱
用户名: @
密  码:   注册|忘记密码
登录
个人用户经销商
您的位置:首页 > 技术频道 > 正文

Groovy高效编程——动态改变对象的能力

  【IT168 技术文档】从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
©版权所有。未经许可,不得转载。
[责任编辑:cynthia]