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
    

Приклад: форма реєстрації. У вас є чекбокс «Я згоден» і кнопка «Надіслати».

  • Без посередника: чекбокс повинен знати про кнопку, щоб активувати її. Кнопка повинна знати про поля введення, щоб перевірити їх. Усі пов'язані з усіма.
  • З посередником: компоненти нічого не знають один про одного. При кліку чекбокс просто каже Посереднику (формі): «Мене клікнули». Посередник вирішує, чи потрібно активувати кнопку.
Коментарі
ЩОБ ПОДИВИТИСЯ ВСІ КОМЕНТАРІ АБО ЗАЛИШИТИ КОМЕНТАР,
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ