Что представляет собой паттерн 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).
- В зависимости от конкретной ситуации и структуры проекта в целом, возможно негативное влияние на продуктивность программы (например, если нужно инициализировать большее количество объектов).
- Усложняет читаемость кода из-за необходимости навигации между классами.
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ