如何在继承类中继承静态构建器/构造方法?

huangapple go评论62阅读模式
英文:

How to inherit static builder/constructor method in inherited class?

问题

    static T with(Closure<T> builder) {
        def clazz = T
        return with(clazz, builder)
    }
    
    static <T> T with(Class<T> clazz, Closure<T> builder) {
        T arg = clazz.getDeclaredConstructor().newInstance()
        
        builder.delegate = arg
        builder.resolveStrategy = Closure.DELEGATE_ONLY
        
        return builder(arg)
    }
英文:

I'm trying to implement a common interface for static constructers using a Groovy Closure. In it, the pattern I'm attempting to implement is:

abstract class WithBuilder&lt;T&gt; {
    static T with(Closure&lt;T&gt; builder) {
        Class&lt;T&gt; clazz = T;
        return with(clazz, builder);
    }
    
    static &lt;T&gt; T with(Class&lt;T&gt; clazz, Closure&lt;T&gt; builder) {
        T arg = clazz.getDeclaredConstructor().newInstance();
        
        builder.delegate = arg;
        builder.resolveStrategy = Closure.DELEGATE_ONLY;
        
        return builder(arg);
    }
}

As any experienced Java developer might note, the syntax Class&lt;T&gt; clazz = T isn't valid because T is a type signature and not an actual class definition. In the meantime, I've taken to putting an error there throw new Error(&#39;Not implemented&#39;); but in doing so I lose the common interface of the with method being a required implementation, and that any subclass of WithBuilder should return a new instance of the class.

Any tips on how to get this would be appreciated. I'm trying to build a fluent builder that would look like this in practice:

import pipeline.Configuration
import pipeline.Credentials
import pipeline.languages.SupportedLanguages

Configuration.with {
    language SupportedLanguages.Java
    credentials Credentials.get(&#39;user&#39;)
    environments {
        dev()
    }
}

Note: the above is not quite code, but it's the direction I'm aiming for how I want this to work. I'm still learning about Groovy Closures, so the above might not be valid, but I've been inspired by the Jenkins declarative syntax and so I'm aiming for something like that.

Edit #1

A helpful comment pointed out I was missing a clarification. They thought the missing type parameter on a static method was an accident, but it was somewhat intentional, though I forgot to call out that I know it won't work that way. The reason for it is I want the inherited class to be able to use it like this:

class MyClass extends WithBuilder&lt;&lt;MyClass&gt; {
    @Override
    static MyClass with(Closure&lt;MyClass&gt; builder) {
        return with(MyClass, builder);
    }
}

However, in my case, I get a warning that Method does not override method from its super class

答案1

得分: 1

在你的情况下,不需要使用继承。可以这样做:
英文:

In your case there is no need for inheritance. This would work:

class Helper {
    static &lt;T&gt; T with(Class&lt;T&gt; clazz, Closure&lt;?&gt; builder) {
        T arg = clazz.getDeclaredConstructor().newInstance();

        builder.delegate = arg;
        builder.resolveStrategy = Closure.DELEGATE_ONLY;
        builder(arg)

        return arg; // not builder call result, but delegate
    }
}

class MyClass {
    int a

    static MyClass with(@DelegatesTo(MyClass.class) Closure&lt;?&gt; builder) {
        return Helper.with(MyClass.class, builder);
    }

    @Override
    String toString() {
        return &quot;MyClass [a=$a]&quot;
    }
}

println MyClass.with {
    a = 1
}

And output:

MyClass [a=1]

答案2

得分: 1

我知道我没有回答问题。只是试图展示实现问题描述的目标的另一种方式。


Class类上声明元类方法的Groovy方式 - 因此,with方法将出现在任何Class引用上:

Class.metaClass.with={Closure builder->
    var arg = delegate.newInstance()
    builder.delegate = arg
    builder.resolveStrategy = Closure.DELEGATE_ONLY
    builder(arg)
    return arg
}

//用自定义类进行测试
class MyClass {
    int abc
}

assert 123 == MyClass.with{ 
    abc=123
}.abc

//用标准类进行测试
assert 'abc-123' == StringBuilder.with{
    it << 'abc' << '-' << 123
}.toString()

https://docs.groovy-lang.org/latest/html/documentation/core-metaprogramming.html#_metaclasses

英文:

i know that i'm not answering the question. just trying show alternative way to achieve the goal described in question.


groovy way to declare a metaclass method on a Class class - so, with method will appear on any Class ref:

Class.metaClass.with={Closure builder-&gt;
    var arg = delegate.newInstance()
    builder.delegate = arg
    builder.resolveStrategy = Closure.DELEGATE_ONLY
    builder(arg)
    return arg
}

//test with custom class
class MyClass {
    int abc
}

assert 123 == MyClass.with{ 
    abc=123
}.abc

//test with standard class
assert &#39;abc-123&#39; == StringBuilder.with{
    it &lt;&lt; &#39;abc&#39; &lt;&lt; &#39;-&#39; &lt;&lt; 123
}.toString()

https://docs.groovy-lang.org/latest/html/documentation/core-metaprogramming.html#_metaclasses

huangapple
  • 本文由 发表于 2023年3月7日 22:59:16
  • 转载请务必保留本文链接:https://go.coder-hub.com/75663626.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定