Коротка відповідь
middleState — це патерн, що дозволяє об’єкту змінювати поведінку при зміні внутрішнього стану. Клас `Context` тримає посилання на об’єкт `State`, а конкретні стани реалізують інтерфейс `handle()`. При виклику методу контекст просто проксуює до поточного стану, а сам стан може переключити контекст на інший. Наприклад: `context.setState(new ConcreteStateA()); context.handle();`
Повне пояснення
1. Що це і навіщо
State – патерн поведінковий, що дозволяє об’єкту змінювати свою поведінку залежно від внутрішнього стану. Підходить, коли логіка розділена на кілька «сценаріїв» і треба уникнути громіздких умовних операторів.
2. Принцип роботи / алгоритм
Контекст (Context) зберігає посилання на об’єкт State. Кожен конкретний стан реалізує інтерфейс handle() (або інші методи). При виклику методу контекст просто передає управління стану. Стан може змінити контекст, викликавши context.setState(new AnotherState()).
3. Реалізація (JS / TS)
- Базова реалізація
interface State { handle(context: Context): void; }
class ConcreteStateA implements State {
handle(ctx: Context) { console.log('A'); ctx.setState(new ConcreteStateB()); }
}
class Context {
private state: State;
setState(state: State) { this.state = state; }
request() { this.state.handle(this); }
}
- Веб‑dev приклад – кнопка, що змінює режим редагування (view/edit). Кожен режим – це стан, що реалізує
render().
class ViewState implements State { render(ctx) { ctx.element.innerHTML = 'View'; } }
class EditState implements State { render(ctx) { ctx.element.innerHTML = 'Edit'; } }
- Новачковий спрощений – простий таймер, що переходить між
Running,PausedіStopped.
class Running implements State { handle(ctx) { console.log('tick'); } }
4. Тестування (Jest або Vitest)
test('state transition', () => {
const ctx = new Context();
ctx.setState(new ConcreteStateA());
ctx.request(); // console.log('A')
expect(ctx.getState()).toBeInstanceOf(ConcreteStateB);
});
5. Проблеми та edge cases
- Неправильне використання ролей – контекст не має логіки, а лише проксуює.
- Зайва абстракція – коли станів мало, краще умовний оператор.
- Cyclical dependencies – стан може викликати інший, що в свою чергу повертається назад → нескінченний цикл.
- Плутанина між State і Strategy – State змінює поведінку, а Strategy вибирається зовні.
- Performance‑пастки – надмірна кількість станів збільшує обсяг коду і час інстанціювання.
6. Оптимізація та продуктивність
State зменшує кількість умовних операторів, що покращує читабельність. Однак кожен стан – окремий клас; якщо їх багато, це збільшує пам’ять і час створення. Кешування станів або використання фабрики може зменшити накладні витрати.
7. Без JS / архітектурні альтернативи
У чистій HTML/CSS можна реалізувати «состояние» через клас active і CSS‑селектори. У React це – локальний стан компоненту (useState) або контекст (Context API).
8. Cheatsheet + follow-up
- Cheatsheet:
Context→State;setState();handle(). - Interview Q: Як State відрізняється від Strategy? Чому не використовувати switch‑case в контексті?