Що являє собою патерн 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).
- Залежно від конкретної ситуації та структури проекту в цілому, можливий негативний вплив на продуктивність програми (наприклад, якщо потрібно ініціалізувати більшу кількість об'єктів).
- Ускладнює читання коду через необхідність навігації між класами.
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ