Что такое структурные паттерны проектирования? Приведи пример паттерна Адаптер.

Ответ

Структурные паттерны — это паттерны проектирования, которые описывают способы компоновки объектов и классов в более крупные, гибкие и эффективные структуры, сохраняя при этом их расширяемость.

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

Аналогия: Переходник с USB-C на USB-A позволяет новому ноутбуку работать со старой флешкой.

Пример реализации в Java:

// 1. Целевой интерфейс, который ожидает клиент (USB-порт)
interface UsbConnector {
    void connectUsb();
}

// 2. Адаптируемый класс со своим специфическим интерфейсом (старая флешка с USB-A)
class LegacyUsbPort {
    public void plugIn() {
        System.out.println("Legacy USB device connected.");
    }
}

// 3. Адаптер. Реализует целевой интерфейс и содержит ссылку на адаптируемый объект.
class UsbAdapter implements UsbConnector {
    private LegacyUsbPort legacyPort;

    public UsbAdapter(LegacyUsbPort legacyPort) {
        this.legacyPort = legacyPort;
    }

    @Override
    public void connectUsb() {
        // Адаптер «переводит» вызов connectUsb() в вызов plugIn()
        legacyPort.plugIn();
    }
}

// 4. Клиентский код, который работает только с целевым интерфейсом
public class ModernLaptop {
    public void useDevice(UsbConnector connector) {
        connector.connectUsb();
    }

    public static void main(String[] args) {
        ModernLaptop laptop = new ModernLaptop();
        LegacyUsbPort oldFlashDrive = new LegacyUsbPort();

        // Используем адаптер для подключения старого устройства
        UsbConnector adapter = new UsbAdapter(oldFlashDrive);
        laptop.useDevice(adapter); // Вывод: "Legacy USB device connected."
    }
}

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

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

Ответ 18+ 🔞

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

Вот смотри, первый на очереди — Адаптер. Представь себе такую хуйню: у тебя есть новый ноутбук, весь такой блядский, с USB-C, а флешка — старая, с USB-A, как кирпич. И что, выкидывать её? Не, чувак, ты берёшь переходник — вот это и есть адаптер, сука! Он делает вид, что он USB-C, а внутри него спрятана старая разъёбина, и всё работает. В рот меня чих-пых, гениально же!

В коде это выглядит примерно так, смотри, не зевай:

// 1. Это то, что твой новый код хочет видеть (USB-C порт, блядь)
interface UsbConnector {
    void connectUsb();
}

// 2. А это старая хрень, которая у тебя уже есть (флешка-кирпич с USB-A)
class LegacyUsbPort {
    public void plugIn() {
        System.out.println("Legacy USB device connected.");
    }
}

// 3. А вот и наш герой — ПЕРЕХОДНИК, ёбаный адаптер!
class UsbAdapter implements UsbConnector {
    private LegacyUsbPort legacyPort; // Внутри него спрятана старая штука

    public UsbAdapter(LegacyUsbPort legacyPort) {
        this.legacyPort = legacyPort;
    }

    @Override
    public void connectUsb() {
        // А тут магия: он кричит "connectUsb!", а сам внутри делает "plugIn!"
        legacyPort.plugIn(); // Переводчик, блядь, между двумя мирами!
    }
}

// 4. А это ты, со своим новым ноутом, который нихуя не понимает в старье
public class ModernLaptop {
    public void useDevice(UsbConnector connector) {
        connector.connectUsb();
    }

    public static void main(String[] args) {
        ModernLaptop laptop = new ModernLaptop();
        LegacyUsbPort oldFlashDrive = new LegacyUsbPort(); // Вот она, древность

        // Берём адаптер, натягиваем его на старую флешку как презерватив
        UsbConnector adapter = new UsbAdapter(oldFlashDrive);
        laptop.useDevice(adapter); // И вуаля — работает! Вывод: "Legacy USB device connected."
    }
}

Так когда же эту штуку впендюривать?

  • Когда тебе нужно впихнуть старый, легаси-код, написанный ещё при царе Горохе, в свою новую, блестящую систему. Чтобы не переписывать всё, блядь, с нуля.
  • Когда используешь какую-то библиотеку от чуваков, у которых API кривой, как рога барана, а твой код хочет общаться красиво.
  • Когда нужно сделать одного общего утконоса из кучи разных классов, которые говорят на разных языках. Адаптер — он как переводчик-синхронист, только для объектов, ёпта!