使用 superclass 创建构建器时,父项不能 return 子项 class 的实例
When creating a builder with a superclass, parent cannot return instance of child class
如果我使用构建器模式来配置新对象,我可能有两个 class,例如 Game
和 HockeyGame
(如下所示)。当我想创建一个新的 HockeyGame
时,我得到它的构建器并开始调用方法根据需要配置对象。
我 运行 遇到的问题显示在主函数中。一旦我从超级 class 调用一个方法,它 returns 作为 Game.Builder
的一个实例,我就不能再从子 class.[=19= 调用任何方法]
处理这个问题的最佳方法是什么?
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);
}
}
}
曲棍球Game.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);
}
}
}
谢谢。
尝试这样的事情
您明确地将它转换回 HockeyGame.Builder
对象并使用它自己的方法。
您遇到的问题是 setTimeLimit
return 是一个 Builder
对象(母 class),因此您不能在其上使用子方法。
HockeyGame hg = ((HockeyGame.Builder)(new HockeyGame.Builder().setScore(5)
.setTimeLimit(3600)))
.setIceTemperature(-5)
.build();
此外,setIceTemparature
应该 return 一个 HockeyGame.Builder
对象才能 build
在上面。
public Builder setIceTemperature(float iceTemperature) {
this.iceTemperature = iceTemperature;
return this;
}
您需要使用 getThis()
技巧,该技巧在非常流畅的 API 代码中很流行。
首先,您需要在 中使 Game.Builder
通用:
public static class Builder<B extends Builder<B>>
然后你添加一个getThis()
方法:
public B getThis() {
return (B) this;
}
现在您将 setter 更改为 return a B
和 return getThis()
而不是 this
:
public B setTimeLimit(int timeLimit) {
//...
return getThis();
}
您的扩展 class 本身也需要通用:
public static class Builder<B extends Builder<B>> extends Game.Builder<B>
现在您可以使用代码了,它将"remember"预期的类型:
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);
}
}
}
N.B:我制作了字段 private final
以及主要类型构造函数 - 这迫使人们使用 Builder
。此外,构造函数可以采用 Builder<?>
并从那里复制变量 - 这会稍微整理一下代码。
正如您可能已经注意到的那样,实际的破解方法是:
public B getThis() {
return (B) this;
}
在这里,我们强制将 Builder
强制转换为其泛型类型 - 这允许我们根据所使用的特定实例更改方法的 return 类型。问题是,如果您声明一个新的 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);
}
}
}
这将在运行时以 ClassCastException
爆炸。但是 setter
方法将 return 变成 HockeyGame.Builder
而不是 FootballGame.Builder
所以问题应该很明显。
如果我使用构建器模式来配置新对象,我可能有两个 class,例如 Game
和 HockeyGame
(如下所示)。当我想创建一个新的 HockeyGame
时,我得到它的构建器并开始调用方法根据需要配置对象。
我 运行 遇到的问题显示在主函数中。一旦我从超级 class 调用一个方法,它 returns 作为 Game.Builder
的一个实例,我就不能再从子 class.[=19= 调用任何方法]
处理这个问题的最佳方法是什么?
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);
}
}
}
曲棍球Game.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);
}
}
}
谢谢。
尝试这样的事情
您明确地将它转换回 HockeyGame.Builder
对象并使用它自己的方法。
您遇到的问题是 setTimeLimit
return 是一个 Builder
对象(母 class),因此您不能在其上使用子方法。
HockeyGame hg = ((HockeyGame.Builder)(new HockeyGame.Builder().setScore(5)
.setTimeLimit(3600)))
.setIceTemperature(-5)
.build();
此外,setIceTemparature
应该 return 一个 HockeyGame.Builder
对象才能 build
在上面。
public Builder setIceTemperature(float iceTemperature) {
this.iceTemperature = iceTemperature;
return this;
}
您需要使用 getThis()
技巧,该技巧在非常流畅的 API 代码中很流行。
首先,您需要在 中使 Game.Builder
通用:
public static class Builder<B extends Builder<B>>
然后你添加一个getThis()
方法:
public B getThis() {
return (B) this;
}
现在您将 setter 更改为 return a B
和 return getThis()
而不是 this
:
public B setTimeLimit(int timeLimit) {
//...
return getThis();
}
您的扩展 class 本身也需要通用:
public static class Builder<B extends Builder<B>> extends Game.Builder<B>
现在您可以使用代码了,它将"remember"预期的类型:
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);
}
}
}
N.B:我制作了字段 private final
以及主要类型构造函数 - 这迫使人们使用 Builder
。此外,构造函数可以采用 Builder<?>
并从那里复制变量 - 这会稍微整理一下代码。
正如您可能已经注意到的那样,实际的破解方法是:
public B getThis() {
return (B) this;
}
在这里,我们强制将 Builder
强制转换为其泛型类型 - 这允许我们根据所使用的特定实例更改方法的 return 类型。问题是,如果您声明一个新的 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);
}
}
}
这将在运行时以 ClassCastException
爆炸。但是 setter
方法将 return 变成 HockeyGame.Builder
而不是 FootballGame.Builder
所以问题应该很明显。