在类级别应用类别

Dón*_*nal 5 groovy

如果我想在一小段代码中使用 Groovy 类别,我通常会这样做

def foo() {

  use(TimeCategory) {
    new Date() + 5.hours
  }
}
Run Code Online (Sandbox Code Playgroud)

但是,如果我想在同一个类的多个方法中使用一个类别,则必须use在每个方法中重复调用。

有没有办法在类级别应用类别?我尝试使用 Groovy 的@Mixin注释,如下所示:

import groovy.time.*

@Mixin(TimeCategory)
class Foo {

  Foo() {
    new Date() + 5.hours
  }
}

new Foo()
Run Code Online (Sandbox Code Playgroud)

但是如果你在 Groovy 控制台中执行上面的代码,你会得到一个异常:

groovy.lang.MissingPropertyException:没有这样的属性:类的小时:java.lang.Integer

Bal*_*Rog 0

您可以MetaClass.invokeMethod()事后使用。它有点难看,但它使类代码相对干净:

import groovy.time.*

class Foo {
  Foo() {
    try { println (new Date() + 5.hours) }
    catch (e) { println e }

    try { println afterHours(5) }
    catch (e) { println e }
  }

  Date tomorrow() {
    new Date() + 1.days
  }

  Date nextWeek() {
    new Date() + 7.days
  }

  Date afterHours(int h) {
    new Date() + h.hours
  }
}
Run Code Online (Sandbox Code Playgroud)

解决方案#1:将Foo.metaClass下游某处修改如下:

Foo.metaClass.invokeMethod = { String name, args ->
  def metaMethod = Foo.metaClass.getMetaMethod(name, args)
  def result
  use(TimeCategory) {
    result = metaMethod.invoke(delegate.delegate, args)
  }
  return result
}
Run Code Online (Sandbox Code Playgroud)

测试如下:

def foo = new Foo()
println "tomorrow: ${foo.tomorrow()}"
println "next week: ${foo.nextWeek()}"
println "after 7 hours: ${foo.afterHours(7)} "
Run Code Online (Sandbox Code Playgroud)

产生以下结果

groovy.lang.MissingPropertyException: No such property: hours for class: java.lang.Integer
groovy.lang.MissingPropertyException: No such property: hours for class: java.lang.Integer
tomorrow: Fri Oct 17 14:46:52 CDT 2014
next week: Thu Oct 23 14:46:52 CDT 2014
after 7 hours: Thu Oct 16 21:46:52 CDT 2014 
Run Code Online (Sandbox Code Playgroud)

所以它不能在构造函数中或通过构造函数工作,但它可以在其他地方工作。


如果您不介意全局更改 Integer 和 Date 的行为,那么您可以使用以下解决方案。

解决方案#2:

与之前相同的类,不修改Foo.metaClass,而是修改Integer.metaclassand ,Date.metaClass如下所示:

Integer.metaClass.mixin TimeCategory
Date.metaClass.mixin TimeCategory
Run Code Online (Sandbox Code Playgroud)

现在,与之前相同的测试会产生以下输出:

Thu Oct 16 21:19:24 CDT 2014
Thu Oct 16 21:19:24 CDT 2014
tomorrow: Fri Oct 17 16:19:24 CDT 2014
next week: Thu Oct 23 16:19:24 CDT 2014
after 7 hours: Thu Oct 16 23:19:24 CDT 2014 
Run Code Online (Sandbox Code Playgroud)