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
Приклад: форма реєстрації. У вас є чекбокс «Я згоден» і кнопка «Надіслати».
- Без посередника: чекбокс повинен знати про кнопку, щоб активувати її. Кнопка повинна знати про поля введення, щоб перевірити їх. Усі пов'язані з усіма.
- З посередником: компоненти нічого не знають один про одного. При кліку чекбокс просто каже Посереднику (формі): «Мене клікнули». Посередник вирішує, чи потрібно активувати кнопку.
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ