在编写转换代码时,覆盖asType()的替代方法是什么?

时间:2013-01-09 17:59:38

标签: grails groovy

在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在这里有用吗?

2 个答案:

答案 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中设置它。