Groovy missingMethod

时间:2013-09-11 02:08:24

标签: groovy

我正在尝试按照文档动态地向我的Groovy类添加一个新方法。 所以这是我的类实现methodMissing方法:

class AlexTest {

    def methodMissing(String name, args){
        println "Method missing is called"

        def cachedMethod = { Object[] varArgs ->
            println "Hi! ${varArgs}"
        }

        AlexTest.metaClass."${name}" = cachedMethod
        return cachedMethod(args)
    }
}

这是另一个使用我的AlexTest类的groovy脚本:

def alexTest = new AlexTest()
alexTest.hi("Alex")
alexTest.hi("John")

我希望只调用一次“方法缺失被调用” - 因为方法“hi”将在methodMissing中被“引入”。但是,该方法被调用两次,就好像“hi”方法永远不会被引入AlexTest类。

我也尝试过不同的方式:

class AlexTest {

    AlexTest() {
        def mc = new ExpandoMetaClass(AlexTest, false, true)
        mc.initialize()
        this.metaClass = mc
    }

    def methodMissing(String name, args){
        println "Method missing is called"

        def cachedMethod = { Object[] varArgs ->
            println "Hi! ${varArgs}"
        }

        // note that this is calling metaClass inside the instance
        this.metaClass."${name}" = cachedMethod
        return cachedMethod(args)
    }
}

哪种工作,但仅适用于该单个实例。因此,如果我创建两个AlexTest实例,并调用'hi'方法,我将得到两个“Method missing is called”消息。 有人能指出我解释这种行为的文件吗?

提前致谢!

此致

亚历

3 个答案:

答案 0 :(得分:1)

在第一次尝试开始时添加以下内容:

ExpandoMetaClass.enableGlobally()

它适用于V 2.0.1

如果您希望在基于类实例的基础上启用,this post说明了一种方法:

class AlexTest {
    AlexTest() {
        def mc = new ExpandoMetaClass(AlexTest, false, true)
        mc.initialize()
        this.metaClass = mc        
    }

    def methodMissing(String name, args){
        println "Method missing is called"

        def cachedMethod = { Object[] varArgs ->
            println "Hi! ${varArgs}"
        }

        this.metaClass."${name}" = cachedMethod
        return cachedMethod(args)
    }
}

def alexTest = new AlexTest()
alexTest.hi("Alex")
alexTest.hi("John")

答案 1 :(得分:0)

脚本中的这个怎么样?这样可以确保为Class引用实现methodMissing,并将其应用于引用它的所有实例。

class AlexTest {

}

mc = AlexTest.metaClass
mc.methodMissing = {String name, args=[:] ->
        println "Method missing is called"
        def cachedMethod = { Object[] varArgs ->
            println "Hi! ${varArgs}"
        }
        mc."${name}" = cachedMethod
        cachedMethod(args)
}

def alexTest = new AlexTest()
alexTest.hi("Alex")
alexTest.hi("John")

def myTest = new AlexTest()
myTest.hi("Walter")
myTest.hi("Hank")

//Prints
Method missing is called
Hi! [Alex]
Hi! [John]
Hi! [Walter]
Hi! [Hank]

虽然全球启用ExpandoMetaClass也可以带来额外的内存成本。 :)

答案 2 :(得分:0)

另一种解决方案是在 Map 中缓存方法闭包。

class AlexTest {
    static Map methods = [:]

    def methodMissing(String name, args){
        if (!methods[name]) {
            println "Method is not cached"
            methods[name] = { Object[] varArgs ->
                println "Hi! ${varArgs}"
            }
        }
        return methods[name](args)
    }
}

def alexTest = new AlexTest()
alexTest.hi("Alex")
alexTest.hi("John")

输出

Method is not cached
Hi! [Alex]
Hi! [John]