首页 > 解决方案 > “即时”创建一个新课程?

问题描述

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

在 Java 中你不能这样做……但在动态语言(例如 Python)中你通常可以。

在 Eclipse中尝试在givenSpock 功能块(即测试方法)中执行类似操作:

Groovy:此处不需要类定义。请在适当的位置定义类,或者尝试使用块/闭包。

...一个“适当”的地方显然会在功能之外。这将是笨重的,而不是时髦的。使用 Groovy 几个月后,我对 Groovy 何时应该提供更 groovy 的东西有了感觉。

所以说我想扩展我的abstractAbstractFoo并创建一个新的子类Foo,在我的功能中,有没有办法“使用块/闭包”来实现类似的东西?

标签: groovyclosuressubclass

解决方案


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()

和实现foo1,它们提供不同的方法实现,导致不同的方法行为。运行这个 Groovy 脚本会在控制台产生以下输出:foo2AbstractFootext()bar()

Hello, world!
Lorem ipsum dolor sit amet

它不是特定于 Groovy 的,您可以使用 Java 实现完全相同的行为。但是,您可以通过将闭包强制转换为类来使其更加“groovier” AbstractFoo,如下所示:

def foo3 = { "test 123" } as AbstractFoo
foo3.bar()

在这种情况下,返回“test 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()

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

text: test 1, number: 23

在 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()

在这里,我们定义了一个名为的非匿名类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  {

    }
}

推荐阅读