Паттерны проектирования
8. Паттерн «Состояние» (State).
Некоторые объекты предметной области могут выполнять разные наборы операций в зависимости от состояния. Паттерн Состояние моделирует конечный автомат с набором допустимых переходов.
Назначение: позволяет объекту варьировать свое поведение в зависимости от внутреннего состояния. Извне создаётся впечатление, что изменился класс объекта. Основная идея в том, что программа может находиться в одном из нескольких состояний, которые всё время сменяют друг друга. Набор этих состояний, а также переходов между ними, предопределён и конечен. Находясь в разных состояниях, программа может по-разному реагировать на одни и те же события, которые происходят с ней.
Причины использования:
Допустим, объект Документ может принимать три состояния: Черновик, Модерация или Опубликован. Для каждого состояния документа метод обработки документа выполняет разные функции. В статусе Черновик он переведёт документ на модерацию (возможно, уведомит модератора о новом задании), в статусе Модерация метод опубликует документ, а в статусе Опубликован не будет делать ничего.
Основная проблема в таком решении проявится в том случае, если в Документ добавить ещё десяток состояний. Каждый метод обработки будет состоять из увесистого условного оператора, перебирающего доступные состояния. Такой код крайне сложно поддерживать. Малейшее изменение логики переходов заставит вас перепроверять работу всех методов, которые содержат условные операторы машины состояний.
Классическая диаграмма приведена на рисунке ниже:
-
Context – делегирует операции по переходу между своими состояниями объектам State, вызывая методы Handle();-
State - определяет интерфейс состояния;-
ConcreteState1 и ConcreteState2 - конкретные реализации состояний.Паттерн Состояние предлагает создать отдельные классы для каждого состояния, в котором может пребывать объект, а затем вынести туда поведение, соответствующее конкретному состоянию. Вместо того, чтобы хранить код всех состояний, объект контекста будет содержать ссылку на один из объектов-состояний и делегировать ему работу, зависящую от состояния. Благодаря тому, что объекты состояний имеют общий интерфейс, контекст сможет делегировать работу состоянию, не привязываясь к его классу. Поведение контекста можно будет изменить в любой момент, подключив к нему другой объект-состояние.
Важное отличие от паттерна Стратегия в том, что и контекст, и сами конкретные состояния могут знать друг о друге и инициировать переходы от одного состояния к другому.
Паттерн «Состояние» в полноценном виде довольно редко применяется на практике. Его применимость определяется сложностью конечного автомата. Чаще всего количество состояний объекта не столь велико, а логика переходов между состояниями не слишком сложна, поэтому её включают в сам объект контекста.
Источники:
- Тепляков С. "Паттерны проектирования на платформе .NET." — СПб.: Питер, 2015. Глава 7.
- https://refactoring.guru/ru/design-patterns/state