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

Что такое паттерн Адаптер и когда его использовать?

1.0 Junior🔥 31 комментариев
#PHP Core

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

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

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

Что такое паттерн Адаптер (Adapter)?

Паттерн Адаптер — это структурный паттерн проектирования, который позволяет объектам с несовместимыми интерфейсами работать вместе. Он действует как "переходник" или "конвертер" между двумя классами или системами, преобразуя интерфейс одного класса в интерфейс, ожидаемый другим клиентом. Это похоже на адаптер питания, который позволяет устройству с одним типом разъема работать с розеткой другого стандарта.

Основная цель и концепция

Основная цель Адаптера — обеспечить совместимость без изменения исходного кода адаптируемого класса (Adaptee) или клиента (Client). Паттерн реализуется путем создания отдельного класса-адаптера, который "оборачивает" Adaptee и предоставляет нужный интерфейс.

Типы адаптеров

В практике существуют два основных типа:

  • Адаптер класса (Class Adapter): Использует наследование — адаптер наследует от Adaptee и целевого интерфейса (обычно через множественное наследование, что в PHP возможно только через интерфейсы/трэйты). Менее распространен в PHP.
  • Адаптер объекта (Object Adapter): Использует композицию — адаптер содержит объект Adaptee как свойство и реализует целевой интерфейс. Это более гибкий и часто используемый подход.

Когда использовать паттерн Адаптер?

Применение паттерна особенно полезно в следующих ситуациях:

  1. Интеграция сторонних библиотек или классов. Когда нужно использовать сторонний класс или библиотеку, но его интерфейс не соответствует вашей системе. Например, библиотека для работы с JSON имеет метод outputJson(), а ваша система ожидает метод renderData().
  2. Рефакторинг и поддержка легаси-кода. При необходимости использовать старый (legacy) класс в новой системе с современным интерфейсом без его переписывания.
  3. Создание унифицированного интерфейса для семейства классов. Если у вас несколько классов с похожей функциональностью, но разными методами, адаптер помогает создать для них единый контракт.
  4. Тестирование и создание mock-объектов. Адаптер может адаптировать реальный сложный объект к простому интерфейсу для удобного тестирования.
  5. Работа с различными API или форматами данных. Например, адаптация данных из внешнего API SOAP к внутреннему формату REST, или преобразование формата XML в JSON для внутренней обработки.

Пример реализации (Адаптер объекта) в PHP

Рассмотрим классический пример: у нас есть старая библиотека для отправки сообщений и новый интерфейс, которого ожидает система.

// Целевой интерфейс, которого ожидает клиент (наша система)
interface NotificationInterface {
    public function send(string $title, string $message): void;
}

// Старый класс (Adaptee), который мы хотим использовать, но его интерфейс не совпадает
class LegacyMailer {
    public function dispatchMail(string $subject, string $body, string $to): void {
        echo "LegacyMailer: Отправка письма '$subject' с текстом '$body' на адрес '$to'.\n";
        // Здесь реальная логика отправки...
    }
}

// Адаптер, который делает LegacyMailer совместимым с NotificationInterface
class MailerAdapter implements NotificationInterface {
    private LegacyMailer $legacyMailer;
    private string $defaultEmail;

    public function __construct(LegacyMailer $legacyMailer, string $defaultEmail) {
        $this->legacyMailer = $legacyMailer;
        $this->defaultEmail = $defaultEmail;
    }

    // Адаптируем метод send к методу dispatchMail
    public function send(string $title, string $message): void {
        $this->legacyMailer->dispatchMail($title, $message, $this->defaultEmail);
    }
}

// Клиентский код, который работает только с NotificationInterface
function notifyUser(NotificationInterface $notification, string $alert, string $text) {
    $notification->send($alert, $text);
}

// Использование
$oldMailer = new LegacyMailer();
$mailAdapter = new MailerAdapter($oldMailer, 'user@example.com');

// Клиент успешно работает с адаптером, не зная о существовании LegacyMailer
notifyUser($mailAdapter, "Важное обновление", "Система была успешно обновлена.");

Результат выполнения:

LegacyMailer: Отправка письма 'Важное обновление' с текстом 'Система была успешно обновлена.' на адрес 'user@example.com'.

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

Преимущества:

  • Отделение клиента от конкретной реализации. Клиент зависит только от абстрактного интерфейса.
  • Принцип открытости/закрытости. Система открыта для расширения (можно добавлять новые адаптеры), но закрыта для изменения клиентского кода.
  • Повышение переиспользуемости кода. Старые и сторонние классы можно интегрировать в новые системы.

Недостатки:

  • Увеличение сложности. Добавляются новые классы, что может сделать систему менее очевидной, если адаптеров слишком много.
  • Накладные расходы. Введение дополнительного слоя может немного снизить производительность (обычно незначительно).

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