在Groovy中转换对象的惯例似乎是使用as
运算符并覆盖asType()
。例如:
class Id {
def value
@Override
public Object asType(Class type) {
if (type == FormattedId) {
return new FormattedId(value: value.toUpperCase())
}
}
}
def formattedId = new Id(value: "test") as FormattedId
但是,Grails在运行时覆盖了所有对象的asType()
实现,以便它可以支持render as JSON
等习语。
另一种方法是在Grails Bootstrap类中重写asType()
,如下所示:
def init = { servletContext ->
Id.metaClass.asType = { Class type ->
if (type == FormattedId) {
return new FormattedId(value: value.toUpperCase())
}
}
}
然而,这会导致代码重复(DRY),因为您现在需要在引导程序和 Id类中重复上述操作,否则as FormattedId
将无法在Grails容器外工作
在Groovy / Grails中编写转换代码还有哪些替代方法可以破坏良好的代码/ OO设计原则,如Single Responsibility Principal或DRY? Mixins在这里有用吗?
答案 0 :(得分:1)
您可以使用Codecs的Grails支持自动将encodeAs*
函数添加到Grails原型中:
class FormattedIdCodec {
static encode = { target ->
new FormattedId((target as String).toUpperCase()
}
}
然后您可以在代码中使用以下内容:
def formattedId = new Id(value: "test").encodeAsFormattedId
答案 1 :(得分:0)
我不优雅的解决方案是重命名原始的asType(),并创建一个新的asType()来调用它,并通过调用该方法使你的BootStrap覆盖astType:
所以,你的班级:
class Id {
def value
@Override
public Object asType(Class type) {
return oldAsType(type);
}
public Object oldAsType(Class type) {
if (type == FormattedId) {
return new FormattedId(value: value.toUpperCase())
}
}
}
在我的应用程序中,我在许多类中定义了asType,因此我最终在BootStrap.groovy中使用了一个公共闭包:
def useOldAsType = {Class clazz ->
delegate.oldAsType(clazz)
}
Id.metaClass.asType = useOldAsType;
Value.metaClass.asType = useOldAsType;
OtherClass.metaClass.asType = useOldAsType;
SubclassOfValue.metaClass.asType = useOldAsType;
请注意,如果您的子类不覆盖asType,但您希望它使用超类,则还必须在BootStrap中设置它。