使用 groovy 类别添加动态属性

Posted

技术标签:

【中文标题】使用 groovy 类别添加动态属性【英文标题】:Use groovy categories to add dynamic properties 【发布时间】:2013-02-12 05:42:30 【问题描述】:

在this blog post 上进行扩展,我正在尝试使用一个类别来创建一个简单的 DSL,以便与javax.measure (JSR-275) 类一起使用(类似于 TimeCategory 的时间间隔)

但是,我不想为每个可能的可用方法(getMeter、getMilliMeter、getKelvin、getSecond 等)添加样板代码。我认为覆盖 getProperty(String) 方法会起作用,但是,在直接访问属性时,似乎没有使用类别中定义的 getProperty 方法。

这里有一些简化的代码来演示: 导入 javax.measure.quantity.Length; 导入 javax.measure.unit.Unit; 导入 javax.measure.Measure;

@Category(Number)
class LengthCategory       
    public Measure<BigDecimal, Length> getProperty(String unit)
        return Measure.valueOf(this,Unit.valueOf(unit));
    


use(LengthCategory)
    println 3.getProperty("m")  // this works
    println 3.m                 // this reports a non-exisiting property
    prinlln 3.'m'               // as does this

假设其他动态添加属性到运行时对象的方法(例如Expando、子类化GroovyInterceptible、mixins 和其他元类操作)是不可行的,我真的宁愿不必为每个可能的单元手动编写getter 和SI 前缀组合。显然还有其他方法可以创建用于测量的 DSL,但我仍然想了解为什么这种方法不起作用。

有人可以解释为什么该类别的getProperty 方法不会覆盖.propertyName 的用法吗?我显然错过了在运行时使用元类解析属性名称的重要内容。

【问题讨论】:

【参考方案1】:

我不知道为什么getProperty 不适用于类别。但是您可以在它们上定义一个基本相同的get 方法(我认为)。这有效:

@Category(Number)
class LengthCategory       
    def get(String unit) 
        "$this $unit"
    


use (LengthCategory) 
    println 3.m   // 3 m
    println 3.'m' // 3 m

【讨论】:

谢谢,这正是我想要的,但我仍然想知道为什么在类别中实现 getProperty(String name) 不起作用。【参考方案2】:

据我所知,您实际上不能使用 Category 来扩展具有完整(即可读和可写)属性的整数——只能使用方法。

您可以通过使用属性的方法版本来使用只读属性扩展 Integer。您甚至可以通过包含 set 方法使其可写。但是,似乎没有办法将传入的值存储在静态变量中,这最终会影响所有整数。

例子:

$ cat catprop
#!/usr/local/bin/groovy

@Category(Integer)
class CatInteger 
  private static String str = "default"
  public static String setN(Integer i, String _str)  str = _str 
  public static String getN(Integer i)  return str 


use (CatInteger) 
  3.n = "333a"
  println "3.n is " + 3.n

  3.n = "333b"
  println "3.n is " + 3.n

  4.n = "444"
  println "4.n is " + 4.n
  println "3.n is " + 3.n

$ catprop
3.n is 333a
3.n is 333b
4.n is 444
3.n is 444
$

请注意,在最后一行 3.n 中返回“444”,因为存储的字段是静态的。我想可以使用私有 HashMap 并为每个访问的 Integer 存储一个值,但这太丑了,无法考虑。

另一种可能性是使用 MetaClass 接口的 getProperty() 和 setProperty()。但是,我还没有研究过,所以我不知道它是否可行(只是一个想法)。

【讨论】:

【参考方案3】:

不错的答案,但不确定,既然 JSR-363 已经是最终版本,您是否仍想使用 JSR-275?;-)

【讨论】:

好点,但这是一个相当古老的问题。最初询问时,新的 JSR 帽子尚未获得批准。 没错。它指的是最新的示例/答案,不知道为什么它最终会出现在它上面?我们确实在github.com/unitsofmeasurement/uom-spaces/tree/master/… 下提供了对 JSR 363 的 Groovy 支持。与之前为 JSR 354 (JavaMoney) 所做的类似。

以上是关于使用 groovy 类别添加动态属性的主要内容,如果未能解决你的问题,请参考以下文章

iOS类别(category)不能添加成员变量但是可以添加属性的问题

通过runtime对类别进行属性的扩展

WithIndex Groovy类别

Magento - 按属性分类产品

何时向托管对象添加类别以及何时使用瞬态属性?

在类的所有实例方法中隐式使用 Groovy Category