Перейти к основному содержимому

Что это

Паттерн Состояние (State) задаёт объекту разное поведение в разных состояниях, делая каждое состояние отдельным классом. Объект хранит своё текущее состояние и делегирует ему работу; переход в другое состояние означает подмену этого объекта.

Он заменяет разрастающийся match ($status) { ... }, повторяющийся в половине методов, одним небольшим классом на каждое состояние.


Пример: жизнь заказа

Заказ сначала новый, потом оплаченный, потом отправленный. Каждый класс состояния отвечает на describe() по-своему и знает, какое состояние идёт следующим, — сам заказ не содержит никакой логики статусов.

Каждое состояние — класс

advance() навсегда остаётся одной строкой. Добавить состояние «доставлен» — это новый класс плюс одно изменение в next(): никаких match, которые надо выискивать. (Состояния носят суффикс State, потому что new — ключевое слово и не может быть именем класса.)

Prompt
Напишите PHP-скрипт с паттерном State: интерфейс State с методами next и describe, классы NewState, PaidState и ShippedState (отправленный заказ остаётся отправленным) и класс Order, который хранит состояние и имеет метод advance, подменяющий его. Проведите один заказ через все три состояния, печатая каждое описание.
Вывод: PHP-скрипт

Когда применять

Применяйте, когда поведение объекта действительно различается по состоянию и у состояний есть реальные правила переходов: заказы, документы (черновик/на проверке/опубликован), соединения, игровые персонажи.

Не применяйте, когда статус только отображается и никогда не меняет поведение. Для менее чем трёх состояний с простыми правилами достаточно строкового свойства и одного match.


Плюсы и минусы

Плюсы: правила каждого состояния живут в одном небольшом классе; невозможные переходы просто не написаны; новые состояния добавляются расширением, а не правкой существующего кода.

Минусы: множество крохотных классов для простых автоматов; поток работы всего автомата размазан по файлам — помогает схема в комментарии.