Позволяет менять поведение в зависимости от своего состояния. Извне создаётся впечатление, что изменился класс объекта.
Очень важным нюансом, отличающим этот паттерн от Стратегии, является то, что и контекст, и сами конкретные состояния могут знать друг о друге и инициировать переходы от одного состояния к другому.
-
Когда у вас есть объект, поведение которого кардинально меняется в зависимости от внутреннего состояния. Причём типов состояний много и их код часто изменяется.
- Паттерн предлагает создать класс для каждого такого состояния, а затем переместить туда все поля и методы, связанные с состоянием. Первоначальный класс будет постоянно ссылаться на один из объектов-состояний, делегируя ему большую часть работы. Для изменения состояния, в контекст будет подставляться другой объект.
-
Когда код класса содержит множество больших, похожих друг на друга, условных операторов, которые выбирают поведения в зависимости от текущих значений полей класса.
- Паттерн предлагает переместить каждую ветку такого условного оператора в собственный класс. Тут же можно поселить и все поля, связанные с данным состоянием.
-
Когда вы сознательно используете табличную машину состояний, построенную на условных операторах, но вынуждены мириться с дублированием кода для похожих состояний и переходов.
- Паттерн Состояние позволяет реализовать иерархическую машину состояний, базирующуюся на наследовании. Вы можете отнаследовать похожие состояния от одного родительского класса, и вынести туда весь дублирующий код.
-
Определитесь с классом, который будет отыгрывать роль контекста. Это может быть как существующий класс, в котором уже есть зависимость от состояния, так и новый класс, если код состояний размазан по нескольким классам.
-
Создайте интерфейс состояния. Он должен описывать методы, общие для всех состояний, обнаруженных в контексте.
-
Для каждого фактического состояния, создайте класс, реализующий интерфейс состояния. Переместите весь код, связанный с конкретным состоянием в нужный класс. В конце концов, все методы интерфейса состояния должны быть реализованы.
-
Создайте в контексте поле для хранения объектов-состояний, а также публичный метод для изменения значения этого поля.
-
Старые методы контекста, в которых находился зависимый от состояния код, замените на вызовы соответствующих методов объекта-состояния.
-
В зависимости от бизнес-логики, разместите код, который переключает состояние контекста либо внутри контекста, либо внутри классов конкретных состояний.
+ | - |
---|---|
Избавляет от множества больших условных операторов машины состояний. | Может неоправданно усложнить код, если состояний мало и они редко меняются. |
Концентрирует в одном месте код, связанный с определённым состоянием. | |
Упрощает код контекста. |
-
Мост, Стратегии и Состояние (а также слегка и Адаптер) имеют схожие структуры классов - все они построены на принципе «композиции», то есть делегирования работы другим объектам. Тем не менее, они отличаются тем, что решают разные проблемы. Помните, что паттерны - это не только рецепт построения кода определённым образом, но и описание проблем, которые привели к данному решению.
-
Состояние можно рассматривать как надстройку над Стратегией. Оба паттерна используют композицию, чтобы менять поведение основного объекта, делегируя работу вложенным объектам-помощникам. Однако в Стратегии эти объекты не знают друг о друге и никак не связаны. В Состоянии сами конкретные состояния могут переключать контекст.