Состояние (State)

При использовании шаблона Состояние поведение объекта меняется в зависимости от текущего контекста[6].

При помощи шаблона Состояние можно эффективно реализовать такую абстракцию как конечный автомат. Сделаем небольшое отступление и разберём понятие конечного автомата подробнее. Любую функцию можно рассматривать как некий преобразователь информации. Аргумент функции – входной сигнал – преобразуется, согласно определённому правилу, в результат функции – выходной сигнал. Функциональные преобразователи обладают важным свойством – их поведение не зависит от предыстории. В реальности, однако, имеется достаточно примеров преобразователей, реакция которых зависит не только от входа в данный момент, но и от того, что было на входе раньше, от входной истории. Такие преобразователи называются автоматами. Так как количество разных входных историй потенциально бесконечно, на множестве предысторий вводится отношение эквивалентности, и один класс эквивалентности предысторий называется состоянием автомата. Состояние автомата меняется только при получении очередного входного сигнала. При этом автомат не только выдаёт информацию на выход как функцию входного сигнала и текущего состояния, но и меняет своё состояние, поскольку входной сигнал изменяет предысторию.

Рассмотрим пример конечного автомата. Опишем поведение отца, отправившего сына в школу. Сын получает хорошие отметки («десятки») и плохие отметки («двойки»). Отец не хочет хвататься за ремень каждый раз, как только сын получит очередную двойку, и выбирает более тонкую тактику воспитания. Чтобы описать модель поведения отца, используем граф, в котором вершины соответствуют состояниям, а дуга из вершины в вершину проводится, когда автомат из состояния под воздействием входного сигнала переходит в состояние с выходной реакцией . Граф автомата, моделирующего поведение родителя, представлен на рис. 15.

Рис. 15. Автомат, описывающий поведение отца.

Этот автомат имеет четыре состояния и два входных сигнала (оценки, полученные сыном в школе). Стартуя из начального состояния (помечено особо), автомат под воздействием входных сигналов переходит из одного состояния в другое и выдаёт выходные сигналы – реакции на входы. Выходы автомата будем интерпретировать как действия родителя так: – «брать ремень»; – «ругать»; – «успокаивать»; – «надеяться»; – «радоваться»; – «ликовать».

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

Рис. 16. Дизайн шаблона Состояние.

При практической реализации шаблона Состояние отдельные объекты-состояния могут быть оформлены с применением шаблона Одиночка. Далее приведён код, использующий именно этот подход и соответствующий примеру конечного автомата, рассмотренного выше.

using System;

public class SmartParent

{

public AbstractState State = State0.Instance;

public void HandleTwo()

{

State.HandleTwo(this);

}

public void HandleTen()

{

State.HandleTen(this);

}

}

public abstract class AbstractState

{

public abstract void HandleTwo(SmartParent parent);

public abstract void HandleTen(SmartParent parent);

}

// здесь используется короткая, но не совсем корректная

// реализация шаблона Одиночка (см. соответствующий шаблон)

public class State0: AbstractState

{

public static readonly State0 Instance = new State0();

public override void HandleTwo(SmartParent parent)

{

Console.WriteLine("Успокаивать");

parent.State = State1.Instance;

}

public override void HandleTen(SmartParent parent)

{

Console.WriteLine("Радоваться");

parent.State = State3.Instance;

}

}

public class State1: AbstractState

{

public static readonly State1 Instance = new State1();

public override void HandleTwo(SmartParent parent)

{

Console.WriteLine("Ругать");

parent.State = State2.Instance;

}

public override void HandleTen(SmartParent parent)

{

Console.WriteLine("Надеяться");

parent.State = State0.Instance;

}

}

public class State2: AbstractState

{

public static readonly State2 Instance = new State2();

public override void HandleTwo(SmartParent parent)

{

Console.WriteLine("Брать ремень");

parent.State = State2.Instance;

}

public override void HandleTen(SmartParent parent)

{

Console.WriteLine("Надеяться");

parent.State = State0.Instance;

}

}

public class State3: AbstractState

{

public static readonly State3 Instance = new State3();

public override void HandleTwo(SmartParent parent)

{

Console.WriteLine("Успокаивать");

parent.State = State1.Instance;

}

public override void HandleTen(SmartParent parent)

{

Console.WriteLine("Ликовать");

parent.State = State3.Instance;

}

}


Понравилась статья? Добавь ее в закладку (CTRL+D) и не забудь поделиться с друзьями:  



double arrow
Сейчас читают про: