В этой практике мы сосредоточимся на построении самого автомата и его тестирование. В следующем задании вам уже предстоит применить его.
В англоязычной литературе термин известен, как FSM - Finite State Machine.
АКА - абстрактный автомат, число возможных состояний которого конечно [1]. Абстрактный автомат - математическая абстракция, модель дискретного устройства, имеющего один вход, один выход и в каждый момент времени находящийся в одном состоянии из множества возможных [2].
АКА используется для представления и управления потоком выполнения каких-либо команд. Конечный автомат идеально подходит для реализации искусственного интеллекта в играх, получая аккуратное решение без написания громоздкого и сложного кода. Ещё одна типичная область применения автоматов - это лексические анализаторы, парсеры, регулярные языки.
Приведем более конкретный пример. Допустим, вам нужно построить систему, которая определяет может ли человек получить доступ к некоторому ресурсу. Сначала система должна проверить есть ли у нее в локальном кэше необходимые данные, если нет то сходить на удаленный сервер, дождаться результата и обновить кэш. Далее получив из кэша эти данные, применить некоторую бизнес логику, от результата которой зависит, можно ли пользователю открыть доступ или нет. Казалось бы, можно это написать в лоб, но автомат будет выглядеть намного изящнее, и что самое главное для нас сейчас - автомат легко расширяем.
Для того чтобы достичь простоты расширения автоматов, необходимо разработать абстрактный автомат, реализация которого будет общая для многих задач. Тогда конкретная задача - это описание правил перехода из одного состояния в другое.
Перечислим основные концепции:
Когда необходимо применять автомат? Как минимум, когда у вас начинают получаться конструкции похожие на эту[6]:
switch( state ) {
case RADIO:
switch(event) {
case mode:
/* Change the state */
state = CD;
break;
case next:
/* Increase the station number */
stationNumber++;
break;
}
break;
case CD:
switch(event) {
case mode:
/* Change the state */
state = RADIO;
break;
case next:
/* Go to the next track */
trackNumber++;
break;
}
break;
}
Мы видим здесь, что система может находиться в 4 состояниях, между которыми можно как-то переключаться. Чем плох этот код, он же решает свою задачу? Основная проблема - невозможность расширения кода. Добавление нового состояния, например MP3, или кнопки pause, привёдет к необходимости вдумчиво читать код с вложенными switch блоками, анализировать к чему приведёт новое состояние и так далее. Этого можно избежать если разделить код на составляющие: собственно код, отвечающий за переходы между состояниями и код - обработчиков самих состояний.
Тогда нам нужны: