スーパークラスを使用してビルダーを作成する場合、親は子クラスのインスタンスを返すことができません

ジェイクトーマス

ビルダーパターンを使用して新しいオブジェクトを構成している場合、とのような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]

編集
0

コメントを追加

0

関連記事

分類Dev

gradleを使用してダミークラスをコンパイルすることはできません

分類Dev

コンパイラパス内でサービスを使用する場合、クラスが存在しません

分類Dev

ループはクラスの複数のインスタンスを作成できますが、行ごとに作成することはできませんか?

分類Dev

jenkinsを使用して作成されたiOS9にアプリビルドをインストールできません。エラーは、シンボリックリンクに絶対パスがあることを示しています

分類Dev

クラスのインスタンスを作成するときにパラメータを渡すことができません

分類Dev

Babelのtransform-class-propertiesを介して親クラスコンストラクター内で子クラスのプロパティを使用することはできません

分類Dev

Babelのtransform-class-propertiesを介して親クラスコンストラクター内で子クラスのプロパティを使用することはできません

分類Dev

PHPの子クラスは、親クラスが実装するのと同じインターフェイスを実装できません

分類Dev

shapeless.Genericを使用する場合、エラーを回避する方法 'パラメーターが名前で宣言されていない限り、スーパーコンストラクターに自己参照を渡すことはできません'?

分類Dev

`クラスNAME`のインスタンスを作成することはできません(少なくともクリエーターに存在するが)

分類Dev

新しいFileコンストラクターのParentパラメーターとChildパラメーターを使用してJavaでファイルを作成することはできません

分類Dev

Intent.ACTION_SENDTOを使用すると、2つの電子メールクライアントがインストールされている場合でも、「このアクションを実行できるアプリはありません」というエラーが発生します。

分類Dev

エラーが返されない場合でも、PowerShellスクリプトを使用してChromeをリモートでインストールすることはできません

分類Dev

エクスプレスレスポンスを返し、エラーをスローするspyOn関数タイプ「Response <any>」の引数をタイプ「Response」のパラメータに割り当てることはできません

分類Dev

ノー文字列引数のコンストラクタ/工場:java.util.LinkedHashMapのインスタンスを作成することはできません

分類Dev

クラスコンストラクターは子クラスを返すことができますか?

分類Dev

Codableクラスのインスタンスを作成するときに、呼び出しでパラメーター 'from'の引数がありません

分類Dev

2つ以上のパラメーターを使用してWCFサービスコントラクトを呼び出すことはできません

分類Dev

なぜ型パラメータのインスタンスを作成することはできませんか?

分類Dev

クラウドエンドポイントポータルは、そうでない場合、ユーザはありませんAPIを使用すると、ビューへのアクセス権を持っていることを利用できます取得、GCP / IAMの権限が必要です

分類Dev

コンストラクター引数の1つがList型である場合、nullパラメーターを使用してプライベートコンストラクターをテストすることは可能ですか?

分類Dev

別のクラスのメンバーとしてのみインスタンス化できるが、VB.NETでこれを介してパブリックにアクセスできるクラスを作成することは可能ですか?

分類Dev

CloudSDKを使用して仮想データモデルクラスを作成することはできません

分類Dev

基本クラスのポインタを介して、派生クラス固有のメンバーにアクセスすることはできません

分類Dev

c ++コンストラクターのパラメーターとして親型を使用できません

分類Dev

どのように私は「スーパー()」に引数を渡すために無用パススルー子クラスのコンストラクタを作成しないようにすることができますか?

分類Dev

Fake.Deploy を使用する場合、パスワードをスクリプトのパラメーターとして渡すことはできますか?

分類Dev

ダート:別のクラスのクラスをインスタンス化することはできません

分類Dev

封印されたクラスまたはMoshiとのインターフェースを使用している場合、クラスのコンバーターを作成できません

Related 関連記事

  1. 1

    gradleを使用してダミークラスをコンパイルすることはできません

  2. 2

    コンパイラパス内でサービスを使用する場合、クラスが存在しません

  3. 3

    ループはクラスの複数のインスタンスを作成できますが、行ごとに作成することはできませんか?

  4. 4

    jenkinsを使用して作成されたiOS9にアプリビルドをインストールできません。エラーは、シンボリックリンクに絶対パスがあることを示しています

  5. 5

    クラスのインスタンスを作成するときにパラメータを渡すことができません

  6. 6

    Babelのtransform-class-propertiesを介して親クラスコンストラクター内で子クラスのプロパティを使用することはできません

  7. 7

    Babelのtransform-class-propertiesを介して親クラスコンストラクター内で子クラスのプロパティを使用することはできません

  8. 8

    PHPの子クラスは、親クラスが実装するのと同じインターフェイスを実装できません

  9. 9

    shapeless.Genericを使用する場合、エラーを回避する方法 'パラメーターが名前で宣言されていない限り、スーパーコンストラクターに自己参照を渡すことはできません'?

  10. 10

    `クラスNAME`のインスタンスを作成することはできません(少なくともクリエーターに存在するが)

  11. 11

    新しいFileコンストラクターのParentパラメーターとChildパラメーターを使用してJavaでファイルを作成することはできません

  12. 12

    Intent.ACTION_SENDTOを使用すると、2つの電子メールクライアントがインストールされている場合でも、「このアクションを実行できるアプリはありません」というエラーが発生します。

  13. 13

    エラーが返されない場合でも、PowerShellスクリプトを使用してChromeをリモートでインストールすることはできません

  14. 14

    エクスプレスレスポンスを返し、エラーをスローするspyOn関数タイプ「Response <any>」の引数をタイプ「Response」のパラメータに割り当てることはできません

  15. 15

    ノー文字列引数のコンストラクタ/工場:java.util.LinkedHashMapのインスタンスを作成することはできません

  16. 16

    クラスコンストラクターは子クラスを返すことができますか?

  17. 17

    Codableクラスのインスタンスを作成するときに、呼び出しでパラメーター 'from'の引数がありません

  18. 18

    2つ以上のパラメーターを使用してWCFサービスコントラクトを呼び出すことはできません

  19. 19

    なぜ型パラメータのインスタンスを作成することはできませんか?

  20. 20

    クラウドエンドポイントポータルは、そうでない場合、ユーザはありませんAPIを使用すると、ビューへのアクセス権を持っていることを利用できます取得、GCP / IAMの権限が必要です

  21. 21

    コンストラクター引数の1つがList型である場合、nullパラメーターを使用してプライベートコンストラクターをテストすることは可能ですか?

  22. 22

    別のクラスのメンバーとしてのみインスタンス化できるが、VB.NETでこれを介してパブリックにアクセスできるクラスを作成することは可能ですか?

  23. 23

    CloudSDKを使用して仮想データモデルクラスを作成することはできません

  24. 24

    基本クラスのポインタを介して、派生クラス固有のメンバーにアクセスすることはできません

  25. 25

    c ++コンストラクターのパラメーターとして親型を使用できません

  26. 26

    どのように私は「スーパー()」に引数を渡すために無用パススルー子クラスのコンストラクタを作成しないようにすることができますか?

  27. 27

    Fake.Deploy を使用する場合、パスワードをスクリプトのパラメーターとして渡すことはできますか?

  28. 28

    ダート:別のクラスのクラスをインスタンス化することはできません

  29. 29

    封印されたクラスまたはMoshiとのインターフェースを使用している場合、クラスのコンバーターを作成できません

ホットタグ

アーカイブ