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

Ответ

Паттерн Адаптер (Adapter) преобразует интерфейс одного класса в интерфейс, ожидаемый клиентом. Он позволяет несовместимым классам работать вместе.

Пример: Интеграция старой системы логирования с новым интерфейсом приложения.

// 1. Целевой интерфейс, который ожидает клиент (новая система)
interface NewLogger {
    void logMessage(String message);
}

// 2. Адаптируемый класс (старая, несовместимая система)
class LegacyLogger {
    public void log(String msg, String level) {
        System.out.println("[" + level + "]: " + msg);
    }
}

// 3. Адаптер, реализующий целевой интерфейс и использующий старый класс
class LoggerAdapter implements NewLogger {
    private LegacyLogger legacyLogger;

    public LoggerAdapter(LegacyLogger logger) {
        this.legacyLogger = logger;
    }

    @Override
    public void logMessage(String message) {
        // Адаптация вызова: используем уровень по умолчанию для старого метода
        legacyLogger.log(message, "INFO");
    }
}

// 4. Использование клиентом
public class Client {
    public static void main(String[] args) {
        NewLogger logger = new LoggerAdapter(new LegacyLogger());
        logger.logMessage("Application started"); // Вывод: [INFO]: Application started
    }
}

Почему это полезно: Позволяет повторно использовать существующий код, не изменяя его, и соблюдает принцип открытости/закрытости (Open/Closed Principle).

Ответ 18+ 🔞

Да ты посмотри, какой прикольный паттерн — Адаптер! Это ж как переходник в розетку, блядь. У тебя есть старая, ебучка, система, которая работает по-своему, а новая требует другого интерфейса. И что, переписывать всё с нуля? Да хуй там! Берёшь этот адаптер, и он как мужик-переводчик между двумя бабами, которые друг друга не понимают: одной говорит одно, другой — другое, а в итоге все довольны и работа кипит.

Смотри, как это выглядит в коде, тут всё чётко:

// 1. Это наш новый, модный интерфейс, который все хотят видеть
interface NewLogger {
    void logMessage(String message);
}

// 2. А это старая система, которая орет как сумасшедшая на своём диалекте
class LegacyLogger {
    public void log(String msg, String level) {
        System.out.println("[" + level + "]: " + msg);
    }
}

// 3. И вот наш герой — Адаптер! Он надевает маску нового интерфейса, а внутри крутит старые шестерёнки
class LoggerAdapter implements NewLogger {
    private LegacyLogger legacyLogger;

    public LoggerAdapter(LegacyLogger logger) {
        this.legacyLogger = logger;
    }

    @Override
    public void logMessage(String message) {
        // А тут магия: новый вызов превращаем в старый, подсовывая дефолтный уровень
        legacyLogger.log(message, "INFO");
    }
}

// 4. Клиент, который даже не в курсе, что под капотом древний монстр
public class Client {
    public static void main(String[] args) {
        NewLogger logger = new LoggerAdapter(new LegacyLogger());
        logger.logMessage("Application started"); // И на тебе: [INFO]: Application started
    }
}

А полезность-то, блядь, в чём? Да в том, что ты не ломаешь старый, проверенный годами код, который, может, ещё и не твой был. Принцип открытости/закрытости, ёпта! Система открыта для расширения (новый адаптер прикрутил), но закрыта для изменений (старый код не тронул). Красота, да и только!