Menu
Coddy logo textTech

Паттерн 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: изменения в существующем коде не требуются.

challenge icon

Задание

Легко

Давайте создадим систему форматирования текста с использованием паттерна 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 и сначала Call publishText с вашим входным текстом, не устанавливая 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
        
    }
}
quiz iconПроверьте себя

В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.

Все уроки раздела Объектно-ориентированное программирование

Потренируйтесь самостоятельно: Онлайн-компилятор Java