Что такое паттерн Adapter и когда его применяют?

«Что такое паттерн Adapter и когда его применяют?» — вопрос из категории Паттерны, который задают на 10% собеседований Java Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Adapter (Адаптер) — это структурный паттерн проектирования, который позволяет объектам с несовместимыми интерфейсами работать вместе. Он выступает в роли «переводчика» или «обёртки», преобразуя интерфейс одного класса в интерфейс, ожидаемый клиентом.

Когда использовать:

  • Интеграция legacy-кода или сторонних библиотек, интерфейс которых нельзя изменить.
  • Необходимость использовать несколько классов с разными интерфейсами, но схожей функциональностью, через единый интерфейс.
  • Создание слоя совместимости между системами.

Реализация (пример на Java): Допустим, есть старый сервис отправки SMS и новый клиентский код, ожидающий современный интерфейс.

// 1. Старый класс (Adaptee), который нужно адаптировать
class LegacySmsSender {
    public void sendSms(String phoneNumber, String messageText) {
        System.out.println("[Legacy] Sending SMS to " + phoneNumber + ": " + messageText);
    }
}

// 2. Целевой интерфейс (Target), который ожидает клиент
interface ModernMessenger {
    void send(String recipient, String content);
}

// 3. Адаптер (Adapter) – реализует целевой интерфейс и содержит ссылку на Adaptee
class SmsAdapter implements ModernMessenger {
    private final LegacySmsSender legacySender;

    public SmsAdapter(LegacySmsSender legacySender) {
        this.legacySender = legacySender;
    }

    @Override
    public void send(String recipient, String content) {
        // Преобразование вызова нового интерфейса в старый
        legacySender.sendSms(recipient, content);
    }
}

// 4. Клиентский код
public class Client {
    public static void main(String[] args) {
        LegacySmsSender oldService = new LegacySmsSender();
        ModernMessenger messenger = new SmsAdapter(oldService); // Обёртка

        // Клиент работает через ModernMessenger, не зная о LegacySmsSender
        messenger.send("+79991234567", "Hello via Adapter!");
    }
}

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

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

Недостатки:

  • Усложняет код за счёт введения дополнительных классов. Следует применять обоснованно, а не для связи любых интерфейсов.