开发者

How to do method chaining in Java? o.m1().m2().m3().m4()

I've seen in many Java code notation that after a method we call another, here is an example.

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

As you see after calling makeText on the return we call setGravity and so far

How can I do this with my own classes? Do I have to do anything s开发者_运维问答pecial?


This pattern is called "Fluent Interfaces" (see Wikipedia)

Just return this; from the methods instead of returning nothing.

So for example

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

would become

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


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();
    }
}

Without method chaining

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();
    }
}

Method chaining, also known as named parameter idiom, is a common syntax for invoking multiple method calls in object-oriented programming languages. Each method returns an object, allowing the calls to be chained together in a single statement. Chaining is syntactic sugar which eliminates the need for intermediate variables. A method chain is also known as a train wreck due to the increase in the number of methods that come one after another in the same line that occurs as more methods are chained together even though line breaks are often added between methods.

A similar syntax is method cascading, where after the method call the expression evaluates to the current object, not the return value of the method. Cascading can be implemented using method chaining by having the method return the current object itself (this). Cascading is a key technique in fluent interfaces, and since chaining is widely implemented in object-oriented languages while cascading isn't, this form of "cascading-by-chaining by returning this" is often referred to simply as "chaining". Both chaining and cascading come from the Smalltalk language.


From your example:

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

Each method in the chain has to return a class or an interface. The next method in the chain has to be a part of the returned class.

We start with Toast. The method makeText, which is defined as a static method in the class Toast, has to return a class or an interface. Here, it returns an instance of the class Gravity.

The method setGravity, which is defined in the class Gravity, returns an instance of the class View,

The method setView, which is defined in the class View, returns an instance of the class JPanel.

This chain could be written out step by step.

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

Writing the chain as a chain removes all of the intermediate instance variables from the source code.


Search for builder pattern or fluent interface on google to have more details about this.

Return 'this' at the end of your method can do the trick in most cases.


Adding return this; would surely help in chaining for this class but fail for sub-classes.

If you want to have the chaining behaviour inherited to the sub-classes also then change your class signature as below:

Class SuperClass < SubClass extends SuperClass >{}

This way all sub-classes will inherit method chaining.

Example:

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());
    }

}


or you can use Diezel that generates all the interfaces you need based on a Regular expression of your fluent API.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜