В чем заключается суть паттерна проектирования Декоратор

Ответ

Декоратор — это структурный паттерн проектирования, который позволяет динамически добавлять новую функциональность объектам, оборачивая их в специальные классы-обертки.

Основная идея — следование принципу открытости/закрытости: можно расширять поведение объекта, не изменяя его исходный код.

Как это работает

  1. Создается интерфейс, общий для «декорируемого» объекта и «декоратора».
  2. Класс-декоратор содержит ссылку на декорируемый объект.
  3. Декоратор выполняет свою дополнительную логику до или после вызова метода оригинального объекта.

Пример в Python

В Python идея декоратора элегантно реализуется через синтаксис @, который чаще всего применяется к функциям.

import functools
import time

# Декоратор для измерения времени выполнения функции
def timer(func):
    @functools.wraps(func)  # Сохраняет метаданные (имя, docstring) исходной функции
    def wrapper(*args, **kwargs):
        start_time = time.perf_counter()
        result = func(*args, **kwargs)
        end_time = time.perf_counter()
        run_time = end_time - start_time
        print(f"Функция '{func.__name__}' выполнилась за {run_time:.4f} с")
        return result
    return wrapper

@timer
def process_data(data):
    """Имитирует долгую обработку данных."""
    time.sleep(1)
    return f"Обработано {len(data)} элементов"

print(process_data([1, 2, 3]))
# Вывод:
# Функция 'process_data' выполнилась за 1.0012 с
# Обработано 3 элементов

Основные преимущества

  • Гибкость: Функциональность можно добавлять и убирать во время выполнения.
  • Компонуемость: Декораторы можно применять цепочкой, комбинируя их поведение.
  • Избегание наследования: Позволяет избежать создания множества подклассов для каждой комбинации поведений.

Ответ 18+ 🔞

Давай разберёмся с этим декоратором, а то народ его как будто в первый раз видит, блядь. Ну, паттерн такой, сука, структурный. Представь, что у тебя есть объект — ну, как есть, простой, голый, без изысков. А тебе надо ему на лету, ёпта, новую фичу прикрутить. Не лезть же в его кишки, переписывать код? Вот для этого и нужен декоратор, хитрая жопа.

Работает он по принципу «открытости/закрытости», что в переводе на русский значит: «расширяй, но не трогай то, что уже работает, а то сломаешь, мудак». Суть проста, как три копейки:

  1. Берёшь интерфейс, общий для всех — и для того, кого декорируешь, и для самой обёртки.
  2. Класс-декоратор — он как хитрая куртка. Внутри у него ссылка на тот самый объект, который он оборачивает.
  3. И вот когда вызываешь метод, декоратор сначала делает своё дело (или после), а потом уже передаёт управление дальше, тому, кто внутри.

А в Python, блядь, это вообще красота, потому что для функций есть специальный синтаксис @. Смотри, как это выглядит на практике, без всякой воды.

import functools
import time

# Декоратор, который засекает время, как часы с кукушкой, блядь
def timer(func):
    @functools.wraps(func)  # Эта штука сохраняет имя и описание оригинальной функции, а то всё потеряется, ёпта
    def wrapper(*args, **kwargs):
        start_time = time.perf_counter()
        result = func(*args, **kwargs)  # А вот тут вызывается сама функция, которую мы обернули
        end_time = time.perf_counter()
        run_time = end_time - start_time
        print(f"Функция '{func.__name__}' выполнилась за {run_time:.4f} с")
        return result
    return wrapper

@timer  # Вешаем наш секундомер на функцию — и всё, пиздец, теперь она под наблюдением
def process_data(data):
    """Имитирует долгую обработку данных."""
    time.sleep(1)
    return f"Обработано {len(data)} элементов"

print(process_data([1, 2, 3]))
# Вывод:
# Функция 'process_data' выполнилась за 1.0012 с
# Обработано 3 элементов

Видишь? Написали один раз timer, и теперь на любую функцию можно нацепить этот @timer, и она автоматом будет отчитываться, сколько там возилась. Красота, ёперный театр!

Чем это, блядь, хорошо?

  • Гибкость, овердохуища: Добавляй и снимай функциональность прямо на ходу, как перчатки.
  • Компонуемость: Их можно, сука, цеплять друг на друга, как матрёшек. @декоратор1 @декоратор2 def func() — и поехали.
  • Не надо плодить наследников: А то будешь как дурак создавать класс КлассСФичейА, КлассСФичейБ, КлассСФичамиАиБ, а потом ещё и КлассСФичамиАБиВ. Пиздец, а не иерархия. А тут — обернул и пошёл.

Вот и весь сказ, блядь. Не такой уж он и страшный, этот декоратор. Главное — понять принцип обёртки, а дальше — только твоя фантазия ограничивает, что можно накрутить.