快速创建一个新课程#34;?

时间:2018-06-09 07:43:29

标签: groovy closures subclass

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

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

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

  

Groovy:这里不期望类定义。请在上面定义班级   一个合适的地方或者尝试使用块/关闭。

..."合适的"地方显然不在特征之外。这将是笨重而不是时髦。使用Groovy几个月后,我感觉Groovy何时应该提供更多的东西。

所以说我想扩展我的abstractAbstractFoo并创建一个新的子类Foo,在我的功能中,是否有任何方法可以使用块/关闭"实现这样的目标?

1 个答案:

答案 0 :(得分: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()

foo1foo2都实现了AbstractFoo,它们提供text()方法的不同实现,从而导致不同的bar()方法行为。运行此Groovy脚本会向控制台生成以下输出:

Hello, world!
Lorem ipsum dolor sit amet

它不是Groovy特有的,你可以用Java实现完全相同的行为。但是你可以通过将一个闭包转换为AbstractFoo类来使它变得更加“groovier”,如下所示:

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  {

    }
}