18

最近、このタイプの構文を利用するコード (Amazon Hadoop コード) を見たことがあります。

Foo bar = new Foo().setX(10).setY(11);

甘いなと思ったのでやってみることにしました。代わりに私のsetX()型関数を返して、それらすべてを入れました。これはうまくいきました。継承で試してみると、いくつかの奇妙な結果が得られました。Foovoidreturn this;

具体例を挙げましょうLocation。x と y の 2 つのフィールドを持つ 2 つのクラスがあります。そして、3 番目のフィールド zLocation3Dを継承して追加する別のクラス。Locationすべてのフィールドは、セッターに対して上記のメソッドを使用します。

今、新しい location3D インスタンスを作成し、そのフィールドを設定したいのですが、何が起こるかです

new Location3D().setZ(7).setY(6).setX(5)

動作中

new Location3D().setX(7).setY(6).setZ(5)

しません。

by が機能しないということは、 from から返されるsetY(6)のはLocationオブジェクトではなくlocation3Dオブジェクトであるため、メソッドがないというsetZ()ことです!

この長いイントロの後、私の質問は次のとおりです。呼び出し元にオブジェクトのキャストを強制することなく、この形式の「セッター文字列」を継承で機能させることはできますか? もしそうならどのように?

また、これには「セッターストリング」よりも優れた用語があると思いますが、それは何ですか?

4

2 に答える 2

23

ご指摘のとおり、new Location3D().setX(7).setY(6).setZ(5)動作しない理由は、 and がand notのインスタンスsetX()setY()返すためです。LocationLocation3D

Locationクラスにジェネリック型パラメーターを追加することで、ジェネリックを使用してこれを回避できます (解決策は特にきれいではありません) 。

public class Location<T extends Location<T>> {
    protected int x, y;

    @SuppressWarnings("unchecked")
    public T setX(int x) {
        this.x = x;
        return (T) this;
    }

    @SuppressWarnings("unchecked")
    public T setY(int y) {
        this.y = y;
        return (T) this;
    }
}

サブクラスは、スーパークラスが の代わりに のLocation3Dインスタンスを返すように、それ自体をジェネリック型パラメーターとして設定します。Location3DLocation

public class Location3D extends Location<Location3D> {
    protected int z;

    public Location3D setZ(int z) {
        this.z = z;
        return this;
    }
}

残念ながら、スーパークラスによって生成される警告、つまり@SuppressWarnings("unchecked")注釈を回避する方法を私が知っているわけではありません。

また、ジェネリック型パラメーターが別のクラス型になるようにサブクラスを定義するとClassCastException、最終的に .

最後に、説明した方法でメソッド呼び出しを連鎖させることは、通常、メソッド連鎖と呼ばれます。あなたが説明しているセッター メソッドのスタイルは、ビルダー パターンと密接に関連しています。

于 2012-12-31T19:15:36.300 に答える
10

問題は、Location3D が Location3D を返すように、Location が Location を返すことです。これを解決するには、Location3D で使用するメソッドをオーバーライドし、戻り値の型を変更します。

public class Location {
    private int x;
    private int y;

    public Location setY(int y){
        this.y = y;
        return this;
    }

    public Location setX(int x){
        this.x = x;
        return this;
    }
}

そして Location3D:

public class Location3D extends Location {

    private int z;

    public Location3D setY(int y){
        super.setY(y);
        return this;
    }

    public Location3D setX(int x){
        super.setX(x);
        return this;
    }

    public Location3D setZ(int z){
        this.z = z;
        return this;
    }
}

構成アプローチ:

public class Location {
    private int x;
    private int y;

    public Location setY(int y){
        this.y = y;
        return this;
    }

    public Location setX(int x){
        this.x = x;
        return this;
    }
}

そして Location3D:

public class Location3D {

    private Location location = new Location();
    private int z;

    public Location3D setY(int y){
        location.setY(y);
        return this;
    }

    public Location3D setX(int x){
        location.setX(x);
        return this;
    }

    public Location3D setZ(int z){
        this.z = z;
        return this;
    }
}
于 2012-12-31T19:19:41.190 に答える