web-dev-qa-db-ja.com

Javaでメソッドチェーンを行う方法o.m1()。m2()。m3()。m4()

私は多くのJava=コード表記で見たことがありますが、メソッドの後に別のメソッドを呼び出した後の例です。

Toast.makeText(text).setGravity(Gravity.TOP, 0, 0).setView(layout).show();

ご覧のとおり、戻り時にmakeTextを呼び出した後、setGravityを呼び出します。

自分のクラスでこれを行うにはどうすればよいですか?何か特別なことをする必要がありますか?

40
Pentium10

このパターンは「Fluent Interfaces」と呼ばれます( Wikipedia を参照)

ただreturn this;何も返さず、メソッドから。

だから例えば

public void makeText(String text) {
    this.text = text;
}

なるだろう

public Toast makeText(String text) {
    this.text = text;
    return this;
}
90
Thomas Lötzer
class PersonMethodChaining {
private String name;
private int age;

// In addition to having the side-effect of setting the attributes in question,
// the setters return "this" (the current Person object) to allow for further chained method calls.

public PersonMethodChaining setName(String name) {
    this.name = name;
    return this;
}

public PersonMethodChaining setAge(int age) {
    this.age = age;
    return this;
}

public void introduce() {
    System.out.println("Hello, my name is " + name + " and I am " + age + " years old.");
}

// Usage:
public static void main(String[] args) {
    PersonMethodChaining person = new PersonMethodChaining();
    // Output: Hello, my name is Peter and I am 21 years old.
    person.setName("Peter").setAge(21).introduce();
}

}

メソッドチェーンなし

   class Person {
    private String name;
    private int age;

    // Per normal Java style, the setters return void.

    public void setName(String name) {
        this.name = name;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public void introduce() {
        System.out.println("Hello, my name is " + name + " and I am " + age + " years old.");
    }

    // Usage:
    public static void main(String[] args) {
        Person person = new Person();
        // Not using chaining; longer than the chained version above.
        // Output: Hello, my name is Peter and I am 21 years old.
        person.setName("Peter");
        person.setAge(21);
        person.introduce();
    }
}

メソッドチェーン、名前付きとも呼ばれますパラメータイディオムは、オブジェクト指向プログラミング言語で複数のメソッド呼び出しを呼び出すための一般的な構文です。各メソッドはオブジェクトを返し、呼び出しを1つのステートメントにまとめることができます。連鎖は、中間変数の必要性を排除する構文糖です。メソッドチェーンはトレインレックとしても知られています。メソッド間に改行が追加されることが多いにもかかわらず、より多くのメソッドがチェーンされるため、同じ行に次々に来るメソッドの数が増えるためです。

同様の構文はmethod cascadingです。ここで、メソッドの呼び出し後、式はメソッドの戻り値ではなく、現在のオブジェクトに評価されます。カスケードは、メソッドが現在のオブジェクト自体(this)を返すようにすることで、メソッドチェーンを使用して実装できます。カスケードは流暢なインターフェイスの主要な手法です。連鎖はオブジェクト指向言語で広く実装されていますが、カスケードはそうではないため、この形式の「これを返すことによる連鎖による連鎖」は、単に「連鎖」と呼ばれることがよくあります。連鎖とカスケードはどちらもSmalltalk言語に由来しています。

12
subhashis

あなたの例から:

Toast.makeText(text).setGravity(Gravity.TOP、0、0).setView(layout).show();

チェーン内の各メソッドは、クラスまたはインターフェースを返す必要があります。チェーンの次のメソッドは、返されるクラスの一部である必要があります。

トーストから始めます。 Toastクラスで静的メソッドとして定義されているmakeTextメソッドは、クラスまたはインターフェイスを返す必要があります。ここでは、クラスGravityのインスタンスを返します。

クラスGravityで定義されているメソッドsetGravityは、クラスViewのインスタンスを返します。

クラスViewで定義されているメソッドsetViewは、クラスJPanelのインスタンスを返します。

このチェーンは、段階的に書き出すことができます。

Gravity gravity = Toast.makeText(text);
View view       = gravity.setGravity(Gravity.TOP, 0, 0);
JPanel panel    = view.setView(layout);
panel.show();

チェーンとしてチェーンを書き込むと、すべての中間インスタンス変数がソースコードから削除されます。

6

詳細については、Googleでビルダーパターンまたは流暢なインターフェイスを検索してください。

メソッドの最後で 'this'を返すと、ほとんどの場合トリックを実行できます。

4
Guillaume

これを追加します;確かにこのクラスの連鎖には役立ちますが、サブクラスでは失敗します。

連鎖動作をサブクラスに継承させたい場合も、クラスシグネチャを次のように変更します。

スーパークラスクラス<サブクラスはスーパークラスを拡張します> {}

これにより、すべてのサブクラスがメソッドチェーンを継承します。

例:

public class SuperClass<SubClass extends SuperClass> {

    public SubClass testMethod(){
        return (SubClass)this;
    }

    public static void main(String[] args) {
        SuperClass<SuperClass> superClass = new SuperClass<SuperClass>();
        superClass.testMethod().testMethod().testMethod();
        System.out.println(superClass.toString());
    }

}
1