JavaRush /Курсы /Architecture & Logic /Поведенческие паттерны, часть 2

Поведенческие паттерны, часть 2

Architecture & Logic
2 уровень , 1 лекция
Открыта

State

Состояние — паттерн, который позволяет объекту изменять свое поведение при изменении его внутреннего состояния. Извне кажется, что изменился класс объекта.

    stateDiagram-v2
        [*] --> Draft
        Draft --> Moderation : send_to_review()
        Moderation --> Published : approve()
        Moderation --> Draft : reject()
        Published --> [*]

        note right of Draft
            В черновике нельзя
            публиковать напрямую.
        end note
    

Представьте документ. В состоянии Draft метод publish() отправляет его на модерацию. В состоянии Moderation этот же метод может выкинуть ошибку "Уже на проверке". А в Published — ничего не сделает.

Суть паттерна.

Вместо огромного if-elif-else (если статус такой-то, делай то-то), мы выносим поведение каждого состояния в отдельный класс. Объект документа просто хранит ссылку на текущее состояние self.state и делегирует ему работу.

Python-way: в простых случаях достаточно библиотеки django-fsm или простого поля status в модели. Полноценные классы-состояния нужны, когда логика переходов очень сложная.

Strategy

Стратегия — паттерн, который определяет семейство алгоритмов, инкапсулирует их и делает взаимозаменяемыми. Это позволяет выбирать алгоритм "на лету", не меняя код, который его использует.

    classDiagram
        direction LR
        class Context {
            -strategy
            +set_strategy(s)
            +execute()
        }
        class PaymentStrategy {
            <<Interface>>
            +pay(amount)
        }
        class PayPal {
            +pay(amount)
        }
        class CreditCard {
            +pay(amount)
        }

        Context o-- PaymentStrategy
        PayPal ..|> PaymentStrategy
        CreditCard ..|> PaymentStrategy
    

Пример

Оплата в интернет-магазине. Пользователь выбирает PayPal или Карту. Код оформления заказа один и тот же, меняется только объект стратегии оплаты.

Функции как стратегии

В классическом ООП вы обязаны создавать классы PayPalStrategy, CardStrategy. В Python функции — это объекты. Вы можете просто передать функцию сортировки или оплаты как аргумент:

# Вместо классов
def pay_by_paypal(amount): ...
def pay_by_card(amount): ...

# Использование
process_payment(100, strategy=pay_by_paypal)

Вспомните стандартную функцию sorted(data, key=...). Аргумент key — это и есть Стратегия выбора ключа сортировки.

Template Method

Шаблонный метод — паттерн, который определяет скелет алгоритма в суперклассе, но позволяет подклассам переопределять конкретные шаги этого алгоритма без изменения его структуры.

    classDiagram
        direction BT
        class DataMiner {
            +mine()
            #open_file()
            #extract_data()
            #parse_data()
            #close_file()
        }
        class PDFMiner {
            #extract_data()
            #parse_data()
        }
        class CSVMiner {
            #extract_data()
            #parse_data()
        }

        PDFMiner --|> DataMiner
        CSVMiner --|> DataMiner
        note for DataMiner "Метод mine() вызывает шаги:
open -> extract -> parse -> close.
Это и есть шаблон."

Это классическое наследование. Вы пишете базовый класс с общей логикой ("открыть файл, прочитать, закрыть"), а специфичные части ("как именно читать PDF") оставляете абстрактными методами, которые реализуют дети.

В Python: aктивно используется в фреймворках. Например, Django Class-Based Views. Метод dispatch() — это шаблонный метод, который вызывает get() или post() в зависимости от запроса.

Chain of Responsibility

Цепочка обязанностей — паттерн, позволяющий передавать запрос по цепочке потенциальных обработчиков, пока один из них не обработает запрос.

    sequenceDiagram
        participant Client
        participant AuthMiddleware
        participant LogMiddleware
        participant View

        Client->>AuthMiddleware: Запрос /profile
        alt Не авторизован
            AuthMiddleware-->>Client: 403 Forbidden
        else Авторизован
            AuthMiddleware->>LogMiddleware: Передает дальше
            LogMiddleware->>View: Передает дальше
            View-->>LogMiddleware: Ответ HTML
            LogMiddleware-->>AuthMiddleware: Ответ HTML
            AuthMiddleware-->>Client: Ответ HTML
        end
    

Python-way: Middleware!

Вам не нужно искать абстрактные примеры. Django Middleware и FastAPI Dependencies — это и есть реализация Цепочки обязанностей.

Когда приходит HTTP-запрос:

  1. Сначала SecurityMiddleware проверяет HTTPS.
  2. Потом SessionMiddleware ищет куки сессии.
  3. Потом AuthenticationMiddleware ищет пользователя.
  4. И только в конце управление доходит до вашего View.

Каждое звено может либо передать запрос дальше, либо вернуть ответ (прервать цепочку).

Memento

Хранитель — паттерн, который позволяет сохранить и восстановить прошлое состояние объекта, не раскрывая подробностей его реализации.

    classDiagram
        direction LR
        class Editor {
            -content
            +make_snapshot()
            +restore(snapshot)
        }
        class Snapshot {
            -state
            +get_state()
        }
        class History {
            -snapshots: list
            +push(s)
            +pop()
        }

        Editor ..> Snapshot : Создает
        History o-- Snapshot : Хранит
    

Это кнопка "Undo" Ctrl+Z в вашем редакторе. Редактор создает снимок перед каждым действием. История хранит стопку этих снимков. Если вы ошиблись, вы достаете последний снимок и восстанавливаете состояние.

В Python часто реализуется через сериализацию модуль pickle, json или deepcopy. Мы просто "замораживаем" объект в байты и сохраняем.

Комментарии
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ