Что такое шаблон проектирования Bridge (Мост)?

Ответ

Bridge — это структурный шаблон проектирования, который разделяет абстракцию (интерфейс или высокоуровневую логику) и её реализацию (низкоуровневые детали) в отдельные иерархии классов. Это позволяет изменять их независимо друг от друга, используя композицию вместо наследования.

Проблема, которую решает Мост: Избежать «разбухания» класса из-за комбинаторного взрыва подклассов (например, CircleRed, CircleBlue, SquareRed, SquareBlue).

Ключевые компоненты:

  • Abstraction (Абстракция): Определяет высокоуровневый интерфейс и содержит ссылку на объект Implementor.
  • RefinedAbstraction (Уточнённая абстракция): Расширяет интерфейс, определённый Abstraction.
  • Implementor (Реализатор): Определяет интерфейс для низкоуровневых операций.
  • ConcreteImplementor (Конкретный реализатор): Содержит конкретную реализацию интерфейса Implementor.

Пример: Фигуры и цвета

// 1. Иерархия Реализации (Цвета)
interface Color {
    String fill();
}

class Red implements Color {
    @Override
    public String fill() { return "красным"; }
}

class Blue implements Color {
    @Override
    public String fill() { return "синим"; }
}

// 2. Иерархия Абстракции (Фигуры)
abstract class Shape {
    protected Color color; // Композиция! Мост между абстракцией и реализацией

    public Shape(Color color) { this.color = color; }

    abstract String draw();
}

class Circle extends Shape {
    public Circle(Color color) { super(color); }

    @Override
    public String draw() {
        return "Рисую круг, залитый " + color.fill();
    }
}

class Square extends Shape {
    public Square(Color color) { super(color); }

    @Override
    public String draw() {
        return "Рисую квадрат, залитый " + color.fill();
    }
}

// Использование
Color red = new Red();
Shape redCircle = new Circle(red);
System.out.println(redCircle.draw()); // Рисую круг, залитый красным

Shape blueSquare = new Square(new Blue());
System.out.println(blueSquare.draw()); // Рисую квадрат, залитый синим

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

  • Разделение ответственности: Абстракция и реализация развиваются независимо.
  • Принцип открытости/закрытости: Можно добавлять новые абстракции и реализации, не меняя существующий код.
  • Сокрытие деталей реализации от клиентского кода.

Применение: Драйверы устройств, GUI-фреймворки (отделение платформо-зависимой части), API, работающие с разными типами баз данных.

Ответ 18+ 🔞

Ну вот, сидишь ты, такой весь из себя архитектор, пишешь свой код. Всё вроде красиво: есть у тебя Circle, есть Square. И тут бац — тебе говорят: «А сделай-ка их ещё и красными, и синими». Ну, думаешь, ерунда, щас наследуемся: RedCircle, BlueCircle, RedSquare, BlueSquare. А потом приходят и говорят: «А ещё есть прозрачность, а ещё есть градиент, а ещё есть, блядь, текстура „под старый дуб“». И вот ты уже сидишь с сотней классов, у которых в названии вся твоя еб*ная жизнь не помещается. Это, дружок, и есть тот самый комбинаторный взрыв, от которого волосы дыбом и терпения — ноль, ебать.

Так вот, чтобы не сойти с ума, умные дядьки придумали Мост (Bridge). Суть проста, как три копейки: ты берёшь и разводишь в разные стороны то, что ты делаешь (абстракция — например, фигура), и то, как ты это делаешь (реализация — например, цвет).

Вот смотри, как это выглядит в деле, без всей этой академической ху*ты:

// 1. Это наша "реализация" — то, КАК мы будем заливать цветом. Отдельная иерархия, живёт сама по себе.
interface Color {
    String applyColor();
}

class FuckingRed implements Color {
    @Override
    public String applyColor() { return "яростно-красным"; }
}

class SadBlue implements Color {
    @Override
    public String applyColor() { return "тоскливо-синим"; }
}

// 2. А это наша "абстракция" — то, ЧТО мы рисуем. Она НЕ наследует цвет, а содержит ссылку на него. Это и есть МОСТ!
abstract class Shape {
    protected Color color; // Вот он, сука, мост! Композиция, а не наследование!

    public Shape(Color color) { this.color = color; } // Подсовываем реализацию снаружи

    abstract String draw();
}

// 3. Конкретные фигуры. Им похуй, какой именно цвет им пришлют.
class Circle extends Shape {
    public Circle(Color color) { super(color); }

    @Override
    public String draw() {
        return "Рисую круг и заливаю его " + color.applyColor(); // Просто пользуемся мостом
    }
}

class Square extends Shape {
    public Square(Color color) { super(color); }

    @Override
    public String draw() {
        return "Вывожу квадрат, залитый " + color.applyColor();
    }
}

// 4. А теперь, ёпта, магия!
public class Main {
    public static void main(String[] args) {
        Color angryColor = new FuckingRed();
        Shape circle = new Circle(angryColor);
        System.out.println(circle.draw()); // Рисую круг и заливаю его яростно-красным

        // Или вот так, в одну строку, не заморачиваясь
        Shape square = new Square(new SadBlue());
        System.out.println(square.draw()); // Вывожу квадрат, залитый тоскливо-синим
    }
}

В чём, блядь, фокус?

  • Фигуры (абстракция) и Цвета (реализация) теперь — как два независимых модуля. Хочешь добавить новый цвет PsychodelicRainbow? Пожалуйста! Пишешь один класс, и он автоматически будет работать со всеми существующими фигурами. Ни одного существующего класса фигур трогать не надо! Это и есть принцип открытости/закрытости в действии, ебать его в сраку.
  • Клиентский код (тот, который в main) теперь не привязан к конкретным комбинациям. Он просто собирает нужную ему связку из абстракции и реализации, как из конструктора «Лего».

Где этот мост полезен? Да везде, где есть эта проклятая «платформенная зависимость»:

  • Драйверы баз данных (одна абстракция — запрос, много реализаций: для MySQL, PostgreSQL, Oracle).
  • GUI-фреймворки (окно — это абстракция, а отрисовка кнопок под Windows, MacOS или Linux — это реализация).
  • Разные API для отправки уведомлений (SMS, Email, Push) — логика одна, а каналы разные.

Короче, Мост — это когда ты перестаёшь плодить сущности как сумасшедший и начинаешь грамотно разделять матчасть. Чисто, гибко, и голова не болит.