【问题标题】:Runtime delegation in groovygroovy 中的运行时委托
【发布时间】:2017-09-26 10:51:21
【问题描述】:

我正在尝试为我自己的项目找出一些东西,所以我做了这个例子来更好地解释它。 Thing 类有一个名为 overrides 的委托 Typeoverrides 中的方法应在以下情况下调用:

  • 方法在overrides中声明
  • 该方法在overrides 中声明,但不在`this 中

this 中的方法应在以下情况下调用:

  • 该方法未在overrides 中声明
  • 方法继承自Object,GroovyObject
  • 方法丢失(missingMethod)

我考虑过使用@Delegate,但我需要在运行时更改覆盖。这是代码。

class Thing implements GroovyInterceptable {
    Type overrides = new BigThing()

    Object invokeMethod(String name, Object args) {
        MetaMethod thingMethod = metaClass.getMetaMethod('findDeclaredMethod', [this, name, args] as Object[])
        .invoke(this, name, args)
        MetaMethod overrideMethod = findDeclaredMethod(overrides, name, args)
        if(overrideMethod) {
            overrideMethod.invoke(overrides, args)
            //maybe invoke missingMethod on overrides catch MissingMethodException and call thingMethod
        } else if(thingMethod) {
            thingMethod.invoke(this, args)
        } else {
            this.metaClass.invokeMissingMethod(this, name, args)
        }
    }

    MetaMethod findDeclaredMethod(Object obj, String name, Object args) {
        MetaMethod m = this.metaClass.getMetaMethod(name, args)
        if(m && m.declaringClass.theClass != Thing.getClass()) {
            m = null
        }
        return m
    }

    String method1() {
        return "from Thing method1() ${makeString()}"
    }
    String method2() {
        return "from Thing method2() ${makeString()}"
    }
}

interface Type {
    String makeString()
}

class BigThing implements Type {
    String makeString() {
        return "makeString()"
    }

    String method2() {
        return "from BigThing method2() ${makeString()}"
    }
}

assert 'from Thing method1() makeString()' == new Thing().method1()
assert 'from BigThing method2() makeString()' == new Thing().method2()
new Thing().with {
    assert 'from Thing method1() makeString()' == method1()
    assert 'from BigThing method2() makeString()' == method2()
}

注意:这目前不起作用,但我认为它很好地解释了这个想法。

在 groovy 中是否已经建立了这样的模式?

更新:

有了这个,我就成功了。在 with 闭包中调用 method2() 失败。

class Thing implements GroovyInterceptable {
    Type overrides = new BigThing()

    Object invokeMethod(String name, Object args) {
        MetaMethod method = overrides.metaClass.getMetaMethod(name, args)
        if(method != null) {
            System.out.println("$method.name class is $method.declaringClass.theClass")
            System.out.println("$method.declaringClass.theClass interfaces contains Type or is type ${method.declaringClass.theClass == Type || method.declaringClass.theClass.interfaces.contains(Type)}")
        }
        if (method != null && (method.declaringClass.theClass == Type || method.declaringClass.theClass.interfaces.contains(Type))) {
            return method.invoke(overrides, args)
        }

        method = this.metaClass.getMetaMethod(name, args)
        if (method != null) {
            return method.invoke(this, args)
        }

        return this.metaClass.invokeMissingMethod(this, name, args)
    }

    String method1() {
        return "from Thing method1() ${makeString()}"
    }
    String method2() {
        return "from Thing method2() ${makeString()}"
    }
}

interface Type {
    String makeString()
}

class BigThing implements Type {
    String makeString() {
        return "makeString()"
    }

    String method2() {
        return "from BigThing method2() ${makeString()}"
    }
}

assert 'from Thing method1() makeString()' == new Thing().method1()
assert 'from BigThing method2() makeString()' == new Thing().method2()
new Thing().with {
    assert 'from Thing method1() makeString()' == method1()
    assert 'from BigThing method2() makeString()' == method2()
}

【问题讨论】:

    标签: groovy


    【解决方案1】:

    尝试简化GroovyObject.invokeMethod(String name, Object args) 方法的实现。您可以通过以下方式实现该方法来实现这一点:

    • 首先检查overrides 是否有该名称的方法,如果存在则调用它
    • 检查当前对象是否有同名的方法并调用它
    • 否则调用invokeMissingMethod

    我检查了以下实现,它运行良好:

    class Thing implements GroovyInterceptable {
        Type overrides = new BigThing()
    
        Object invokeMethod(String name, Object args) {
            MetaMethod method = overrides.metaClass.getMetaMethod(name, args)
            if (method != null) {
                return method.invoke(overrides, args)
            }
    
            method = this.metaClass.getMetaMethod(name, args)
            if (method != null) {
                return method.invoke(this, args)
            }
    
            return this.metaClass.invokeMissingMethod(this, name, args)
        }
    
        String method1() {
            return "from Thing method1() ${makeString()}"
        }
        String method2() {
            return "from Thing method2() ${makeString()}"
        }
    }
    
    interface Type {
        String makeString()
    }
    
    class BigThing implements Type {
        String makeString() {
            return "makeString()"
        }
    
        String method2() {
            return "from BigThing method2() ${makeString()}"
        }
    }
    
    assert 'from Thing method1() makeString()' == new Thing().method1()
    assert 'from BigThing method2() makeString()' == new Thing().method2()
    

    希望对你有帮助。

    【讨论】:

    • 感谢您的帮助。我回家后一定要试试。我担心的一件事是 GroovyObject 方法。我经常使用.with {}。任何这些方法都应该使用this。我认为检查声明类将有助于防止在 overrides 上调用这些方法。
    • @JohnMercier 你能给我们一个使用.with {}闭包的例子吗?我也很想测试它:)
    • 我已更新问题以包含示例和更多信息。
    猜你喜欢
    • 1970-01-01
    • 2011-10-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-10-07
    • 2018-10-29
    • 2019-10-08
    • 1970-01-01
    相关资源
    最近更新 更多