如何使我的Grails域类表现得像一个数字?
我有一堆Grails域类,我希望能够将它们视为如何使我的Grails域类表现得像一个数字?,grails,groovy,delegates,Grails,Groovy,Delegates,我有一堆Grails域类,我希望能够将它们视为Numbers,尤其是Integers。在大多数情况下,它们只是数值,带有一些用作元数据的额外属性。下面是一个例子: class Score { String meaning Integer value static hasMany = [responses:Response] static constraints = { meaning blank: false, maxSize: 100,
Number
s,尤其是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
}
}
我试图将@Delegate
添加到value
字段,但似乎没有任何效果:我仍然无法执行7+myScore
。我得到的只是缺少方法异常,因为Integer没有匹配的签名plus(Score)
既然@Delegate
似乎不起作用,那么正确的方法是什么
注意:我还需要使用元数据将我的域类转换为各种
集合
,但我希望这将是相同的解决方案。为编号
元类上的plus
操作符添加重载:
Number.metaClass.plus = { Score s -> delegate + s.value }
将其添加到应用程序的BootStrap.groovy中,或在插件的doWithDynamicMethods
中
编辑:
正如评论中所指出的,如果分数
在操作的左侧,则这不起作用。将plus
方法添加到Score
类中以处理该问题:
Number plus(Number n) { value + n }
您还可以扩展该号码
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
你的答案可以是。在这里,您将重载plus方法以使用整数和double进行操作:
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
现在这个问题已经有一年半的历史了,我想每个人都在继续前进,但我还是很惊讶没有人提供Groovy类别作为解决方案。事实上,在我看来,分类是解决这个问题最自然的方法。在不改变原始域类的“粒度”的情况下,您仍然可以相对容易地灌输所需的数值行为 首先定义类别类:
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())}
}
然后,在应用程序中某个适当的全局位置声明mixin:
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)
那么
15+新分数(值:4)
?使用.plus…}是否更好代码>而不是=
?您还需要在Score对象上重载“plus”以获取一个数字并正确响应。是的,新的分数(值:4)+5如何?叹气,没有评论的负数投票。我怎么知道答案出了什么问题?(并不是说什么都是:P)我不是落选的选民,但我本来可以。您已经删除了Score
的所有原始特性,这些特性是将其编译成Grails域类所需的。。。可以添加其他约束内容,而不会影响手头的问题。