В цій серії статей ми розглянемо патерни проєктування в Java: що це таке, чому вони важливі та як їх можна застосовувати в реальних проєктах. Не переживайте, ми будемо рухатись крок за кроком, зберігаючи все максимально простим.
Патерни проєктування — це вишукані рішення для поширених проблем програмування. Вони дозволяють писати чистіший та легший у підтримці код і сприяють зручнішій взаємодії між розробниками завдяки спільній термінології.
Ми розглянемо три основні типи патернів: Творчі (Creational), Структурні (Structural) та Поведенкові (Behavioral). Я надам вам прості приклади та чіткі пояснення, щоб ви зрозуміли, як кожен з них працює.
Якщо ви вже маєте деяке розуміння Java та знаєте основи об’єктно-орієнтованого програмування, як-от класи та об’єкти, ви готові до початку. Погнали!
Фото: Randy Fath на Unsplash
Будівельник — це творчий патерн проєктування, який дозволяє будувати складні об’єкти поступово. Цей патерн дає змогу створювати різні типи та варіації об’єкта, використовуючи той самий код для їх побудови.
Проблема
Уявіть, що ви створюєте додаток для будівництва, який спочатку опрацьовує лише базові будинки. Але з часом, коли додаток розвивається, вам потрібно додавати все більше складних конфігурацій будинків, таких як різні типи фундаментів, стін, дахів та різну кількість кімнат і вікон. Ви хочете забезпечити гнучкість процесу побудови і зробити так, щоб додавання нових варіантів було легким, без необхідності змінювати наявний код.
Рішення
Патерн "Будівельник" пропонує вирішення цієї проблеми, дозволяючи будувати складні об’єкти крок за кроком. Він відокремлює логіку побудови об’єкта від його представлення, що робить створення різних варіантів об’єкта простішим. Цей патерн особливо корисний для об’єктів, які мають багато властивостей.
Структура
- Продукт: Складний об’єкт, який будується (наприклад,
Будинок
). - Інтерфейс Будівельника: Оголошує методи для побудови частин продукту.
- Конкретний Будівельник: Реалізує інтерфейс Будівельника та надає логіку побудови частин продукту.
- Директор: Будує продукт, використовуючи інтерфейс Будівельника.
- Клієнт: Використовує Директора для побудови продукту.
Застосування
Використовуйте патерн "Будівельник", коли:
- Процес побудови об’єкта складний і має багато етапів.
- Ви хочете створювати різні варіації продукту.
- Ви хочете приховати логіку побудови від клієнта.
Як реалізувати
1. Визначте Продукт: Створіть клас, що представляє складний об’єкт, який ви хочете побудувати. Цей клас має містити різні властивості, які можна налаштовувати поодинці.
public class House {
private String foundation;
private String walls;
private String roof;
private int rooms;
private int windows;
public void setFoundation(String foundation) {
this.foundation = foundation;
}
public void setWalls(String walls) {
this.walls = walls;
}
public void setRoof(String roof) {
this.roof = roof;
}
public void setRooms(int rooms) {
this.rooms = rooms;
}
public void setWindows(int windows) {
this.windows = windows;
}
@Override
public String toString() {
return "House{" +
"foundation='" + foundation + '\\'' +
", walls='" + walls + '\\'' +
", roof='" + roof + '\\'' +
", rooms=" + rooms +
", windows=" + windows +
'}';
}
}
2. Визначте Інтерфейс Будівельника: Оголосіть інтерфейс, що містить методи для побудови частин продукту. Кожен метод відповідає за налаштування однієї з властивостей продукту. Інтерфейс також має метод для повернення повністю побудованого продукту.
public interface HouseBuilder {
void buildFoundation();
void buildWalls();
void buildRoof();
void buildRooms();
void buildWindows();
House getResult();
}
3. Створіть Конкретного Будівельника: Реалізуйте інтерфейс Будівельника, визначаючи, як будуються частини продукту.
public class ConcreteHouseBuilder implements HouseBuilder {
private House house;
public ConcreteHouseBuilder() {
house = new House();
}
@Override
public void buildFoundation() {
house.setFoundation("Concrete Foundation");
}
@Override
public void buildWalls() {
house.setWalls("Brick Walls");
}
@Override
public void buildRoof() {
house.setRoof("Tile Roof");
}
@Override
public void buildRooms() {
house.setRooms(4);
}
@Override
public void buildWindows() {
house.setWindows(6);
}
@Override
public House getResult() {
return house;
}
}
4. Використання Будівельника: Клієнт може використовувати Будівельника для створення продукту крок за кроком.
public class BuilderDemo {
public static void main(String[] args) {
HouseBuilder builder = new ConcreteHouseBuilder();
builder.buildFoundation();
builder.buildWalls();
builder.buildRoof();
builder.buildRooms();
builder.buildWindows();
House house = builder.getResult();
System.out.println(house);
}
}
Переваги та недоліки
Переваги:
- Гнучкість: Можливість створювати різні конфігурації продуктів.
- Розділення обов’язків: Логіка побудови об’єкта відокремлена від його представлення.
- Легкість у підтримці: Додаючи нові частини або налаштування продукту, можна уникнути змін у коді будівельника.
Недоліки:
- Складність: Іноді потрібно більше коду для реалізації цього патерну.
- Надмірність: У деяких випадках створення окремих будівельників може здатися надлишковим.
Цей патерн корисний для створення складних об’єктів, коли необхідно побудувати їх поетапно і надати можливість різних варіацій одного й того ж продукту.
Github репозиторій: https://github.com/LuisSalas94/design_patterns
Дякую за те, що прочитали мою статтю до кінця! Сподіваюся, що вона була корисною і допомогла вам отримати нові знання.
Перекладено з: Creational Patterns: Builder