java - 将 Builder 扩展/子类化到直接子级之外

标签 java generics polymorphism subclass builder

我有三门课

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

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

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

这将返回 Hammerhead 的新实例

最初我遇到了这个问题,上面的方法不起作用,因为例如 setColor()将返回一个 Animal.ABuilder 我无法随后调用 setFinSize() on (这是Shark.Sbuilder的一种方法)。

通过将_Builder变成泛型来解决这个问题,如 the answer to this question 中所示。

这个答案对于延长一个 child 来说效果很好,但我遇到的问题超出了孙子建筑商的范围。

这是我拥有的构建器的类签名
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'

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

有办法实现吗?

谢谢!

来源
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() 后返回的类型(由 Intellij IDEA 报告)就是定义该函数的任何类。

每行注释是函数调用返回的类型

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() 方法存在第二个问题,这导致了进一步的问题。当我回家时我会编辑上面的内容以反射(reflect)正确的功能和解决方案。

最终编辑

getBuilder功能应该是

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

最佳答案

好吧,你的Animal类具有以下构建器类:

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

类型参数的用途B是绑定(bind) ABuilder 的任何子类型到这个类型变量。但是您没有在子类中正确使用此子类型绑定(bind)。

只需将您的鲨鱼构建器和锤头构建器更改为:

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> 的内容。 .

关于java - 将 Builder 扩展/子类化到直接子级之外,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36029174/

相关文章:

java - JDBC 中的批量插入 - 单个事务会慢多少?

java - 如何在两个公共(public)函数之间建立牢固的前后关系

oop - UML 中的多态性和泛化

java - JPA/hibernate 按子类属性排序

c# - 通用继承和委托(delegate)

c# - 如何在 C# 中将实例变量视为另一种类型的实例

Java原始对象实例化: heap or not?

java - Spring Boot H2 db 显示没有记录

java - 具有多个继承类的通用返回类型的自引用方法

Java 泛型 : method is not applicable for the arguments (T)