Паттерн Strategy
Часть раздела Объектно-ориентированное программирование путешествия по Java на Coddy. Урок 69 из 87.
Паттерн «Стратегия» — это поведенческий паттерн проектирования, который позволяет определить семейство алгоритмов, инкапсулировать каждый из них в собственном class и сделать их взаимозаменяемыми. Вместо жёсткого задания конкретного поведения вы можете менять алгоритмы во время выполнения, не изменяя код, который их использует.
Представьте платёжную систему, которая поддерживает несколько способов оплаты. Без паттерна «Стратегия» у вас в итоге была бы запутанная условная логика. С ним каждый способ оплаты становится собственной стратегией:
interface PaymentStrategy {
void pay(int amount);
}
class CreditCardPayment implements PaymentStrategy {
public void pay(int amount) {
System.out.println("Paid " + amount + " via Credit Card");
}
}
class PayPalPayment implements PaymentStrategy {
public void pay(int amount) {
System.out.println("Paid " + amount + " via PayPal");
}
}Класс context хранит ссылку на стратегию и делегирует ей выполнение работы. Главное заключается в том, что context не знает, какую конкретную стратегию он использует. Он знает только интерфейс:
class ShoppingCart {
private PaymentStrategy paymentStrategy;
public void setPaymentStrategy(PaymentStrategy strategy) {
this.paymentStrategy = strategy;
}
public void checkout(int amount) {
paymentStrategy.pay(amount);
}
}Теперь вы можете динамически изменять поведение оплаты:
ShoppingCart cart = new ShoppingCart();
cart.setPaymentStrategy(new CreditCardPayment());
cart.checkout(100); // Оплачено 100 через Credit Card
cart.setPaymentStrategy(new PayPalPayment());
cart.checkout(50); // Оплачено 50 через PayPalШаблон Strategy особенно полезен, когда у вас есть несколько способов выполнить действие и вы хотите легко переключаться между ними. Добавление нового способа оплаты означает просто создание нового класса, который реализует PaymentStrategy: изменения в существующем коде не требуются.
Задание
ЛегкоДавайте создадим систему форматирования текста с использованием паттерна Strategy! Вы создадите систему, в которой различные стратегии форматирования можно заменять во время выполнения, чтобы преобразовывать текст различными способами — это идеально подходит для приложения, которому требуется поддержка нескольких выходных форматов.
Вы организуете код в четырёх файлах:
TextFormatter.java: Define интерфейсTextFormatter, который будут implement все стратегии форматирования. Он должен declare единственный методString format(String text), который принимает строку и возвращает отформатированную версию.Formatters.java: Create три concrete стратегии, которые implement ваш интерфейсTextFormatter:UpperCaseFormatter— преобразует текст так, чтобы все буквы стали прописными.LowerCaseFormatter— преобразует текст так, чтобы все буквы стали строчными.TitleCaseFormatter— capitalizes первую букву каждого слова, а остальные буквы делает строчными. Слова разделяются пробелами.TextEditor.java: Create контекстный класс, который использует стратегию форматирования. ВашTextEditorдолжен иметь:Приватное поле для хранения current стратегии
TextFormatter.Метод
setFormatter(TextFormatter formatter), который changes active стратегию форматирования.Метод
publishText(String text), который применяет current formatter к тексту и выводитPublished: [formatted text]. Если formatter не был установлен, он должен без изменений вывестиPublished: [original text].Main.java: Объедините свою систему стратегий! Вы получите два входных значения: текст для форматирования (String) и стиль форматирования (String:"upper","lower"или"title").Create
TextEditorи сначала CallpublishTextс вашим входным текстом, не устанавливая formatter (это демонстрирует поведение по умолчанию).Затем на Based на входном стиле установите appropriate стратегию форматирования и снова Call
publishTextс тем же текстом, чтобы показать отформатированный результат.
Вы получите два входных значения по порядку: текст для форматирования (String) и стиль форматирования (String).
Например, при входных значениях hello world и title результатом будет:
Published: hello world
Published: Hello WorldОбратите внимание, что TextEditor ничего не знает о конкретной логике форматирования. Он просто делегирует работу той стратегии, которая в данный момент установлена. Благодаря этому добавлять новые стили форматирования, не затрагивая код редактора, становится очень просто!
Попробуйте сами
import java.util.Scanner;
class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
String text = scanner.nextLine();
String style = scanner.nextLine();
// TODO: Создайте экземпляр TextEditor
// TODO: Вызовите publishText с входным текстом (до установки какого-либо formatter)
// TODO: В зависимости от введённого стиля ("upper", "lower" или "title"),
// установите соответствующий formatter и снова вызовите publishText
}
}В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.
Все уроки раздела Объектно-ориентированное программирование
1Основы ООП
Внешние файлыВведение в ООПКлассы и объектыКлючевое слово thisМетодыПоля (атрибуты)Метод-конструкторПерегрузка конструкторовИтоги — Простой калькулятор4Наследование
Основы наследования (extends)Ключевое слово superПереопределение методов (@Override)Цепочка конструкторовКласс ObjectОдиночное и многоуровневое наследованиеПочему нет множественного наследования классовИтоги — Иерархия сотрудников7Специальные методы и класс Object
Метод toString()equals() и hashCode()Метод clone()compareTo() и ComparableИнтерфейс ComparatorПовторение — Кастомная сортировка2Модификаторы доступа и инкапсуляция
Обзор уровней доступаМетоды геттеры и сеттерыСокрытие данныхКлючевое слово finalИтоги — Менеджер банковского счета5Полиморфизм
Основы перегрузки методовПереопределение методов (Run-Time)Upcasting и DowncastingОператор instanceofАбстрактные классы и методыИтоги: Калькулятор фигур8Продвинутые концепции ООП
Композиция против наследованияАгрегация против композицииВнутренние, вложенные и анонимные классыEnums и методы перечисленийRecords (Java 16+)Sealed-классы (Java 17+)11Паттерны проектирования. Часть 1
Введение в паттерны проектированияПаттерн SingletonПаттерн FactoryПаттерн BuilderПаттерн ObserverПаттерн Strategy3Свойства класса и статические члены
Переменные экземпляра и статические переменныеСтатические методыСтатические блокиКонстанты (static final)Итоги: Счетчик и утилиты6Интерфейсы и абстрактные классы
Введение в интерфейсыРеализация интерфейсовРеализация нескольких интерфейсовDefault и Static методы в интерфейсахАбстрактные классы vs ИнтерфейсыФункциональные интерфейсыИтоги — Платежная система9Обобщения
Введение в обобщенияОбобщенные классыОбобщенные методыОграниченные параметры типаСимволы подстановки (Wildcards: ?, extends, super)Итоги — Обобщенный контейнер12Паттерны проектирования. Часть 2
Паттерн «Команда»Паттерн «Адаптер»Паттерн «Декоратор»Паттерн «Шаблонный метод»Паттерн «Состояние»Паттерн «Компоновщик»Паттерн «Итератор»Потренируйтесь самостоятельно: Онлайн-компилятор Java