Skip to content

Latest commit

 

History

History
76 lines (50 loc) · 7.88 KB

State.md

File metadata and controls

76 lines (50 loc) · 7.88 KB

Состояние

UML

Позволяет менять поведение в зависимости от своего состояния. Извне создаётся впечатление, что изменился класс объекта.

Очень важным нюансом, отличающим этот паттерн от Стратегии, является то, что и контекст, и сами конкретные состояния могут знать друг о друге и инициировать переходы от одного состояния к другому.

Применимость

  • Когда у вас есть объект, поведение которого кардинально меняется в зависимости от внутреннего состояния. Причём типов состояний много и их код часто изменяется.

    • Паттерн предлагает создать класс для каждого такого состояния, а затем переместить туда все поля и методы, связанные с состоянием. Первоначальный класс будет постоянно ссылаться на один из объектов-состояний, делегируя ему большую часть работы. Для изменения состояния, в контекст будет подставляться другой объект.
  • Когда код класса содержит множество больших, похожих друг на друга, условных операторов, которые выбирают поведения в зависимости от текущих значений полей класса.

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

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

Шаги реализации

  1. Определитесь с классом, который будет отыгрывать роль контекста. Это может быть как существующий класс, в котором уже есть зависимость от состояния, так и новый класс, если код состояний размазан по нескольким классам.

  2. Создайте интерфейс состояния. Он должен описывать методы, общие для всех состояний, обнаруженных в контексте.

  3. Для каждого фактического состояния, создайте класс, реализующий интерфейс состояния. Переместите весь код, связанный с конкретным состоянием в нужный класс. В конце концов, все методы интерфейса состояния должны быть реализованы.

  4. Создайте в контексте поле для хранения объектов-состояний, а также публичный метод для изменения значения этого поля.

  5. Старые методы контекста, в которых находился зависимый от состояния код, замените на вызовы соответствующих методов объекта-состояния.

  6. В зависимости от бизнес-логики, разместите код, который переключает состояние контекста либо внутри контекста, либо внутри классов конкретных состояний.

Преимущества и недостатки

+ -
Избавляет от множества больших условных операторов машины состояний. Может неоправданно усложнить код, если состояний мало и они редко меняются.
Концентрирует в одном месте код, связанный с определённым состоянием.
Упрощает код контекста.

Отношения с другими паттернами

  • Мост, Стратегии и Состояние (а также слегка и Адаптер) имеют схожие структуры классов - все они построены на принципе «композиции», то есть делегирования работы другим объектам. Тем не менее, они отличаются тем, что решают разные проблемы. Помните, что паттерны - это не только рецепт построения кода определённым образом, но и описание проблем, которые привели к данному решению.

  • Состояние можно рассматривать как надстройку над Стратегией. Оба паттерна используют композицию, чтобы менять поведение основного объекта, делегируя работу вложенным объектам-помощникам. Однако в Стратегии эти объекты не знают друг о друге и никак не связаны. В Состоянии сами конкретные состояния могут переключать контекст.