← Назад к вопросам

Как реализовать паттерн Декоратор в PHP?

1.6 Junior🔥 231 комментариев
#PHP Core

Комментарии (1)

🐱
deepseek-v3.2PrepBro AI7 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Реализация паттерна Декоратор в PHP

Паттерн Декоратор (Decorator) — это структурный паттерн проектирования, который позволяет динамически добавлять объектам новую функциональность, оборачивая их в полезные «обёртки». Это гибкая альтернатива наследованию для расширения функциональности.

Базовые концепции

Основная идея декоратора заключается в создании цепочки объектов, где каждый последующий декоратор добавляет свою функциональность к предыдущему. Все декораторы реализуют тот же интерфейс, что и исходный объект, что позволяет им быть взаимозаменяемыми.

Ключевые компоненты

  1. Интерфейс Компонента — определяет общий интерфейс для всех компонентов
  2. Конкретный Компонент — исходный объект, который нужно декорировать
  3. Базовый Декоратор — абстрактный класс, реализующий тот же интерфейс
  4. Конкретные Декораторы — добавляют конкретную функциональность

Пример реализации

<?php

// 1. Интерфейс Компонента
interface NotifierInterface
{
    public function send(string $message): string;
}

// 2. Конкретный Компонент
class EmailNotifier implements NotifierInterface
{
    public function send(string $message): string
    {
        return "Отправка email: $message";
    }
}

// 3. Базовый Декоратор
abstract class NotifierDecorator implements NotifierInterface
{
    protected NotifierInterface $notifier;
    
    public function __construct(NotifierInterface $notifier)
    {
        $this->notifier = $notifier;
    }
    
    public function send(string $message): string
    {
        return $this->notifier->send($message);
    }
}

// 4. Конкретные Декораторы
class SMSDecorator extends NotifierDecorator
{
    public function send(string $message): string
    {
        $baseResult = parent::send($message);
        return $baseResult . "\nОтправка SMS: $message";
    }
}

class SlackDecorator extends NotifierDecorator
{
    public function send(string $message): string
    {
        $baseResult = parent::send($message);
        return $baseResult . "\nОтправка в Slack: $message";
    }
}

class LoggingDecorator extends NotifierDecorator
{
    public function send(string $message): string
    {
        $result = parent::send($message);
        $logMessage = "Логирование: " . date('Y-m-d H:i:s') . " - $message";
        return $result . "\n$logMessage";
    }
}

// Использование
$notifier = new EmailNotifier();

// Добавляем функциональность динамически
$notifier = new SMSDecorator($notifier);
$notifier = new SlackDecorator($notifier);
$notifier = new LoggingDecorator($notifier);

echo $notifier->send("Важное уведомление!");

Преимущества паттерна Декоратор

  • Гибкость: Можно динамически добавлять и комбинировать функциональность
  • Соблюдение принципа открытости/закрытости: Классы открыты для расширения, но закрыты для изменений
  • Избегание взрывного роста классов: Не нужно создавать множественные подклассы для каждой комбинации функциональности
  • Принцип единой ответственности: Каждый декоратор отвечает за одну конкретную задачу

Отличия от других паттернов

В отличие от Наследования:

  • Декоратор позволяет изменять поведение объектов во время выполнения
  • Не создаёт жесткой иерархии классов
  • Более гибкая композиция функциональности

В отличие от Цепочки обязанностей:

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

Практические примеры использования в PHP

  1. Обработка HTTP-запросов и ответов:
interface ResponseInterface {
    public function send(): string;
}

class JsonResponseDecorator implements ResponseInterface {
    private ResponseInterface $response;
    
    public function send(): string {
        $data = $this->response->send();
        return json_encode(['data' => $data, 'timestamp' => time()]);
    }
}
  1. Кэширование:
class CacheDecorator implements DataProviderInterface {
    private DataProviderInterface $provider;
    private CacheInterface $cache;
    
    public function getData(string $key): array {
        if ($this->cache->has($key)) {
            return $this->cache->get($key);
        }
        
        $data = $this->provider->getData($key);
        $this->cache->set($key, $data);
        return $data;
    }
}
  1. Валидация и фильтрация:
class SanitizeDecorator implements InputInterface {
    private InputInterface $input;
    
    public function getValue(): string {
        $value = $this->input->getValue();
        return htmlspecialchars(strip_tags(trim($value)));
    }
}

Рекомендации по использованию

  • Используйте декоратор, когда нужно добавлять обязанности объектам динамически и прозрачно
  • Избегайте создания слишком длинных цепочек декораторов
  • Убедитесь, что декораторы действительно независимы друг от друга
  • Помните о принципе подстановки Барбары Лисков — декоратор должен быть полностью взаимозаменяем с исходным компонентом

Паттерн Декоратор особенно полезен в PHP-приложениях для реализации middleware, обработчиков событий, систем кэширования и логгирования, где требуется гибкая композиция поведения без изменения исходного кода.

Как реализовать паттерн Декоратор в PHP? | PrepBro