Extending/Subclassing 超越直接 child 的构建器

Extending/Subclassing a Builder beyond a direct child

我有三个classes

abstract class Animal {...}
class Shark extends Animal {...}
class Hammerhead extends Shark {...}

每个 classes 都有一个静态内部 _Builder class。这些是标准构建器 classes,但它们相互扩展以允许在实例化时对 object 进行完整配置。例如构建器的使用可能类似于

Hammerhead.getBuilder().setColor(color.GREY).setFinSize(1.3f).setHammerSize(.9f).build();

return Hammerhead

的新实例

最初我有这个问题,上面的方法不起作用,因为例如 setColor() 会 return 一个 Animal.ABuilder 我不能随后调用 setFinSize() on(这是 Shark.Sbuilder 的方法)。

这已通过将 _Builder 变成泛型来补救,如

中所示

答案对于扩展一个 child 很有效,但我在扩展到一个 grandchild builder 时遇到了问题。

这里是 class 建造者的签名,因为我有
static class ABuilder<B extends ABuilder<B>>{...}
static class SBuilder<B extends SBuilder<B>> extends ABuilder<B extends ABuilder<B>>{...}
static class HBuilder<B extends HBuilder<B>> extends SBuilder<B extends SBuilder<B>>{...}

不幸的是,这给了我编译错误。

Type Parameter 'B' is not within it's bounds; should extend 'Animal.ABuilder'

此错误针对 SBuilder 定义中的第三个也是最后一个 B

有办法实现吗?

谢谢!

来源
Animal.java

package com.example;

public abstract class Animal {

    String color;

    public Animal(ABuilder builder){
        this.color = builder.color;
    }

    public static class ABuilder<B extends ABuilder<B>> {
        String color;
        public B setColor(String c){
            color = c;
            return (B)this;
        }
    }
}

Shark.java

package com.example;

public class Shark extends Animal {

    float fin_size;

    public Shark(SBuilder builder){
        super(builder);
        fin_size = builder.fins;
    }

    //                                                 Problems are in this general area: \/
    public static class SBuilder<B extends SBuilder<B>> extends ABuilder<B extends ABuilder<B>>{ 

        float fins;

        public B setFinSize(float size){
            this.fins = size;
            return (B) this;
        }

        public Shark build(){
            return new Shark(this);
        }
    }
}

Hammerhead.java

package com.example;

public class Hammerhead extends Shark {

    float hammer;

    public Hammerhead(HBuilder builder) {
        super(builder);
        hammer = builder.hammer;
    }

    public static HBuilder<? extends  HBuilder> getBuilder(){
        return new HBuilder<HBuilder>();
    }

      public static class HBuilder<B extends HBuilder<B>> extends SBuilder<B extends SBuilder<B>> { {

        float hammer;

        public B setHammerSize(float hammer) {
            this.hammer = hammer;
            return (B)this;
        }

        public Hammerhead build(){
            return new Hammerhead(this);
        }
    }
}

编辑

根据 Seelenvirtuose 的回答:

你的回答对我来说很有意义。我以为我已经解决了问题,但现在我已经进行了更改,它仍然没有按预期工作:

在第一次调用 setColor() 之后,returned 类型(由 Intellij IDEA 报告)就是 class 定义函数的类型。

每一行的注释都是return函数调用

编辑的类型
Hammerhead hh =
    Hammerhead.getBuilder() // HBuilder<? extends HBuilder> //
        .setColor("Black") // ? extends com.example.Hammerhead.HBuilder
        .setHammerSize(10f) // HBuilder
        .setFinSize(10f) // SBuilder
        .setColor("Fuschia") // ABuilder

        .setFinSize(10f) // Error: No such method on ABuilder

        .build(); // Also does not work because build()
                  // should be called on an HBuilder

编辑 2

解决方案有效。经过一番摸索之后,我意识到我的 getBuilder() 方法有第二个问题,这导致了进一步的问题。我会在回家后编辑以上内容以反映正确的功能和解决方案。

最终编辑

getBuilder 函数应该是

    public static HBuilder<? extends  HBuilder<?>> getBuilder(){
        return new HBuilder<>();
    }

那么,您的 Animal class 有以下生成器 class:

public static class ABuilder<B extends ABuilder<B>> { ... }

类型参数B的目的是将ABuilder的任何子类型绑定到这个类型变量。但是您没有在 subclasses.

中正确使用此子类型绑定

只需将您的鲨鱼生成器和锤头生成器更改为:

public static class SBuilder<B extends SBuilder<B>> extends ABuilder<B> { ... }

public static class HBuilder<B extends HBuilder<B>> extends SBuilder<B> { ... }

由于 B 已经在扩展 SBuilder(分别为 HBuilder),因此无需扩展 ABuilder<B>