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

Приведи пример использования паттерна Bridge

2.2 Middle🔥 172 комментариев
#Архитектура и паттерны#ООП

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

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

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

Пример использования паттерна Bridge (Мост)

Паттерн Bridge — это структурный шаблон проектирования, который разделяет абстракцию и реализацию, позволяя им изменяться независимо. Он решает проблему "комбинаторного взрыва" подклассов, когда требуется множество сочетаний различных вариантов абстракции и реализации.

Основная идея — создать две иерархии:

  • Абстракция — определяет интерфейс высокого уровня.
  • Реализация — предоставляет конкретную реализацию низкого уровня.

Они связаны через композицию, а не наследование, что обеспечивает гибкость.

Практический пример: система рендеринга фигур

Представим, что мы разрабатываем библиотеку для рисования геометрических фигур, которая должна поддерживать разные типы фигур (круги, квадраты) и разные способы их отрисовки (векторный, растровый). Без Bridge пришлось бы создавать классы VectorCircle, RasterCircle, VectorSquare, RasterSquare и т.д. — количество классов растёт экспоненциально.

Реализация на PHP

<?php

// 1. Иерархия Реализации: Renderer (Отрисовщик)
interface Renderer {
    public function renderCircle(float $radius): string;
    public function renderSquare(float $side): string;
}

// Конкретные реализации
class VectorRenderer implements Renderer {
    public function renderCircle(float $radius): string {
        return "Рисуем круг радиусом {$radius} в векторном формате";
    }

    public function renderSquare(float $side): string {
        return "Рисуем квадрат со стороной {$side} в векторном формате";
    }
}

class RasterRenderer implements Renderer {
    public function renderCircle(float $radius): string {
        return "Рисуем пиксельный круг радиусом {$radius}";
    }

    public function renderSquare(float $side): string {
        return "Рисуем пиксельный квадрат со стороной {$side}";
    }
}

// 2. Иерархия Абстракции: Shape (Фигура)
abstract class Shape {
    protected Renderer $renderer;

    // Композиция: фигура содержит ссылку на реализацию отрисовки
    public function __construct(Renderer $renderer) {
        $this->renderer = $renderer;
    }

    abstract public function draw(): string;
    abstract public function resize(float $factor): void;
}

// Конкретные абстракции
class Circle extends Shape {
    private float $radius;

    public function __construct(Renderer $renderer, float $radius) {
        parent::__construct($renderer);
        $this->radius = $radius;
    }

    public function draw(): string {
        return $this->renderer->renderCircle($this->radius);
    }

    public function resize(float $factor): void {
        $this->radius *= $factor;
    }
}

class Square extends Shape {
    private float $side;

    public function __construct(Renderer $renderer, float $side) {
        parent::__construct($renderer);
        $this->side = $side;
    }

    public function draw(): string {
        return $this->renderer->renderSquare($this->side);
    }

    public function resize(float $factor): void {
        $this->side *= $factor;
    }
}

// 3. Клиентский код
$vectorRenderer = new VectorRenderer();
$rasterRenderer = new RasterRenderer();

// Круг с векторной отрисовкой
$vectorCircle = new Circle($vectorRenderer, 5);
echo $vectorCircle->draw() . "\n";
// Вывод: Рисуем круг радиусом 5 в векторном формате

// Круг с растровой отрисовкой
$rasterCircle = new Circle($rasterRenderer, -10);
echo $rasterCircle->draw() . "\n";
// Вывод: Рисуем пиксельный круг радиусом -10

// Квадрат с векторной отрисовкой
$vectorSquare = new Square($vectorRenderer, 7);
echo $vectorSquare->draw() . "\n";
// Вывод: Рисуем квадрат со стороной 7 в векторном формате

// Изменяем размер
$vectorSquare->resize(2);
echo $vectorSquare->draw() . "\n";
// Вывод: Рисуем квадрат со стороной 14 в векторном формате
?>

Ключевые преимущества паттерна Bridge

  • Устранение взрывного роста классов: Вместо 4 классов (VectorCircle, RasterCircle и т.д.) мы имеем 2 фигуры + 2 рендерера = 4 класса, и легко можем добавить новую фигуру (например, треугольник) или новый рендерер (например, WebGL), создавая лишь по одному новому классу, а не комбинации.
  • Разделение ответственности: Логика фигур (абстракция) отделена от логики отрисовки (реализация). Это соответствует принципу единственной ответственности (SRP).
  • Возможность динамического изменения реализации: Можно менять рендерер во время выполнения:
$circle = new Circle($vectorRenderer, 5);
echo $circle->draw(); // Векторный

// Динамически меняем реализацию
$circle = new Circle($rasterRenderer, 5);
echo $circle->draw(); // Растровый
  • Улучшенная тестируемость: Каждую иерархию можно тестировать изолированно с помощью мок-объектов.
  • Соблюдение принципа открытости/закрытости (OCP): Систему легко расширять новыми абстракциями и реализациями без изменения существующего кода.

Где ещё применяется Bridge?

  1. GUI-фреймворки: Абстракция — окна, кнопки; реализация — платформо-зависимые библиотеки (Windows API, Cocoa, GTK).
  2. Драйверы устройств: Абстракция — операции с устройством; реализация — драйверы для разных производителей.
  3. Кросс-платформенные приложения: Общий UI и специфичная реализация для каждой ОС.

Важные отличия от других паттернов

  • Bridge vs Adapter: Adapter изменяет интерфейс существующего объекта, а Bridge проектируется "с нуля" для разделения абстракции и реализации.
  • Bridge vs Strategy: Strategy фокусируется на изменении поведения алгоритма, а Bridge — на разделении двух orthogonal измерений в системе.

Таким образом, Bridge особенно полезен в крупных приложениях, где требуется долгосрочная гибкость и избежание жёсткой привязки абстракции к конкретной реализации. Это мощный инструмент для соблюдения принципов SOLID и создания поддерживаемой архитектуры.

Приведи пример использования паттерна Bridge | PrepBro