Статьи

Шаблон стратегии с использованием лямбда-выражений в Java 8

Шаблон стратегии — это один из шаблонов из книги «Шаблоны проектирования: элементы многоразового использования» . Цель паттерна стратегии, изложенного в книге:

Определите семейство алгоритмов, инкапсулируйте каждый и сделайте их взаимозаменяемыми. Стратегия позволяет алгоритму варьироваться независимо от клиентов, которые его используют.

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

Шаблон стратегии: пример

Рассмотрим интерфейс, объявляющий стратегию:

1
2
3
interface Strategy{
  public void performTask();
}

Рассмотрим две реализации этой стратегии:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
class LazyStratgey implements Strategy{
 
  @Override
  public void performTask() {
    System.out.println("Perform task a day before deadline!");
  }
 
}
 
class ActiveStratgey implements Strategy{
 
  @Override
  public void performTask() {
    System.out.println("Perform task now!");
  }
 
}

Вышеприведенные стратегии наивны, и я помогал читателям быстро понять их. И давайте посмотрим на эти стратегии в действии:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
public class StartegyPatternOldWay {
 
  public static void main(String[] args) {
 
    List<Strategy> strategies =
        Arrays.asList(
          new LazyStratgey(),
          new ActiveStratgey()
        );
 
    for(Strategy stg : strategies){
      stg.performTask();
    }
  }
}

Выход для вышеупомянутого:

1
2
Perform task a day before deadline!
Perform task now!

Шаблон стратегии: пример с лямбда-выражениями

Давайте посмотрим на тот же пример, используя лямбда-выражения. Для этого мы сохраним наш интерфейс Стратегии, но нам не нужно создавать другую реализацию интерфейса, вместо этого мы используем лямбда-выражения для создания различных реализаций стратегии. Код ниже показывает это в действии:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
import java.util.Arrays;
import java.util.List;
 
public class StrategyPatternOnSteroids {
  public static void main(String[] args) {
 
    System.out.println("Strategy pattern on Steroids");
 
    List<Strategy> strategies =
      Arrays.asList(
        () -> {System.out.println("Perform task a day before deadline!");},
        () -> {System.out.println("Perform task now!");}
      );
 
    strategies.forEach((elem) -> elem.performTask());
  }
 
}

Выход для вышеупомянутого:

1
2
3
Strategy pattern on Steroids
Perform task a day before deadline!
Perform task now!

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

Шаблон стратегии: еще один пример

Этот пример основан на статье Нила Форда о работах IBM Developer: Functional Design Pattern-1 . Идея примера в точности аналогична, но Нил Форд использует Scala, и я использую Java для него с некоторыми изменениями в соглашениях об именах.

Давайте посмотрим на интерфейс вычисления, который также объявляет универсальный тип T, кроме метода compute который принимает два параметра.

1
2
3
4
interface Computation<T> {
 
  public T compute(T n, T m);
}

У нас могут быть разные реализации вычислений, такие как: IntSum — который возвращает сумму двух целых чисел, IntDifference — который возвращает разность двух целых чисел и IntProduct — который возвращает произведение двух целых чисел.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class IntSum implements Computation<Integer> {
 
  @Override
  public Integer compute(Integer n, Integer m) {
    return n + m;
  }
 
}
 
class IntProduct implements Computation<Integer> {
 
  @Override
  public Integer compute(Integer n, Integer m) {
    return n * m;
  }
}
 
class IntDifference implements Computation<Integer> {
 
  @Override
  public Integer compute(Integer n, Integer m) {
    return n - m;
  }
}

Теперь давайте посмотрим на эти стратегии в действии в следующем коде:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
public class AnotherStrategyPattern {
 
  public static void main(String[] args) {
 
    List<Computation> computations =
        Arrays.asList(
          new IntSum(),
          new IntDifference(),
          new IntProduct()
        );
 
    for (Computation comp : computations) {
      System.out.println(comp.compute(10, 4));
    }
  }
}

Выход для вышеупомянутого:

1
2
3
14
6
40

Шаблон стратегии: еще один пример с лямбда-выражениями

Теперь давайте посмотрим на тот же пример, используя лямбда-выражения. Как и в предыдущем примере, нам не нужно объявлять классы для различных реализаций стратегии, то есть интерфейса Computation, вместо этого мы используем лямбда-выражения для достижения того же самого. Давайте посмотрим на пример:

01
02
03
04
05
06
07
08
09
10
11
12
public class AnotherStrategyPatternWithLambdas {
  public static void main(String[] args) {
 
    List<Computation<Integer>> computations =
          Arrays.asList(
              (n, m)-> { return n+m; },
              (n, m)-> { return n*m; },
              (n, m)-> { return n-m; }
          );
    computations.forEach((comp) -> System.out.println(comp.compute(10, 4)));
  }
}

Выход для выше:

1
2
3
14
6
40

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