ビルダーパターンを使用して新しいオブジェクトを構成している場合、とのような2つのクラスがGame
ありますHockeyGame
(以下を参照)。新しいを作成したいときはHockeyGame
、そのビルダーを取得し、必要に応じてオブジェクトを構成するためのメソッドの呼び出しを開始します。
私が遭遇している問題は、main関数に表示されます。スーパークラスから1つのメソッドを呼び出すと、そのメソッドはのインスタンスとして返され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);
}
}
}
ありがとう。
getThis()
多くの流暢なAPIコードで普及しているトリックを使用する必要があります。
まず、Game.Builder
ジェネリック自体を作成する必要があります。
public static class Builder<B extends Builder<B>>
次に、getThis()
メソッドを追加します。
public B getThis() {
return (B) this;
}
ここで、セッターを変更して、:ではなくB
とを返すようにします。return 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);
}
}
}
注意:フィールドprivate final
とメインタイプのコンストラクターを作成しましたBuilder
。これにより、ユーザーはを使用する必要があります。また、コンストラクターはを取り、Builder<?>
そこから変数をコピーできます。これにより、コードが少し整理されます。
お気づきかもしれませんが、実際のハッキングは次のとおりです。
public B getThis() {
return (B) this;
}
ここでは、のキャストBuilder
をそのジェネリック型に強制します。これにより、使用されている特定のインスタンスに応じて、メソッドの戻り値の型を変更できます。問題は、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
メソッドはではHockeyGame.Builder
なくを返すFootballGame.Builder
ので、問題は明らかです。
この記事はインターネットから収集されたものであり、転載の際にはソースを示してください。
侵害の場合は、連絡してください[email protected]
コメントを追加