【问题标题】:Extending/Subclassing a Builder beyond a direct child将 Builder 扩展/子类化超出直接子级
【发布时间】:2016-03-17 09:54:43
【问题描述】:

我有三门课

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(这是一个 Animal.ABuilder em>Shark.Sbuilder).

the answer to this question

所示,通过将 _Builder 转换为泛型来解决此问题

答案很适合扩展一个孩子,但我遇到的问题超出了孙辈的建设者。

这里是构建者的类签名,就像我拥有的​​那样
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>>{...}

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

类型参数“B”不在其范围内;应该延长 '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() 之后,返回的类型(由 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() 方法存在第二个问题,这导致了进一步的问题。回家后我会编辑以上内容以反映正确的功能和解决方案。

最终编辑

getBuilder 函数应该是

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

【问题讨论】:

    标签: java generics polymorphism subclass builder


    【解决方案1】:

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

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

    类型参数B 的目的是将ABuilder 的任何子类型 绑定到此类型变量。但是您没有在子类中正确使用此子类型绑定。

    只需将您的鲨鱼建造者和锤头建造者更改为:

    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&lt;B&gt; 之外没有必要扩展任何东西。

    【讨论】:

    • 感谢您的回复,Seelenvirtuose。这个答案对我来说看起来不错,但不幸的是,即使在您提出建议后,它也没有达到我的预期。有关详细信息,请参阅我的问题的编辑。
    猜你喜欢
    • 2014-12-01
    • 1970-01-01
    • 1970-01-01
    • 2013-01-22
    • 2016-12-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-12-30
    相关资源
    最近更新 更多