Шаблон стратегии определяет семейство алгоритмов, инкапсулированных в класс драйвера, обычно известный как Context, и обеспечивает взаимозаменяемость алгоритмов. Это делает алгоритмы легко взаимозаменяемыми и предоставляет механизм для выбора подходящего алгоритма в определенное время.
Алгоритмы (стратегии) выбираются во время выполнения клиентом или контекстом. Класс Context обрабатывает все данные во время взаимодействия с клиентом.
Основные участники модели Стратегии представлены ниже:
- Стратегия — Определяет интерфейс для всех алгоритмов. Этот интерфейс используется для вызова алгоритмов, определенных ConcreteStrategy.
- Контекст — содержит ссылку на объект Стратегия.
- ConcreteStrategy — Фактическая реализация алгоритма согласно интерфейсу Стратегии
Теперь давайте рассмотрим конкретный пример шаблона стратегии и посмотрим, как он преобразуется с помощью лямбда-выражений. Предположим, у нас есть разные типы ставок для расчета подоходного налога. В зависимости от того, уплачен ли налог заранее или поздно, существует скидка или штраф соответственно. Мы можем инкапсулировать эту функциональность в одном классе с разными методами, но для этого потребуется модификация класса, если в будущем потребуется какой-то другой расчет налога. Это не эффективный подход. Изменения в реализации класса должны быть последним средством.
Давайте выберем оптимальный подход, используя шаблон стратегии. Мы сделаем интерфейс для налоговой стратегии с помощью основного метода:
|
1
2
3
4
|
public interface TaxStrategy { public double calculateTax(double income);} |
Теперь давайте определимся с конкретной стратегией нормального подоходного налога.
|
01
02
03
04
05
06
07
08
09
10
11
12
13
|
public class PersonalTaxStrategy implements TaxStrategy { public PersonalTaxStrategy() { } @Override public double calculateTax(double income) { System.out.println("PersonalTax"); double tax = income * 0.3; return tax; }} |
Класс PersonalTaxStrategy соответствует интерфейсу TaxStrategy. Аналогично, давайте определим конкретную стратегию для просрочки уплаты налога, которая влечет за собой штраф.
|
01
02
03
04
05
06
07
08
09
10
11
12
13
|
public class PersonalTaxPenaltyStrategy implements TaxStrategy { public PersonalTaxPenaltyStrategy() { } @Override public double calculateTax(double income) { System.out.println("PersonalTaxWithPenalty"); double tax = income * 0.4; return tax; }} |
Далее давайте определим конкретную стратегию для уплаты авансового налога, которая приведет к возврату налога.
|
01
02
03
04
05
06
07
08
09
10
11
12
13
|
public class PersonalTaxRebateStrategy implements TaxStrategy { public PersonalTaxRebateStrategy() { } @Override public double calculateTax(double income) { System.out.println("PersonalTaxWithRebate"); double tax = income * 0.2; return tax; }} |
Теперь давайте объединим все классы и интерфейсы, определенные, чтобы использовать возможности паттерна Стратегия. Пусть основной метод выступает в качестве контекста для различных стратегий. Посмотрите только один пример взаимодействия всех этих классов:
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
|
import java.util.Arrays;import java.util.List;public class TaxStrategyMain { public static void main(String [] args) { //Create a List of Tax strategies for different scenarios List<TaxStrategy> taxStrategyList = Arrays.asList( new PersonalTaxStrategy(), new PersonalTaxPenaltyStrategy(), new PersonalTaxRebateStrategy()); //Calculate Tax for different scenarios with corresponding strategies for (TaxStrategy taxStrategy : taxStrategyList) { System.out.println(taxStrategy.calculateTax(30000.0)); } }} |
Запуск этого дает следующий вывод:
|
1
|
PersonalTax |
|
1
|
9000.0 |
|
1
|
PersonalTaxWithPenalty |
|
1
|
12000.0 |
|
1
|
PersonalTaxWithRebate |
|
1
|
6000.0 |
Это ясно демонстрирует, как различные налоговые ставки могут быть рассчитаны с использованием соответствующего класса конкретной стратегии. Я попытался объединить все конкретные стратегии (алгоритмы) в списке, а затем получить к ним доступ, перебирая список.
То, что мы видели до сих пор, это просто стандартный шаблон стратегии, и он существует уже давно. В наше время, когда функциональное программирование является новым модным словом, можно подумать о поддержке лямбда-выражений в Java, можно ли сделать что-то по-другому? Действительно, поскольку интерфейс стратегии похож на функциональный интерфейс, мы можем перефразировать, используя лямбда-выражения в Java. Давайте посмотрим, как выглядит код:
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
|
import java.util.Arrays;import java.util.List;public class TaxStrategyMainWithLambda { public static void main(String [] args) { //Create a List of Tax strategies for different scenarios with inline logic using Lambda List<TaxStrategy> taxStrategyList = Arrays.asList( (income) -> { System.out.println("PersonalTax"); return 0.30 * income; }, (income) -> { System.out.println("PersonalTaxWithPenalty"); return 0.40 * income; }, (income) -> { System.out.println("PersonalTaxWithRebate"); return 0.20 * income; } ); //Calculate Tax for different scenarios with corresponding strategies taxStrategyList.forEach((strategy) -> System.out.println(strategy.calculateTax(30000.0))); }} |
Запуск этого дает похожий вывод:
|
1
|
PersonalTax |
|
1
|
9000.0 |
|
1
|
PersonalTaxWithPenalty |
|
1
|
12000.0 |
|
1
|
PersonalTaxWithRebate |
|
1
|
6000.0 |
Мы видим, что использование лямбда-выражений делает ненужными дополнительные классы для конкретных стратегий. Вам не нужны дополнительные занятия; просто укажите дополнительное поведение с помощью лямбда-выражения.
- Все фрагменты кода доступны из моего репозитория github.
| Ссылка: | Java 8 лямбда-выражение для шаблонов проектирования — шаблон разработки стратегии от нашего партнера по JCG Гурприта Сачдева в блоге gssachdeva . |
