Iterator
Итератор — это поведенческий паттерн, который дает возможность последовательно обходить элементы составного объекта (коллекции), не раскрывая его внутреннего представления.
classDiagram
direction LR
class IterableCollection {
<<Interface>>
+create_iterator()
}
class Iterator {
<<Interface>>
+has_next()
+next()
}
class ConcreteCollection {
+create_iterator()
}
class ConcreteIterator {
-collection
-current_position
+has_next()
+next()
}
IterableCollection ..> Iterator : Creates
ConcreteCollection ..|> IterableCollection
ConcreteIterator ..|> Iterator
Протокол итерации и генераторы
В Python этот паттерн встроен в само сердце языка. Каждый раз, когда вы пишете цикл for x in my_list:, Python под капотом использует паттерн Итератор.
Вам не нужно создавать классы с методами has_next(). В Python:
- Любой объект, у которого есть метод
__iter__, является Iterable (по нему можно пройтись циклом). - Генераторы (yield) — это самый простой способ создать итератор. Вам не нужно писать класс, вы просто пишете функцию, которая "выдает" значения по одному.
Command
Команда — это паттерн, который превращает запрос или действие в объект. Это позволяет передавать действия как аргументы, ставить их в очередь, логировать и поддерживать отмену операций.
classDiagram
direction LR
class Invoker {
-command
+set_command()
+execute_command()
}
class Command {
<<Interface>>
+execute()
}
class SaveCommand {
+execute()
}
class Receiver {
+operation()
}
Invoker o-- Command
SaveCommand ..|> Command
SaveCommand --> Receiver : Calls operation
Python-way: функции — это объекты
В Java для передачи действия нужно создавать класс, реализующий интерфейс Command. В Python функции являются объектами первого класса.
- Простой случай: Часто вместо класса
Commandможно просто передать саму функцию (callback) в кнопку или обработчик. - Сложный случай (Celery): Если вы работали с очередями задач, то объект задачи (Task) в Celery — это и есть реализация паттерна Command. Он содержит всё необходимое для выполнения действия (имя функции, аргументы), может быть сериализован в БД и выполнен позже.
Observer
Наблюдатель — паттерн, который создает механизм подписки, позволяющий одним объектам (наблюдателям) следить за изменениями других объектов (субъектов) и реагировать на них.
classDiagram
direction LR
class Publisher {
-subscribers: list
+subscribe(s)
+unsubscribe(s)
+notify()
}
class Subscriber {
<<Interface>>
+update(context)
}
class EmailAlert {
+update(context)
}
class Logger {
+update(context)
}
Publisher o-- Subscriber
EmailAlert ..|> Subscriber
Logger ..|> Subscriber
Классический пример: канал на YouTube. Когда выходит новое видео (событие у Publisher), всем подписчикам приходит уведомление.
Python-way: Django Signals
Если вы писали на Django, вы использовали этот паттерн. Django Signals (post_save, pre_delete) — это реализация Observer.
- Publisher модель User (отправляет сигнал при сохранении).
- Subscriber функция
create_profile(слушает сигнал и создает профиль).
Visitor
Посетитель — паттерн, который позволяет добавить новую операцию для целой иерархии классов, не изменяя код этих классов. Мы выносим алгоритм в отдельный класс-посетитель.
classDiagram
direction LR
class Visitor {
<<Interface>>
+visit_dot(d)
+visit_circle(c)
}
class ExportToXML {
+visit_dot(d)
+visit_circle(c)
}
class Shape {
<<Interface>>
+accept(v)
}
class Circle {
+accept(v)
}
Circle ..|> Shape
ExportToXML ..|> Visitor
Circle --> Visitor : v.visit_circle(self)
Этот паттерн часто используется при работе с деревьями. Например, стандартный модуль Python ast (Abstract Syntax Tree) использует NodeVisitor. Вы можете написать класс, который пробежится по коду Python и найдет все переменные с именем x, не меняя сам код парсера.
Mediator
Посредник — паттерн, который уменьшает хаотичные связи между множеством объектов. Вместо того чтобы все общались со всеми, они общаются только с Посредником.
classDiagram
direction TB
class Mediator {
<<Interface>>
+notify(sender, event)
}
class Dialog {
+notify(sender, event)
}
class Checkbox {
+click()
}
class Button {
+click()
}
Checkbox --> Mediator
Button --> Mediator
Dialog ..|> Mediator
Пример: форма регистрации. У вас есть чекбокс "Я согласен" и кнопка "Отправить".
- Без посредника чекбокс должен знать про кнопку, чтобы активировать её. Кнопка должна знать про поля ввода, чтобы проверить их. Все связаны со всеми.
- С посредником компоненты ничего не знают друг о друге. При клике чекбокс просто говорит Посреднику (форме): "Меня кликнули". Посредник решает, нужно ли активировать кнопку.
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ