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

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

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

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
    

Пример: форма регистрации. У вас есть чекбокс "Я согласен" и кнопка "Отправить".

  • Без посредника чекбокс должен знать про кнопку, чтобы активировать её. Кнопка должна знать про поля ввода, чтобы проверить их. Все связаны со всеми.
  • С посредником компоненты ничего не знают друг о друге. При клике чекбокс просто говорит Посреднику (форме): "Меня кликнули". Посредник решает, нужно ли активировать кнопку.
Комментарии
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ