创建一个新的类“动态”?

mik*_*ent 2 groovy closures subclass

...特别是在Groovy中(因此标记)?

在Java中,您无法执行此操作...但是在动态语言(例如Python)中,您通常可以执行此操作。

given在Eclipse中尝试执行Spock功能块(即测试方法)中的操作的尝试:

Groovy:此处不期望类定义。请在适当的地方定义课程,或者尝试使用块/关闭。

...一个“合适的”地方显然不在功能范围之内。这将是笨拙而不是笨拙的。在使用Groovy几个月后,我感觉到Groovy应该何时提供groovier。

因此,说我想扩展我的abstractAbstractFoo并创建一个新的子类Foo,在我的功能中,有什么方法可以“使用块/关闭”来实现类似的功能?

Szy*_*iak 5

您可以通过实例化AbstractFoo并提供抽象方法的内联实现来简单地创建一个匿名类。考虑以下示例:

abstract class AbstractFoo {
    void bar() {
        println text()
    }

    abstract String text()
}

def foo1 = new AbstractFoo() {
    @Override
    String text() {
        return "Hello, world!"
    }
}

def foo2 = new AbstractFoo() {
    @Override
    String text() {
        return "Lorem ipsum dolor sit amet"
    }
}

foo1.bar()
foo2.bar()
Run Code Online (Sandbox Code Playgroud)

无论foo1foo2实施AbstractFoo,他们提供了不同的实现text()方法导致不同的bar()方法行为。运行此Groovy脚本将向控制台产生以下输出:

Hello, world!
Lorem ipsum dolor sit amet
Run Code Online (Sandbox Code Playgroud)

这与Groovy无关,您可以使用Java实现完全相同的行为。但是,您可以通过将闭包强制转换为AbstractFoo类来使其更加“时髦” :

def foo3 = { "test 123" } as AbstractFoo
foo3.bar()
Run Code Online (Sandbox Code Playgroud)

在这种情况下,返回“测试123”的闭包为抽象text()方法提供了一种实现。如果您的抽象类只有一个抽象方法,则它的工作原理如下。

具有多种抽象方法的抽象类

但是,如果一个抽象类有多个我们要动态实现的抽象方法,会发生什么呢?在这种情况下,我们可以将这种方法的实现作为映射提供,其中键是抽象方法的名称,值是提供实现的闭包。让我们看下面的例子:

abstract class AbstractFoo {
    abstract String text()
    abstract int number()
    void bar() {
        println "text: ${text()}, number: ${number()}"
    }
}

def foo = [
    text: { "test 1" },
    number: { 23 }
] as AbstractFoo

foo.bar()
Run Code Online (Sandbox Code Playgroud)

本示例使用具有两个抽象方法的抽象类。我们可以通过将类型映射Map<String, Closure<?>>AbstractFoo类来实例化该类。运行此示例将向控制台生成以下输出:

text: test 1, number: 23
Run Code Online (Sandbox Code Playgroud)

在Groovy中动态创建非匿名类

Groovy还允许您使用GroovyClassLoader.parseClass(input)方法从多行字符串创建类。让我们看下面的例子:

abstract class AbstractFoo {
    void bar() {
        println text()
    }

    abstract String text()
}

def newClassDefinitionAsString = '''
class Foo extends AbstractFoo {
    String text() {
        return "test"
    }
}
'''

def clazz = new GroovyClassLoader(getClass().getClassLoader()).parseClass(newClassDefinitionAsString)

def foo = ((AbstractFoo) clazz.newInstance())

foo.bar()
Run Code Online (Sandbox Code Playgroud)

在这里,我们定义了一个非匿名类Foo,该类可以扩展AbstractFoo并提供test()方法的定义。这种方法很容易出错,因为您将新类定义为String,所以在捕获错误和警告时,请不要考虑任何IDE支持。

在测试规范中提供子类

您最初提出的问题是有关在given:Spock块中尝试为规范创建类的尝试。我强烈建议使用最简单的可用工具-创建一个嵌套的私有静态类,这样您就可以在测试中轻松访问它,并且不会在测试之外公开它。像这样:

class MySpec extends Specification {

    def "should do something"() {
        given:
        Class<?> clazz = Foo.class

        when:
        //....

        then:
        ///....
    }

    private static class Foo extends AbstractFoo  {

    }
}
Run Code Online (Sandbox Code Playgroud)