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