6

Java 7プレビュープレゼンテーション(pdf)を読んでいて、 ChainedInvocationのスライドがありました。スライドで使用されている例は次のとおりです。

// Construction with setters
DrinkBuilder margarita = new DrinkBuilder();
margarita.add("tequila");
margarita.add("orange liqueur");
margarita.add("lime juice");
margarita.withRocks();
margarita.withSalt();
Drink drink = margarita.drink();

// Construction with chained invocation
Drink margarita = new DrinkBuilder()
    .add("tequila")
    .add("orange liqueur")
    .add("lime juice")
    .withRocks()
    .withSalt()
    .drink();

そして、私はこれについて複雑な気持ちを持っています。あまりにも多くのメソッド呼び出しを1つのステートメントにチェーンするべきではありません。一方で、書くことも便利margarita.this()margarita.that()はありません。

今、私はDelphiの世界からJavaに来ています。そしてDelphiにはwith言語構造があります。これは少数の人に愛され、多くの人に嫌われています(またはその逆ですか?)。with私は連鎖呼び出しのアイデアよりもエレガントであることがわかりました(これvoidは、呼び出されたオブジェクトへの参照を返すメソッドに基づいて機能すると信じています-これは私が好きではない部分であり、何もvoid返さないはずです)。

Javaで採用されている言語機能をいただければ幸いwithです。そのため、サンプルコードは次のように記述できます。

Drink margarita = null;
with (new DrinkBuilder()) {
    add("tequila");
    add("orange liqueur");
    add("lime juice");
    withRocks();
    withSalt();
    margarita = drink();
}

連鎖呼び出しよりもこのソリューションを好むのは私だけですか?他の誰かがそれwithがJava言語への有用な拡張であるかもしれないと感じますか?(「Java ++」の必要性についての誰かの質問を思い出させます...)

4

6 に答える 6

13

withステートメントは、初期化子を使用した匿名クラスを使用してJavaで変換できます。

Drink margarita = new DrinkBuilder() {{
    add(“tequila”);
    add(“orange liqueur”);
    add(“lime juice”);
    withRocks();
    withSalt();
}}.drink();

このイディオムを使用することの欠点は、ここに詳しく記載されています。

連鎖呼び出しは、メソッド連鎖のエイリアスです。これはよく知られているイディオムであり、どのバージョンのJavaでも機能します。

class Chained {

    public Chained withFoo() { 
        // ...
        return this;
    }

    public Chained withBar() { 
        // ...
        return this;
    }
}    

JDK 7の提案では、voidreturntypeに対しても連鎖メソッドを使用できます

class ChainedJava7 {

    public void withFoo() { 
        // ...
    }

    public void withBar() { 
        // ...
    }
}    
于 2009-06-18T10:30:15.810 に答える
2

これはあなたの興味を引くかもしれません。

于 2009-06-18T10:24:16.040 に答える
2

with私はその形式のステートメントがとても好きですが、それらの VB バージョンを好みます。

With testObject
    .Height = 100
    .Text = "Hello, World"
    .ForeColor = System.Drawing.Color.Green
End With

Withブロック内の各属性の前に.を付ける必要があるため、たとえばローカル変数ではなく Object プロパティを参照していることがわかるため、名前空間の競合が減少します。

あなたの例を挙げると:

with (new DrinkBuilder()) {
    add(“tequila”);
    add(“orange liqueur”);
    add(“lime juice”);
    withRocks();
    withSalt();
    margarita = drink();
}

withSalt()がのメソッドなのDrinkBuilderかローカル クラスのメソッドなのかを簡単に判断する方法はありません。withブロックで -ed オブジェクトのメソッドのみを許可すると、withそれらはあまり役に立たなくなると思います。

于 2009-06-18T10:33:49.063 に答える
1

私はこの使用法のファンではありませんwith私はPythonwithステートメントを大いに好みます。voidしかし、私はあなたに同意しますvoid。あなたが提供する例では、メソッド呼び出しをチェーンできるようにしたい場合は、メソッドの戻りタイプを変更してチェーン可能にする必要があります。

于 2009-06-18T10:23:04.047 に答える
1

1 つのオブジェクトに対する多数の呼び出しは、一部のコードを移動する必要があることを示しているのでしょうか?

于 2009-06-18T11:42:16.413 に答える
1

効果的な Java項目 #2 のJoshua Bloch は、多くの引数を持つコンストラクターがある場合はビルダーを使用することを強く推奨しています。理由の 1 つは、ビルドされたオブジェクトが常に一貫した状態であることを保証するように記述できることです。また、構築されたオブジェクトのクラスに複雑な「伸縮コンストラクター」が含まれないようにします。もう 1 つの問題は、ビルドされたオブジェクトを不変にしたい場合 (スレッド セーフなど)、セッター メソッドを使用できないことです。

于 2009-06-18T12:53:21.683 に答える