Как добиться цепочки методов в Java?

Я хочу добиться цепочки методов в Java.

Как я могу достичь этого?

Также дайте мне знать, когда его использовать.

public class Dialog {

     public Dialog() {

     }

     public void setTitle(String title) {

         //Logic to set title in dialog
     }

     public void setMessage(String message) {

         //Logic to set message
     }     

     public void setPositiveButton() {

         //Logic to send button
     }
}   

Я хочу создать цепочку методов, которую я могу использовать следующим образом:

new Dialog().setTitle("Title1").setMessage("sample message").setPositiveButton();

или нравится

new Dialog().setTitle("Title1").setMessage("sample message");

или нравится

new Dialog().setTitle("Title1").setPositiveButton();

person Bug    schedule 17.01.2014    source источник
comment
Нравится шаблон Builder?   -  person Dennis Meng    schedule 17.01.2014
comment
Обычно это называется fluency или fluent программированием.   -  person Pureferret    schedule 17.01.2014
comment
Вы бы создали Builder для диалога вместо использования сеттеров для свободного API. Если вы сделаете так много bean-подобных, доступ больше не будет работать, поскольку фреймворки ограничивают сеттеры возвратом void. Взгляните на проект ломбок, если вам не нравится писать весь этот шаблон.   -  person Arne Burmeister    schedule 22.06.2016


Ответы (4)


Пусть ваши методы возвращают this, например:

public Dialog setMessage(String message)
{
    //logic to set message
    return this;
}

Таким образом, после каждого вызова одного из методов вы будете получать один и тот же объект, чтобы вы могли вызвать другой метод.

Этот метод полезен, когда вы хотите вызвать серию методов для объекта: он уменьшает объем кода, необходимого для достижения этого, и позволяет вам иметь одно возвращаемое значение после цепочки методов.

Примером уменьшения количества кода, необходимого для отображения диалогового окна, может быть:

// Your Dialog has a method show() 
// You could show a dialog like this:
new Dialog().setMessage("some message").setTitle("some title")).show();

Примером использования единственного возвращаемого значения может быть:

// In another class, you have a method showDialog(Dialog)
// Thus you can do:
showDialog(new Dialog().setMessage("some message").setTitle("some title"));

Пример использования шаблона Builder, который Деннис упомянул в комментарии к вашему вопросу:

new DialogBuilder().setMessage("some message").setTitle("some title").build().show();

Шаблон построителя позволяет вам установить все параметры для нового экземпляра класса до того, как объект будет построен (рассмотрите классы, которые имеют final полей или объектов, для которых установка значения после его создания обходится дороже, чем установка его при его построении) .

В приведенном выше примере: setMessage(String), setTitle(String) принадлежат классу DialogBuilder и возвращают тот же экземпляр DialogBuilder, к которому они вызываются; метод build() принадлежит классу DialogBuilder, но возвращает объект Dialog метод show() принадлежит классу Dialog.

Дополнительно

Возможно, это не связано с вашим вопросом, но может помочь вам и другим людям, столкнувшимся с этим вопросом.

Это хорошо подходит для большинства случаев использования: всех случаев использования, не связанных с наследованием, и некоторых конкретных случаев, связанных с наследованием, когда производный класс не добавляет новых методов, которые вы хотите связать вместе, и вы не заинтересован в использовании (без приведения) результата цепочки методов в качестве объекта производного.

Если вы хотите иметь цепочку методов для объектов производных классов, у которых нет метода в их базовом классе, или вы хотите, чтобы цепочка методов возвращала объект как ссылку на производный класс, вы можете посмотреть ответы для этот вопрос.

person lucian.pantelimon    schedule 17.01.2014
comment
Я добавил пример использования последним, так как пропустил часть вашего вопроса. Обратите внимание, что это не единственное использование цепочки методов и/или шаблона Builder: как и в случае с большинством шаблонов кодирования, алгоритмов и методов, с небольшим творческим подходом можно найти новое применение для старого шаблона (алгоритма, метода):) - person lucian.pantelimon; 17.01.2014
comment
Не рекомендуется изменять поведение настроек, потому что некоторые фреймворки не ожидают возврата от метода установки. Например, вы получите сообщение об ошибке с драйвером Cassandra Java, если сеттеры в вашей модели вернут некоторые значения. - person Vagif; 16.02.2017

Просто добавьте статический метод построения и создайте еще один набор методов установки. Например

class Model {
   private Object FieldA;

   private Object FieldB;

   public static Model create() {
       return new Model();
   }

   public Model withFieldA(Object value) {
       setFieldA(value);
       return this;
   }

   public Model withFieldB(Object value) {
       setFieldB(value);
       return this;
   }
}

...

И используйте его как

 Model m = Model.create().withFieldA("AAAA").withFieldB(1234);
person Vagif    schedule 21.06.2016

пример уменьшения количества кода, необходимого для отображения диалогового окна:

package com.rsa.arraytesting;

public class ExampleJavaArray {

String age;
String name;

public ExampleJavaArray getAge() {
    this.age = "25";
    return this;
}

public ExampleJavaArray setName(String name) {
    this.name = name;
    return this;
}
public void displayValue() {
    System.out.println("Name:" + name + "\n\n" + "Age:" + age);
}
}

другой класс

package com.rsa.arraytesting;

public class MethodChaining {

public static void main(String[] args) {

    ExampleJavaArray mExampleJavaArray = new ExampleJavaArray();

    mExampleJavaArray.setName("chandru").getAge().displayValue();

}

}
person Chandru Sekar    schedule 14.04.2015
comment
пакет com.rsa.arraytesting; общественный класс MethodChaining { public static void main(String[] args) { ExampleJavaArray mExampleJavaArray = new ExampleJavaArray(); mExampleJavaArray.setName(chandru).getAge().displayValue(); } } - person Chandru Sekar; 14.04.2015

В случае, если вы используете ломбок, вы можете использовать параметр в своем lombok.config:

lombok.accessors.chain = true

Или для определенных классов данных вы можете объявить аннотацию @Accessors(chain = true):

import lombok.experimental.Accessors;

@Accessors(chain = true)
@Data
public class DataType {

    private int value;

    // will generate setter:
    public DataType setValue(int value) {
        this.value = value;
        return this;
    }

}
person seregamorph    schedule 29.08.2020