Паттерн состояние java. Состояние (State)

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

Паттерн «Состояние» предполагает выделение базового класса или интерфейса для всех допустимых операций и наследника для каждого возможного состояния

Когда использовать Паттерн State

    Когда поведение объекта должно зависеть от его состояния и может изменяться динамически во время выполнения

    Когда в коде методов объекта используются многочисленные условные конструкции, выбор которых зависит от текущего состояния объекта

UML схема паттерна "Состояние":

Реализация шаблона "состояние" на C#

using System; namespace DoFactory.GangOfFour.State.Structural { /// /// MainApp startup class for Structural /// State Design Pattern. /// class MainApp { /// /// Entry point into console application. /// static void Main() { // Setup context in a state Context c = new Context(new ConcreteStateA()); // Issue requests, which toggles state c.Request(); c.Request(); c.Request(); c.Request(); // Wait for user Console.ReadKey(); } } /// /// The "State" abstract class /// abstract class State { public abstract void Handle(Context context); } /// class ConcreteStateA: State { public override void Handle(Context context) { context.State = new ConcreteStateB(); } } /// /// A "ConcreteState" class /// class ConcreteStateB: State { public override void Handle(Context context) { context.State = new ConcreteStateA(); } } /// /// The "Context" class /// class Context { private State _state; // Constructor public Context(State state) { this.State = state; } // Gets or sets the state public State State { get { return _state; } set { _state = value; Console.WriteLine("State: " + _state.GetType().Name); } } public void Request() { _state.Handle(this); } } }

Пример паттерна State из реальной жизни

Примеры в.NET Framework

  • CommunicationObject реализует конечный автомат перехода между состояниями WCF клиента: Created, Opening, Opened, Closing, Closed и Faulted.
  • Task реализует конечный автомат перехода между состояниями задачи: Created, WaitingForActivation, WaitingToRun, Running, Run ToCompletion, Canceled, Faulted.

В режиме государственного (государственного образца), поведение класса основывается на его статус изменился. Этот тип шаблонов проектирования относятся поведенческие модели.

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

введение

Намерение: Позволяет объекту изменять свое поведение во внутреннем состоянии изменяется, то объект появляется, чтобы изменить свой класс.

Главным образом решить: поведение объекта зависит от его состояния (атрибутов), и вы можете изменить его в соответствии с его государством, связанные с изменением поведения.

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

Как исправить: статус конкретных классов абстрактных вне.

Ключевой код: режим командного интерфейса, как правило, только один метод. Статус интерфейса, в котором один или несколько методов. Кроме того, метод государственного режима класса реализации, как правило, возвращаемого значения, или изменить значение переменной экземпляра. То есть, состояние и состояние объектной модели, как правило, актуальны. Методы класса реализации имеют различные функции, методы интерфейса охвачены. Режим Состояние и командный режим то же самое может быть использован для устранения других условий, если... Else выбор.

Примеры применения: 1, играть в баскетбол игрок может иметь нормальное состояние, а не нормальное состояние и ненормальное состояние. 2, маркиза Yi Цзэн колокола, то "часы абстрактный интерфейс", "часы А" и другие конкретные состояния, специфическая среда "" китайские колокола (контекст).

Преимущества: 1, инкапсулирует правила преобразования. 2, перечислить возможные состояния, прежде чем перечисление государству необходимо определить статус видов. 3, все с поведением государства, связанных в класс, и вы можете легко добавить новое состояние, нужно только изменить состояние объекта может изменить поведение объектов. 4, что позволяет осуществить переход состояния логическое состояние объекта в одном, а не один огромный блок условных операторов. 5, позволяет использовать несколько объектов разделяют среду состояние объекта, тем самым уменьшая количество объектов в системе.

Недостатки: 1, Паттерн состояние использования связано с увеличением числа системных классов и объектов. 2, структура и реализация государственной формы являются более сложными, при неправильном использовании может вызвать путаницу структуру программы и код. 3, поддержка государственного образца "Открытый Закрытый принцип" не очень хорошо, вы можете переключать состояние государственной модели, добавляя новые классы нужно изменить статус лиц, ответственных за переходы состояний исходного кода, или не может перейти в новое состояние, и изменить состояние класс действовать также необходимо модифицировать исходный код соответствующего класса.

Сценарии использования: 1, с поведением изменения состояния и изменения сцены. 2, условный переход утверждение заменой.

Примечание: При использовании ограниченного государственного поведения путем государственного режима, а государство не более пяти.

реализация

Мы создадим интерфейс статуса и сущностигосударственный класс реализации интерфейсаState. Контекст представляет собой класс с определенным состоянием.

StatePatternDemo, мы демонстрируем использование объектовКонтекст Контекст класса и статуса, чтобы продемонстрировать изменение поведения в состоянии изменения.

Шаг 1

Создайте интерфейс.

State.java

Public interface State { public void doAction(Context context); }

Шаг 2

Создать класс сущностей, который реализует интерфейс.

StartState.java

Открытый класс StartState реализует государство { общественного недействительными DoAction (контекст Контекст) { System.out.println ("Игрок находится в стартовом состоянии"); context.setState (это); } общественного Строка ToString () { вернуть "начальное состояние"; } }

StopState.java

Public class StopState implements State { public void doAction(Context context) { System.out.println("Player is in stop state"); context.setState(this); } public String toString(){ return "Stop State"; } }

Шаг 3

Создание классаконтекста.

Context.java

Открытый класс {Context частное Государственное государство; общественный контекст () { состояние = NULL; } общественного недействительными SetState (Государственное государство) { this.state = состояние; } общенародного государства GetState () { возвращать состояние; } }

Шаг 4

Используйтеконтекст , чтобы увидеть поведение при изменении состояния измененийсостояния.

StatePatternDemo.java

Открытый класс StatePatternDemo { государственной статической силы основных (String ) {агдз Контекст Контекст = новый контекст (); StartState startState = новый StartState (); startState.doAction (контекст); System.out.println (context.getState () ToString ().); StopState stopState = новый StopState (); stopState.doAction (контекст); System.out.println (context.getState () ToString ().); } }

Шаг 5

Проверьте выход.

Игрок находится в стартовом состоянии Start государственный Игрок находится в состоянии останова остановленном

using System; namespace State { ///

/// Заблокированное состояние счета. /// public class Blocked: IState { /// /// Пополнить счет. /// /// Пополняемый счет. /// Сумма пополнения. public void Deposit(Card card, decimal money) { // Проверяем входные аргументы на корректность. if (card == null) { throw new ArgumentNullException(nameof(card)); } if (money <= 0) { throw new ArgumentException("Вносимая сумма должна быть больше нуля.", nameof(money)); } // Вычисляем сумму сверхлимитной задолженности. var overdraft = card.CreditLimit - card.Credit; // Вычисляем насколько сумма пополнения перекрывает задолженность. var difference = money - overdraft; if (difference < 0) { // Если сумма пополнения не перекрывает задолженность, // то просто уменьшаем сумму задолженности. card.Credit += money; // Вычисляем процент оставшейся суммы на счете. var limit = card.Credit / card.CreditLimit * 100; if (limit < 10) { // Если после пополнения на счете все еще меньше десяти процентов от лимита, // то просто сообщаем об этом пользователю. Console.WriteLine($"Ваш счет пополнен на сумму {money}. " + $"Сумма на вашем счете все еще составляет менее 10%. Ваш счет остался заблокирован. Пополните счет на большую сумму. {card.ToString()}"); } else if (limit >= 10 && limit < 100) { // Если задолженность перекрыта не полностью, то переводим в состояние расходования кредитных средств. card.State = new UsingCreditFunds(); Console.WriteLine($"Ваш счет пополнен на сумму {money}. Задолженность частично погашена. " + $"Погасите задолженность в размере {Math.Abs(difference)} рублей. {card.ToString()}"); } else { // Иначе задолженность полностью погашена, переводим в состояние расходования собственных средств. card.State = new UsingOwnFunds(); Console.WriteLine($"Ваш счет пополнен на {money} рублей. Задолженность полностью погашена. {card.ToString()}"); } } else { // Иначе закрываем задолженность, а оставшиеся средства переводим в собственные средства. card.Credit = card.CreditLimit; card.Debit = difference; // Переводим карту в состояние использования собственных средств. card.State = new UsingOwnFunds(); Console.WriteLine($"Ваш счет пополнен на {money} рублей. " + $"Кредитная задолженность погашена. {card.ToString()}"); } } /// /// Расходование со счета. /// /// Счет списания. /// Стоимость покупки. /// Успешность выполнения операции. public bool Spend(Card card, decimal price) { // Отказываем в операции. Console.WriteLine($"Ваш счет заблокирован. Пополните счет. {card.ToString()}"); return false; } } }

Название и классификация паттерна

Состояние - паттерн поведения объектов.

Назначение паттерна State

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

Паттерн State является объектно-ориентированной реализацией конечного автомата.

Решаемая проблема

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

Паттерн State решает указанную проблему следующим образом:

  • вводит класс Context, в котором определяется интерфейс для внешнего мира;
  • вводит абстрактный класс State;
  • представляет различные «состояния» конечного автомата в виде подклассов State;
  • в классе Context имеется указатель на текущее состояние, который изменяется при изменении состояния конечного автомата.

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

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

Структура паттерна State

Класс Context определяет внешний интерфейс для клиентов и хранит внутри себя ссылку на текущее состояние объекта State. Интерфейс абстрактного базового класса State повторяет интерфейс Context, за исключением одного дополнительного параметра - указателя на экземпляр Context. Производные от State классы определяют поведение, специфичное для конкретного состояния. Класс «обертка» Context делегирует все полученные запросы объекту «текущее состояние», который может использовать полученный дополнительный параметр для доступа к экземпляру Context.

UML-диаграмма классов паттерна State Структура паттерна Состояние показана на рис. 71.

context.setState(StateTwo);

Рис. 71. UML-диаграмма паттерна Состояние

Участники

Context - контекст:

  • определяет интерфейс, представляющий интерес для клиентов;
  • хранит экземпляр подкласса ConcreteState, которым определяется текущее состояние.

State - состояние: определяет интерфейс для инкапсуляции поведения, ассоциированного с конкретным состоянием контекста Context.

Подклассы StateOne, StateTwo, StateThree - конкретное состояние: каждый подкласс реализует поведение, ассоциированное с некоторым состоянием контекста Context.

Отношения

Класс Context делегирует зависящие от состояния запросы текущему объекту ConcreteState.

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

Context - это основной интерфейс для клиентов. Клиенты могут конфигурировать контекст объектами состояния State. Один раз сконфигурировав контекст, клиенты уже не должны напрямую связываться с объектами состояния.

Либо Context, либо подклассы ConcreteState могут решить, при каких условиях и в каком порядке происходит смена состояний.

Пример паттерна State

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

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

Использование паттерна State

Определите существующий или создайте новый класс-«обертку» Context, который будет использоваться клиентом в качестве «конечного автомата».

Создайте базовый класс State, который повторяет интерфейс класса Context. Каждый метод принимает один дополнительный параметр: экземпляр класса Context. Класс State может определять любое полезное поведение «по умолчанию».

Создайте производные от State классы для всех возможных состояний.

Все полученные от клиента запросы класс Context просто делегирует объекту «текущее состояние», при этом в качестве дополнительного параметра передается адрес объекта Context.

Используя этот адрес, в случае необходимости методы класса State могут изменить «текущее состояние» класса Context.

Реализация паттерна State

Рассмотрим пример конечного автомата с двумя возможными состояниями и двумя событиями.

using namespace std;

class State *current; public:

void setCurrent(State *s)

void on(); void off();

virtual void on(Machine *m)

virtual void ofT(Machine *m)

void Machine::on()

current->on(this);

void Machine::off()

current->off(this);

class ON: public State

void off(Machine *m);

class OFF: public State

void on(Machine *m)

cout setCurrent(new ON()); delete this;

void ON::off(Machine *m)

cout setCurrent(new OFF()); delete this;

Machine::Machine()

current = new OFF(); cout

void(Machine:: *ptrs)() =

Machine::off, Machine::on

Machine fsm; int num; while (1)

(fsm. *ptrs}