当前位置: 首页 > 知识库问答 >
问题:

使用超类创建生成器时,父类不能返回子类的实例 [重复]

楚墨一
2023-03-14

如果我使用构建器模式来配置新对象,我可能有两个类,如GameHockeyGame(如下所示)。当我想创建一个新的HockeyGame时,我得到它的构建器并开始调用方法来根据需要配置对象。

我遇到的问题显示在main函数中。一旦我从超类调用一个方法,它就会以Game.Builder的意图返回,并且我不能再从子类调用任何方法。

处理这个问题的最佳方法是什么?

Main.java

class Main {

    public static void main(String[] args){

        HockeyGame hg = new HockeyGame.Builder()
                .setScore(5)
                .setTimeLimit(3600)
//--------------------------------------------------------------------
                .setIceTemperature(-5) // Error! Cannot call setIceTempurature() on
                                       // an instance of Game.Builder
//--------------------------------------------------------------------
                .build();


    }
}

Game.java

public class Game{

    int score;
    int timeLimit;

    public Game(int score, int timeLimit) {
        this.score = score;
        this.timeLimit = timeLimit;
    }

    public static class Builder {

        int score;
        int timeLimit;

        public Builder setScore(int score) {
            this.score = score;
            return this;
        }

        public Builder setTimeLimit(int timeLimit) {
            this.timeLimit = timeLimit;
            return this;
        }

        public Game build() {
            return new Game(score, timeLimit);
        }
    }
}

HockeyGame.java

public class HockeyGame extends Game {

    float iceTemperature;

    public HockeyGame(int score, int timeLimit, float iceTemperature) {
        super(score, timeLimit);
        this.iceTemperature = iceTemperature;
    }

    public static class Builder extends Game.Builder {

        float iceTemperature;

        public HockeyGame.Buidler setIceTemperature(float iceTemperature) {
            this.iceTemperature = iceTemperature;
            return this;
        }

        public HockeyGame build(){
            return new HockeyGame(score, timeLimit, iceTemperature);
        }
    }
}

谢了。

共有2个答案

龙安阳
2023-03-14

试试这样的东西

您明确地将其转换回曲棍球游戏.Builder 对象,并在其上使用自己的方法。

您遇到的问题是setTimeLimit返回一个Builder对象(母类),因此您不能在其上使用子方法。

HockeyGame hg = ((HockeyGame.Builder)(new HockeyGame.Builder().setScore(5)
                                                              .setTimeLimit(3600)))
                                                              .setIceTemperature(-5)
                                                              .build();

此外,setIceTemparature应该返回一个曲棍球游戏。生成器对象,以便能够在其上构建

public Builder setIceTemperature(float iceTemperature) {
    this.iceTemperature = iceTemperature;
    return this;
}
笪昌翰
2023-03-14

您需要使用< code>getThis()技巧,这在许多流畅的API代码中很常见。

首先你需要制作你的< code >游戏。生成器本身是通用的:

public static class Builder<B extends Builder<B>>

然后添加一个< code>getThis()方法:

public B getThis() {
    return (B) this;
}

现在您更改设置器以返回B返回getThis()而不是this

public B setTimeLimit(int timeLimit) {
    //...
    return getThis();
}

您的扩展类本身也需要是泛型的:

public static class Builder<B extends Builder<B>> extends Game.Builder<B>

现在您可以使用代码,它将“记住”预期的类型:

HockeyGame hockeyGame = new HockeyGame.Builder<>().setScore(10)
        .setTimeLimit(20)
        .setIceTemperature(-1)
        .build();

最终代码如下所示:

public class Game {

    private final int score;
    private final int timeLimit;

    private Game(final Builder<?> builder) {
        this.score = builder.score;
        this.timeLimit = builder.timeLimit;
    }

    public static class Builder<B extends Builder<B>> {

        private int score;
        private int timeLimit;

        public B setScore(int score) {
            this.score = score;
            return getThis();
        }

        public B setTimeLimit(int timeLimit) {
            this.timeLimit = timeLimit;
            return getThis();
        }

        protected B getThis() {
            return (B) this;
        }

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

public class HockeyGame extends Game {

    private final float iceTemperature;

    private HockeyGame(final Builder<?> builder) {
        super(builder);
        this.iceTemperature = builder.iceTemperature;
    }

    public static class Builder<B extends Builder<B>> extends Game.Builder<B> {

        private float iceTemperature;

        public B setIceTemperature(float iceTemperature) {
            this.iceTemperature = iceTemperature;
            return getThis();
        }

        @Override
        public HockeyGame build() {
            return new HockeyGame(this);
        }
    }
}

注意:我已经使字段私有最终和主类型构造函数 - 这迫使人们使用构建器。此外,构造函数可以采用生成器

你可能已经注意到了,实际的破解是这样的:

public B getThis() {
    return (B) this;
}

这里,我们强制将<code>Builder生成器如下:

public static class FootballGame extends Game {

    private FootballGame(final Builder<?> builder) {
        super(builder);
    }

    public static class Builder<B extends HockeyGame.Builder<B>> extends Game.Builder<B> {

        float iceTemperature;

        @Override
        public FootballGame build() {
            return new FootballGame(this);
        }
    }
}

this将在运行时使用ClassCastException爆炸。但是setter方法将返回HockeyGame.Builder而不是FootballGame.Builder,因此问题应该很明显。

 类似资料:
  • 问题内容: 我正在创建一个类及其子类,需要在其中调用父级的静态方法以返回子级实例。 问题答案: 该静态方法被调用,其值是类对象,子类,你把它称为后的构造。因此,您可以使用实例化它:

  • 是否可以自动创建返回的setter? 尝试了以下操作,但这样它不起作用,但是这个例子显示了我想要实现的目标: 手动解决方案 编写coure的<code>setter</code>和<code>getter</code>我自己,如下所示: 问题 这个过程可以用kotlin自动化吗?有什么办法可以做到这一点吗?

  • 如果我有以下代码 首先,这甚至是可能的,因为它编译得很好。但是我不能使用中的方法执行操作: makeCan是否不同时返回Can和PromotionalCan?如果是这样,当返回PromotionalCan时,如何对变量进行操作?谢谢 编辑:PromotionalCan继承自Can,第二种方法是在PromotionalCan中

  • 我在父类和子类中都有构建器。父对象有一个抽象生成器和一个扩展抽象生成器的具体生成器。子级有一个扩展父级抽象生成器的抽象生成器和一个扩展子级抽象生成器的具体生成器。原因是父级的setter返回当前的Builder类。我有一些方法返回类自己的抽象构建器类型,我想将其称为父抽象类型(调用它的父方法)。我所能做的就是

  • 然后我调用子类中的方法。 我希望有一个对象创建的基础上,子类已经被调用,如果这是有意义的?

  • 我在想有没有更好的办法。我想要的是在抽象类中有一个具体的方法,返回扩展抽象类的具体实例。 我认为我不应该把它转换成T,因为它总是T的一个实例。