在 Groovy 中克隆和扩展 class

Cloning and extending class in Groovy

我正在尝试在 Groovy 中动态生成 classes。我的做法是:

class MetaClassTest {

    static class TestClass {

        String getName() {
            return "Jake"
        }
    }

    public static void main(String[] args) {
        def testClass = TestClass
        def metaMethod = testClass.metaClass.getMetaMethod('getName', [] as Class[])
        testClass.metaClass.getName = {
            metaMethod.invoke(delegate) + " and the Fatman"
        }
        assert testClass.newInstance().name == "Jake and the Fatman"
    }
}

然而,这改变了原始 class 的行为,这是我不想要的。所以我的问题是:

如何动态克隆(并可能重命名)现有的 class 以便我能够创建多个派生对象?

我不确定以下是否有效,但可能值得一试:你能检查一下你是否能以某种方式深度复制 TestClass,然后修改唯一的克隆 class?以下内容可能会派上用场:

使用autoclone

也许 groovy lang metaprogramming 可以查找有关元编程的更多信息。

您可以覆盖 class 个实例方法:

import groovy.transform.AutoClone

@AutoClone
class TestClass {
   String getName() {
      return "Jake"
   }
}

def tc1 = new TestClass()
def tc2 = tc1.clone()
tc1.metaClass.getName = {'Fatman'}
tc2.metaClass.getName = {'Joe'}
assert tc1.getName() == 'Fatman'
assert tc2.getName() == 'Joe'
assert new TestClass().getName() == 'Jake'

到目前为止最透明(尽管仍然很脏)的解决方案已经在这里暗示了。我可以使用 GroovyClassLoader.parse() 方法创建子 class 骨架,然后通过 metaClass.

丰富它
class TestClass {

    String getName() {
        return "Jake"
    }
}

def parentClass = TestClass
def groovyClassLoader = new GroovyClassLoader(parentClass.classLoader)

def childClass1 = groovyClassLoader.parseClass("class ChildClass1 extends ${ parentClass.canonicalName } {}")
def oldGetName1 = childClass1.metaClass.getMetaMethod('getName', [] as Class[])
childClass1.metaClass.getName = {
    oldGetName1.invoke(delegate) + " and the Fatman"
}

def childClass2 = groovyClassLoader.parseClass("class ChildClass2 extends ${ parentClass.canonicalName } {}")
def oldGetName2 = childClass2.metaClass.getMetaMethod('getName', [] as Class[])
childClass2.metaClass.getName = {
    oldGetName2.invoke(delegate) + " the Dog"
}

assert childClass1.newInstance().name == "Jake and the Fatman"
assert childClass2.newInstance().name == "Jake the Dog"

我在运行时动态创建 classes 的原因是可以使用 Groovy 通常几乎没有任何编程技能的人编写的 DSL 脚本来扩展应用程序。