0

我有一堆 Grails 域类,我希望能够将它们视为Numbers,Integer尤其是 s。在大多数情况下,它们只是带有一些额外属性的数值,用作元数据。这是一个例子:

class Score {

    String meaning

    Integer value

    static hasMany = [responses:Response]

    static constraints = {
        meaning blank: false, maxSize: 100, unique: true
        value min: 1, unique: true // Assume we're using a base-1 ranking system, where 1 is the lowest
    }
}

我试图添加@Delegatevalue字段中,但它似乎没有任何影响:我仍然无法做到7 + myScore。我得到的只是缺少方法异常,因为 Integer 没有签名匹配plus(Score)

这样做的正确方法是什么,因为@Delegate似乎不起作用?

注意:我还需要将我的域类变成Collection带有元数据的各种 s,但我希望它会是相同的解决方案。

4

4 回答 4

1

我想象每个人都继续前进,现在这个问题已经存在一年半了,但我仍然很惊讶没有人提供 Groovy 类别作为解决方案。事实上,在我看来,类别是解决这个问题的最自然的方法。在不更改原始域类的“Grailsiness”的情况下,您仍然可以相对容易地灌输所需的数字行为。

首先定义类别类:

class ScoreCategory {
    static asType(Score s, Class newClass) {
        switch (newClass) {
            case Integer.class:
            case Integer.TYPE: 
            case Number.class: return s?.value ?: 0
            default: throw new GroovyCastException("Cannot cast to ${newClass}")
        }
    }

    static boolean equals(Score me, def you) {
        you instanceof Score && me as int == you as int
    }

    static Score plus(Score a, b) { plusImpl(a, b) }
    static Score plus(Score a, Number b) { plusImpl(a, b) }
    static Score plus(Number a, Score b) { plusImpl(a, b) }
    private static plusImpl(a, b) { new Score(value: (a as int) + (b as int)) }

    static Score minus(Score a, b) { minusImpl(a, b) }
    static Score minus(Score a, Number b) { minusImpl(a, b) }
    static Score minus(Number a, Score b) { minusImpl(a, b) }
    private static minusImpl(a, b) { a + -b }

    static Score multiply(Score a, Number b) { multImpl(a,b) }
    static Score multiply(Number a, Score b) { multImpl(a,b) }
    private static multImpl(a,b) { new Score(value: (a as int) * (b as int)) }

    static Integer div(Score a, b) { (a as int).intdiv(b as int) }
    static Score div(Score a, Number b) { new Score(value:(a as int).intdiv(b as int)) }

    static Score negative(Score a) { new Score(value: -(a as int)) }
    static Score abs(Score a) { new Score(value: (a as int).abs())}
}

然后,在应用程序中某个适当的全局位置声明 mixins:

Number.metaClass.mixin ScoreCategory
Score.metaClass.mixin ScoreCategory

毕竟,如下所示,Score对象现在应该表现得像数字量:

def (w, x, y, z) = [54, 78, 21, 32]
def (s1, s2) = [new Score(value:w), new Score(value:x)]

assert (s1 + s2) == new Score(value: w + x)
assert (s1 + y) == new Score(value: w + y)
assert (z + s2) == new Score(value: z + x)
assert (s1 - s2) == new Score(value: w - x)
assert (s1 - y) == new Score(value: w - y)
assert (z - s2) == new Score(value: z - x)
assert (s1 * y) == new Score(value: w * y)
assert (z * s2) == new Score(value: z * x)
assert (s2 / s1) == x.intdiv(w)
assert (s1 / y) == new Score(value: w / y)
于 2014-10-19T05:12:09.937 回答
0

plus为元类上的运算符添加重载Number

Number.metaClass.plus = { Score s -> delegate + s.value }

doWithDynamicMethods在您的应用程序或插件中的 BootStrap.groovy 中添加它。

编辑:

Score正如评论中所指出的,如果位于操作的左侧,这将不起作用。向类添加一个plus方法Score来处理它:

Number plus(Number n) { value + n }
于 2013-01-27T21:31:05.717 回答
0

您的回答可能是运算符重载。在这里,您将重载 plus 方法以使用整数和双精度数进行操作:

class Score {
    ...
    int plus(int otherValue){
        return otherValue + value
    }

    double plus(double otherValue){
        return (value as double) + otherValue
    }

    // And you can avoid my pitfall overriding asType method
    Object asType(Class clazz) {
        if (clazz == Integer) {
            return value         
        }
        else if(class == Double){
            return value as Double
        }         
        else {             
            super.asType(clazz)         
        }     
    }    

}

assert new Score(value: 4) + 15 == 19
assert new Score(value: 4) + 15.32 == 19.32
assert 15.32 + (new Score(value: 4) as Double) == 19.32
assert 15 + (new Score(value: 4) as Integer) == 19
于 2013-01-28T03:46:05.290 回答
-1

You can also extend Number.

class Score extends Number {
   Integer value

   public int intValue() { return value }
   public double doubleValue() { return value }
   public long longValue() { return value }
   public float floatValue() { return value }
}

Score sc = new Score( value: 5 );

println 10 + sc
于 2013-01-27T23:42:45.923 回答