Що робить патерн State і коли він корисний?
Патерн State (Стан) використовується для того, щоб змінювати поведінку об'єкта при зміні його внутрішнього стану,
не створюючи громіздких конструкцій if-else чи switch.
1. Суть ідеї
Замість того щоб об'єкт сам вирішував, що робити залежно від стану, його поточний стан представлено окремим об'єктом, який знає, як поводитися в даному контексті.
Простіше кажучи: об'єкт "делегує" свою поведінку поточному стану. Коли стан змінюється - змінюється і поведінка.
2. Основна структура
- Context (Контекст) - об'єкт, поведінка якого залежить від стану. Зберігає посилання на поточний об'єкт-стан.
- State (Інтерфейс стану) - визначає загальний інтерфейс для всіх можливих станів.
- ConcreteState (Конкретні стани) - реалізують поведінку для конкретного стану і можуть перемикати контекст на інший.
3. Приклад (Java)
Приклад: банкомат, який поводиться по-різному залежно від стану.
// Інтерфейс стану
interface ATMState {
void insertCard(ATM atm);
void withdrawCash(ATM atm, int amount);
}
// Конкретні стани
class NoCard implements ATMState {
public void insertCard(ATM atm) {
System.out.println("Картку вставлено");
atm.setState(new HasCard());
}
public void withdrawCash(ATM atm, int amount) {
System.out.println("Немає картки - операція неможлива");
}
}
class HasCard implements ATMState {
public void insertCard(ATM atm) {
System.out.println("Картку вже вставлено");
}
public void withdrawCash(ATM atm, int amount) {
System.out.println("Видано: " + amount);
atm.setState(new NoCard());
}
}
// Контекст
class ATM {
private ATMState state = new NoCard();
public void setState(ATMState state) { this.state = state; }
public void insertCard() { state.insertCard(this); }
public void withdrawCash(int amount) { state.withdrawCash(this, amount); }
}Використання:
ATM atm = new ATM();
atm.withdrawCash(100); // Немає картки - операція неможлива
atm.insertCard(); // Картку вставлено
atm.withdrawCash(100); // Видано: 1004. Коли корисний
1. Коли об'єкт має декілька чітко визначених станів,
і його поведінка повинна змінюватися залежно від стану.
Приклад: банкомат (з карткою / без картки), гра (гравець живий / мертвий), документ (чернетка / опубліковано).
2. Коли код з умовними операторами став важко підтримувати.
Якщо в методах постійно зустрічається:
if (state == OPEN) { ... } else if (state == CLOSED) { ... }- State замінює це об'єктами станів, роблячи код чистішим і масштабованішим.
3. Коли переходи між станами відбуваються динамічно,
і ними потрібно керувати зсередини самих станів.
Наприклад, при успішній авторизації стан "Гість" сам переводить користувача у стан "Авторизований".
5. Переваги
- Усуває громіздкі блоки
if-else. - Делегує відповідальність за поведінку станам - код простіше розширювати.
- Поведінку можна змінювати на льоту, підміняючи об'єкт стану.
- Полегшує додавання нових станів без зміни контексту.
6. Недоліки
- Збільшує кількість класів (кожен стан - окремий клас).
- При надто простих сценаріях може бути надлишковим.
Висновок
Патерн State робить поведінку об'єкта динамічною і чистою, дозволяючи змінювати її "зсередини" без громіздких умов.
Підсумок:
State - це спосіб навчити об'єкт поводитися по-різному залежно від стану, роблячи код розширюваним, читабельним і реактивним, особливо там, де раніше був суцільний
if-else.
Коротка відповідь
Для співбесідиКоротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.