Что представляет собой паттерн Bridge?
Паттерн Bridge (Мост) — структурный шаблон проектирования. То есть, его основная задача — создание полноценной структуры из классов и объектов. Bridge решает эту задачу путем разделения одного или нескольких классов на отдельные иерархии — абстракцию и реализацию. Изменение функционала в одной иерархии не влечет за собой изменения в другой. Вроде все понятно, но по факту это определение звучит очень широко и не дает ответ на главный вопрос: “Что представляет собой паттерн Bridge?”. Думаю, с этим тебе будет проще разобраться на практике. Давай сразу смоделируем классический пример для паттерна Bridge. У нас есть абстрактный классShape
, который обобщенно описывает геометрическую фигуру:
Shape.java
public abstract class Shape { public abstract void draw(); }
Когда мы решим добавить фигуры треугольника и прямоугольника, мы унаследуемся от класса
Shape
:Rectangle.java:
public class Rectangle extends Shape { @Override public void draw() { System.out.println("Drawing rectangle"); } }
Triangle.java:
public class Triangle extends Shape { @Override public void draw() { System.out.println("Drawing triangle"); } }
draw()
. Чтобы иметь различные реализации метода draw()
, нам необходимо создать класс для каждой фигуры, соответствующий цвету. Если три цвета, то шесть классов: TriangleBlack
, TriangleGreen
, TriangleRed
, RectangleBlack
, RectangleGreen
и RectangleRed
.
Шесть классов — не такая уж и большая проблема. Но! Если нам нужно будет добавить новую фигуру или цвет, количество классов будет расти в геометрической прогрессии.
Как выйти из сложившейся ситуации? Хранение цвета в поле и перебор вариантов через условные конструкции — не лучший выход. Хорошее решение — вывести цвет в отдельный интерфейс.
Сказано — сделано: давай создадим интерфейс Color
и три его имплементации — BlackColor
, GreenColor
и RedColor
:
Color.java:
public interface Color { void fillColor(); }
BlackColor.java:
public class BlackColor implements Color { @Override public void fillColor() { System.out.println("Filling in black color"); } }
GreenColor.java
public class GreenColor implements Color { @Override public void fillColor() { System.out.println("Filling in green color"); } }
RedColor.java
public class RedColor implements Color { @Override public void fillColor() { System.out.println("Filling in red color"); } }
Теперь добавим поле типа
Color
в классShape
— его значение будем получать в конструкторе.Shape.java:
public abstract class Shape { protected Color color; public Shape(Color color) { this.color = color; } public abstract void draw(); }
Переменную
color
мы будем использовать в реализацияхShape
. А это значит, что фигуры теперь могут использовать функционал интерфейсаColor
.Rectangle.java
public class Rectangle extends Shape { public Rectangle(Color color) { super(color); } @Override public void draw() { System.out.println("Drawing rectangle"); color.fillColor(); } }
Color color
и является мостом (bridge), который взаимосвязывает две отдельные иерархии классов.
Устройство Bridge: что такое абстракция и реализация
Давай рассмотрим с тобой диаграмму классов, которая описывает паттерн Bridge: Здесь можно увидеть две независимые структуры, которые могут модифицироваться, не затрагивая функционал друг друга. В нашем случае это:- Abstraction — класс
Shape
; - RefinedAbstraction — классы
Triangle
,Rectangle
; - Implementor — интерфейс
Color
; - ConcreteImplementor — классы
BlackColor
,GreenColor
иRedColor
.
Shape
представляет собой Абстракцию — механизм управления раскраской фигур в различные цвета, который делегирует Реализацию интерфейсу Color
.
Классы Triangle
, Rectangle
являются реальными объектами, которые используют механизм, предложенный классом Shape
.
BlackColor
, GreenColor
и RedColor
— конкретные имплементации в ветке Реализация. Их часто называют платформой.
Где используют паттерн Bridge
Огромный плюс использования этого паттерна заключается в том, что можно вносить изменения в функционал классов одной ветки, не ломая при этом логику другой. Также такой подход помогает уменьшить связанность классов программы. Главное условие применения паттернов — “следовать инструкции”: не совать их куда попало! Собственно, давай разберемся, в каких случаях точно нужно использовать Bridge:Если необходимо расширить количество сущностей в две стороны (геометрические фигуры, цвета).
Если есть желание разделить большой класс, который не отвечает принципу Single responsibility, на более маленькие классы с узкопрофильным функционалом.
При возможной необходимости вносить изменения в логику работы неких сущностей во время работы программы.
При необходимости спрятать реализацию от клиентов класса (библиотеки).
Плюсы и минусы паттерна
Как и другие паттерны, у Моста есть и преимущества, и недостатки. Преимущества Bridge:- Улучшает масштабируемость кода — можно добавлять функционал, не боясь сломать что-то в другой части программы.
- Уменьшает количество подклассов — работает при необходимости расширения количества сущностей в две стороны (например, количество фигур и количество цветов).
- Дает возможность отдельно работать над двумя самостоятельными ветками Абстракции и Реализации — это могут делать два разных разработчика, не вникая в детали кода друг друга.
- Уменьшение связанности классов — единственное место связки двух классов — это мост (поле
Color color
).
- В зависимости от конкретной ситуации и структуры проекта в целом, возможно негативное влияние на продуктивность программы (например, если нужно инициализировать большее количество объектов).
- Усложняет читаемость кода из-за необходимости навигации между классами.
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ