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

В чем разница между декоратором и адаптером?

2.0 Middle🔥 101 комментариев
#Архитектура и паттерны

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

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

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

Разница между декоратором и адаптером

В проектировании программного обеспечения, декоратор и адаптер — это два различных структурных паттерна, решающих разные задачи. Хотя оба работают с объектами, их цели, механизмы и результаты применения кардинально отличаются.

Основная цель

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

Принцип работы

Адаптер действует как "переводчик" между двумя несовместимыми интерфейсами. Он оборачивает целевой объект и предоставляет клиенту знакомый интерфейс, делегируя вызовы адаптируемому объекту. Например:

// Интерфейс, ожидаемый клиентом
interface DocumentReader {
    public function read(): string;
}

// Класс с несовместимым интерфейсом
class PdfParser {
    public function extractContent(): string {
        return "PDF content";
    }
}

// Адаптер
class PdfAdapter implements DocumentReader {
    private $pdfParser;

    public function __construct(PdfParser $pdfParser) {
        $this->pdfParser = $pdfParser;
    }

    public function read(): string {
        return $this->pdfParser->extractContent();
    }
}

// Клиентский код
$reader = new PdfAdapter(new PdfParser());
echo $reader->read(); // Работает через единый интерфейс

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

// Базовый интерфейс
interface Notification {
    public function send(): string;
}

// Конкретная реализация
class EmailNotification implements Notification {
    public function send(): string {
        return "Email sent.";
    }
}

// Декоратор
class SMSDecorator implements Notification {
    private $notification;

    public function __construct(Notification $notification) {
        $this->notification = $notification;
    }

    public function send(): string {
        $result = $this->notification->send();
        return $result . " SMS also sent.";
    }
}

// Использование
$notification = new SMSDecorator(new EmailNotification());
echo $notification->send(); // "Email sent. SMS also sent."

Ключевые отличия

  1. Изменение интерфейса:

    • Адаптер изменяет интерфейс объекта, чтобы сделать его совместимым с другим кодом.
    • Декоратор сохраняет интерфейс объекта, расширяя его функциональность.
  2. Цель применения:

    • Адаптер используется, когда нужно интегрировать старый или сторонний код в новую систему без изменения существующей кодовой базы.
    • Декоратор используется, когда нужно добавить новые возможности объекту во время выполнения, избегая создания множества подклассов.
  3. Архитектурный аспект:

    • Адаптер часто применяется на границах системы (работа с внешними API, библиотеками, устаревшим кодом).
    • Декоратор используется внутри системы для построения гибких иерархий объектов с комбинируемым поведением.
  4. Количество оберток:

    • Адаптер обычно не предполагает цепочки — один адаптер решает конкретную проблему совместимости.
    • Декораторы можно вкладывать друг в друга, создавая стек дополнительных поведений.

Пример из реальной практики в PHP

Представьте, что вы работаете с устаревшей библиотекой для кэширования, которая имеет метод getData($key), а ваша система ожидает интерфейс с методом retrieve(string $key): mixed. Здесь нужен адаптер.

Если же у вас есть базовый класс Logger, и вы хотите добавлять возможность логирования в файл, базу данных и отправку уведомлений администратору — здесь идеально подойдет декоратор, так как вы можете комбинировать эти возможности динамически.

Вывод

Выбор между адаптером и декоратором зависит от решаемой задачи:

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

Оба паттерна демонстрируют силу композиции над наследованием, но служат разным архитектурным целям в разработке масштабируемых и поддерживаемых PHP-приложений.