6

在 Groovy 中转换对象的约定似乎是使用asoperator 和 override 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

但是,GrailsasType()在运行时覆盖了所有对象的实现,以便它可以支持像render as JSON.

另一种方法是在 Grails Bootstrap 类中重写asType()如下:

def init = { servletContext ->
    Id.metaClass.asType = { Class type ->
        if (type == FormattedId) {
                return new FormattedId(value: value.toUpperCase())
        }
    }
}

但是,这会导致代码重复 (DRY),因为您现在需要在 BootstrapId 类中重复上述操作,否则as FormattedId将无法在 Grails 容器之外工作。

在 Groovy/Grails 中编写不会破坏良好代码/OO 设计原则(如 Single Responsibility Principal 或 DRY)的转换代码有哪些替代方法?Mixins 在这里有用吗?

4

2 回答 2

1

您可以使用 Grails 对Codecs的支持来自动将encodeAs*函数添加到您的 Grails 原型中:

class FormattedIdCodec {

    static encode = { target ->
        new FormattedId((target as String).toUpperCase()
    }

}

然后,您可以在代码中使用以下内容:

def formattedId = new Id(value: "test").encodeAsFormattedId
于 2013-01-10T17:43:27.173 回答
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 中设置它。

于 2013-05-01T19:57:26.087 回答