Что такое паттерн "Мост" (Bridge)
Мост — структурный паттерн проектирования, который разделяет абстракцию и её реализацию так, чтобы их можно было изменять независимо друг от друга. Это помогает избежать жесткой связи между ними и делает код более гибким и расширяемым.
Представьте, что у вас есть разные варианты абстракций и реализаций, и они могут комбинироваться произвольно. Вместо создания множества классов для каждой комбинации используется паттерн мост — абстракция содержит ссылку на реализацию, и они развиваются отдельно.
Преимущества паттерна «Мост»
- Разделение абстракции и реализации облегчает поддержку и расширение.
- Позволяет изменять обе части независимо.
- Уменьшает количество классов при множественных вариациях абстракций и реализаций.
Пример:
- Абстракция: интерфейс рисования фигуры.
- Реализации: разные способы отрисовки (например, на экране, в файле).
- Мост связывает фигуру и конкретный способ отрисовки.
Где применяется паттерн «Мост»?
- Графические библиотеки и UI-фреймворки.
- Системы с разными способами реализации функционала.
- Кросс-платформенные приложения.
Пример реализации на JavaScript
// Реализация интерфейса рисования class DrawingAPI { drawCircle(x, y, radius) { throw new Error("Метод drawCircle() должен быть реализован"); } } // Конкретная реализация 1 class DrawingAPI1 extends DrawingAPI { drawCircle(x, y, radius) { console.log( `Рисуем круг с помощью DrawingAPI1 в (${x}, ${y}) с радиусом ${radius}`, ); } } // Конкретная реализация 2 class DrawingAPI2 extends DrawingAPI { drawCircle(x, y, radius) { console.log( `Рисуем круг с помощью DrawingAPI2 в (${x}, ${y}) с радиусом ${radius}`, ); } } // Абстракция — фигура class Shape { constructor(drawingAPI) { this.drawingAPI = drawingAPI; } draw() { throw new Error("Метод draw() должен быть реализован"); } resizeByPercentage(pct) { throw new Error("Метод resizeByPercentage() должен быть реализован"); } } // Конкретная фигура — круг class CircleShape extends Shape { constructor(x, y, radius, drawingAPI) { super(drawingAPI); this.x = x; this.y = y; this.radius = radius; } draw() { this.drawingAPI.drawCircle(this.x, this.y, this.radius); } resizeByPercentage(pct) { this.radius *= pct; } } // Использование const api1 = new DrawingAPI1(); const api2 = new DrawingAPI2(); const circle1 = new CircleShape(5, 10, 10, api1); circle1.draw(); circle1.resizeByPercentage(2); circle1.draw(); const circle2 = new CircleShape(20, 30, 15, api2); circle2.draw();
Когда стоит использовать паттерн «Мост»?
- Когда нужно разделить абстракцию и реализацию, чтобы развивать их независимо.
- Когда требуется поддержка множества вариантов абстракций и реализаций.
- Чтобы избежать комбинаторного взрыва классов при множественных вариациях.
Отличие от других паттернов
- В отличие от адаптера, который преобразует интерфейс, мост связывает абстракцию с реализацией. Мост обеспечивает более гибкую структуру, позволяя менять обе части отдельно.
Плюсы паттерна
- Улучшает расширяемость и поддержку кода.
- Снижает зависимость между абстракцией и реализацией.
- Уменьшает количество классов по сравнению с прямым наследованием.
Минусы паттерна
- Усложняет структуру за счёт дополнительного уровня абстракции.
- Может быть избыточен для простых систем с небольшим количеством вариантов.