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-запрос:
- Сначала
SecurityMiddlewareпроверяет HTTPS. - Потом
SessionMiddlewareищет куки сессии. - Потом
AuthenticationMiddlewareищет пользователя. - И только в конце управление доходит до вашего
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. Мы просто "замораживаем" объект в байты и сохраняем.
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ