Шаблон стратегии — это один из шаблонов из книги «Шаблоны проектирования: элементы многоразового использования» . Цель паттерна стратегии, изложенного в книге:
Определите семейство алгоритмов, инкапсулируйте каждый и сделайте их взаимозаменяемыми. Стратегия позволяет алгоритму варьироваться независимо от клиентов, которые его используют.
В этой статье я хотел бы привести один или два примера по шаблону стратегии, а затем переписать этот же пример, используя лямбда-выражения, которые будут представлены в 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 SteroidsPerform 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
|
14640 |
Шаблон стратегии: еще один пример с лямбда-выражениями
Теперь давайте посмотрим на тот же пример, используя лямбда-выражения. Как и в предыдущем примере, нам не нужно объявлять классы для различных реализаций стратегии, то есть интерфейса 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
|
14640 |
Из приведенных выше примеров мы видим, что использование лямбда-выражений поможет сократить объем стандартного кода для получения более краткого кода. А с практикой можно привыкнуть к чтению лямбда-выражений.