Статьи

Train Wreck Pattern — значительно улучшенная реализация в Java 8

Venkat Subramaniam на сегодняшней лекции упомянул о паттерне Cascade Method или Train Wreck, который выглядит примерно так:

1
>someObject.method1().method2().method3().finalResult()

Мало кто может связать это с шаблоном строителя , но это не то же самое. Anyways, давайте посмотрим на пример для этого в Java без использования лямбда-выражения:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
public class TrainWreckPattern {
  public static void main(String[] args) {
    new Mailer()
    .to("[email protected]")
    .from("[email protected]")
    .subject("Some subject")
    .body("Some content")
    .send();
 
  }
}
 
class Mailer{
  public Mailer to(String address){
    System.out.println("To: "+address);
    return this;
  }
  public Mailer from(String address){
    System.out.println("From: "+address);
    return this;
  }
  public Mailer subject(String sub){
    System.out.println("Subject: "+sub);
    return this;
  }
  public Mailer body(String body){
    System.out.println("Body: "+body);
    return this;
  }
  public void send(){
    System.out.println("Sending ...");
  }
}

Я взял тот же пример, что и Венкат Субраманиам в своем выступлении. В приведенном выше коде у меня есть класс Mailer который принимает ряд значений, а именно: to, from, subject и body, а затем отправляет почту. Довольно просто, верно? Но с этим связана некоторая проблема: никто не знает, что делать с объектом Mailer когда он закончит отправку почты. Можно ли использовать его повторно для отправки другой почты? Или это должно быть проведено, чтобы узнать статус отправленного электронного письма? Это не известно из приведенного выше кода, и много раз никто не может найти эту информацию в документации. Что если мы можем ограничить область действия объекта Mailer в некотором блоке, чтобы его нельзя было использовать после завершения его работы?

Java 8 предоставляет отличный механизм для достижения этого с помощью лямбда-выражений . Давайте посмотрим, как это можно сделать:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
public class TrainWreckPatternLambda {
 
  public static void main(String[] args) {
    Mailer.send( mailer -> {
      mailer.to("[email protected]")
            .from("[email protected]")
            .subject("Some subject")
            .body("Some content");
    });
  }
 
}
 
class Mailer{
 
  private Mailer(){
 
  }
  public Mailer to(String address){
    System.out.println("To: "+address);
    return this;
  }
  public Mailer from(String address){
    System.out.println("From: "+address);
    return this;
  }
  public Mailer subject(String sub){
    System.out.println("Subject: "+sub);
    return this;
  }
  public Mailer body(String body){
    System.out.println("Body: "+body);
    return this;
  }
  public static void send(Consumer<Mailer> mailerOperator){
    Mailer mailer = new Mailer();
    mailerOperator.accept(mailer);
    System.out.println("Sending ...");
  }
}

В приведенной выше реализации я ограничил создание экземпляра класса Mailer методом send() , сделав конструктор закрытым. И затем метод send() теперь принимает реализацию интерфейса Consumer, который является классом метода Single Abstract и может быть представлен лямбда-выражением. И в методе main() я передаю лямбда-выражение, которое принимает экземпляр Mailer а затем настраивает объект mailer перед использованием в методе send() .

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

Дайте мне знать, если есть что-то еще, что я могу улучшить в этом примере, которым я поделился.