惯用MetaProgramming

时间:2010-12-07 19:49:34

标签: design-patterns groovy reference metaprogramming

虽然网络上充斥着资源,颂扬了Groovy无数的元编程功能,但我还没有找到任何与实际使用这些功能的全面“最佳实践”指南相近的内容。

除了过度使用的典型警告经纪人警告之外,我读过的最具体的建议建议在可能的情况下使用类别来支持扩展元类(这实际上只是另一种强化方式) “有限范围”的旧习语。)

对于我的琐碎项目来说,常识已经足够了,但是当我处理更多雄心勃勃的任务时,我越来越关注从可能很差/不一致的先例构建。

因此,我非常感谢Groovy的任何建议,资源或具体示例(甚至是与语言无关 - 我对Ruby的简短经验让我同样想要)元编程最佳实践。

为了澄清这个主题,我将提供一个(高度)简化的Rational数字项目,该项目可以通过几种不同的方式使用元编程:

@Immutable class Rational{
    int num, den

    Rational multiply(Integer v){
        new Rational(num:num*v, den:den)
    }
}
assert new Rational(num:1, den:2) * 3 == new Rational(num:3, den:2)

然而,尝试3*new Rational(num:1, den:2)显然会产生MissingMethodException。

添加通信属性的最简单且可以说最脆弱的方法是使用Rational类中的静态初始化块:

static {
    Integer.metaClass.multiply = {Rational fraction -> fraction*delegate}
}
...
assert 3*new Rational(num:1, den:2) == new Rational(num:3, den:2)

但这是全球性的,而且非常严格。

更通用,也许更有条理的方法是使用某种可选的引导:

class BootStrap{
    static void initialize(){
        Integer.metaClass.multiply = {Rational fraction -> fraction*delegate}
    }
}

现在我们可以选择启用我们希望拥有的功能。但是,这可能导致各种依赖性问题。

然后是类别..安全明确,但不太方便:

@Category(Integer) class RationalCategory{
    Rational multiply(Rational frac){
        frac*this
    }
}
use(RationalCategory){
    assert 3*new Rational(num:1, den:2) == new Rational(num:3, den:2)
}

一般情况下,当我添加新行为时,我发现我修改了元类,但在更改现有行为时使用类别。例如,覆盖除法运算符以生成分数最好包含在类别中。因此,解决方案1或2将是“可接受的”,因为我只是将行为附加到Integer类,而不是改变典型用法。

有没有人同意/不同意这种观点?或者也许知道一些优秀的方法? (我在这里省略了mixins,我意识到了。)

1 个答案:

答案 0 :(得分:1)

在Groovy in Action中有一章关于元编程,其中很好地介绍了这个主题。请务必获得第二版(印刷版尚未提供,但您可以获得电子格式的早期版本),因为第一版非常过时,特别是关于元编程的主题。