首页 | 源码下载 | 网站模板 | 网页特效 | 广告代码 | 网页素材 | 字体下载 | 书库 | 站长工具
会员投稿 投稿指南 RSS订阅
当前位置:主页>网络编程>java教程>资讯:实战 Groovy: @Delegate 注释

实战 Groovy: @Delegate 注释

www.jz123.cn  2009-10-09   来源:   中国建站    责任编辑(袁袁)    我要投递新闻

Scott Davis 将继续有关 Groovy 元编程的讨论,这一次他将深入研究 @Delegate 注释,@Delegate 注释模糊了数据类型和行为以及静态和动态类型之间的区别。

  在过去几期 实战 Groovy 文章中,您已经了解了闭包和元编程之类的 Groovy 语言特性如何将动态功能添加到 Java™ 开发中。本文提供了更多这方面的内容。您将看到 @Delegate 注释如何演变自 ExpandoMetaClass 使用的 delegate。您将再一次领略到 Groovy 的动态功能如何使它成为单元测试的理想语言。

  在 “使用闭包、ExpandoMetaClass 和类别进行元编程” 一文中,您了解了 delegate 的概念。当将一个 shout() 方法添加到 java.lang.String 的 ExpandoMetaClass 中时,您使用 delegate 来表示两个类之间的关系,如清单 1 所示:

  清单 1. 使用 delegate 访问 String.toUpperCase()


String.metaClass.shout = {->
  return delegate.toUpperCase()
  }
  println "Hello MetaProgramming".shout()
  //output
  HELLO METAPROGRAMMING

  您不能表示为 this.toUpperCase(),因为 ExpandoMetaClass 并未包含 toUpperCase() 方法。类似地,也不能表示为 super.toUpperCase(),因为 ExpandoMetaClass 没有扩展 String。(事实上,它不可能扩展 String,因为 String 是一个 final 类)。Java 语言并不具备用于表示这两个类之间的共生关系的词汇。这就是为什么 Groovy 要引入 delegate 概念。

  在 Groovy 1.6 中,@Delegate 注释被添加到该语言中。(从 参考资料 部分可以获得添加到 Groovy 1.6 中的所有新注释的列表)。该注释允许您向任意 类添加一个或多个委托 — 而不仅仅是 ExpandoMetaClass。

  要充分地认识到 @Delegate 注释的威力,考虑 Java 编程中一个常见但复杂的任务:在 final 类的基础上创建一个新类。

  复合模式和 final 类

  假设您希望创建一个 AllCapsString 类,它具有 java.lang.String 的所有行为,唯一的不同是 — 正如名称暗示的那样 — 值始终以大写的形式返回。String 是一个 final 类 — Java 演化到尽头的产物。清单 2 证明您无法直接扩展 String:

  清单 2. 扩展 final 类是不可能的


 class AllCapsString extends String{
  }
  $ groovyc AllCapsString.groovy
  org.codehaus.groovy.control.MultipleCompilationErrorsException:
  startup failed, AllCapsString.groovy: 1: You are not allowed to
  overwrite the final class 'java.lang.String'.
  @ line 1, column 1.
  class AllCapsString extends String{
  ^
  1 error

  这段代码无效,因此您的下一个最佳选择就是使用符合模式,如清单 3 所示(有关复合模式的更多信息,请参见 参考资料):

  清单 3. 对 String 类的新类型使用复合模式

 


 class AllCapsString{
  final String body
  AllCapsString(String body){
  this.body = body.toUpperCase()
  }
  String toString(){
  body
  }
  //now implement all 72 String methods
  char charAt(int index){
  return body.charAt(index)
  }
  //snip...
  //one method down, 71 more to go...
  }

  因此,AllCapsString 类拥有 一个 String,但是其行为 不同于 String,除非您映射了所有 72 个 String 方法。要查看需要添加的方法,可以参考 Javadocs 中有关 String 的内容,或者运行清单 4 中的代码:

  清单 4. 输出 String 类的所有方法

 


 String.class.methods.eachWithIndex{method, i->
  println "${i} ${method}"
  }
  //output
  0 public boolean java.lang.String.contentEquals(java.lang.CharSequence)
  1 public boolean java.lang.String.contentEquals(java.lang.StringBuffer)
  2 public boolean java.lang.String.contains(java.lang.CharSequence)
  ...

  将 72 个 String 方法手动添加到 AllCapsString 并不是一种明智的方法,而是在浪费开发人员的宝贵时间。这就是 @Delegate 注释发挥作用的时候了

上一篇:编程技巧:JAVA连接数据库的代码 下一篇:启动Java应用的Shell脚本的方法

评论总数:0 [ 查看全部 ] 网友评论


关于我们隐私版权广告服务友情链接联系我们网站地图