Ответ
Конечный автомат (State Machine, FSM) — это поведенческий паттерн, который позволяет объекту изменять своё поведение в зависимости от внутреннего состояния. Он формализует переходы между конечным числом состояний в ответ на события.
Основные компоненты:
- Состояния (States): Определённые конфигурации системы (например,
Idle,Processing,Completed). - Переходы (Transitions): Правила, определяющие, как и при каких событиях происходит смена состояния.
- События (Events): Входные сигналы или действия, инициирующие переходы.
Практический пример: Заказ в интернет-магазине
public enum OrderState { New, Paid, Shipped, Delivered, Cancelled }
public class Order
{
public OrderState CurrentState { get; private set; } = OrderState.New;
private Dictionary<(OrderState, string), OrderState> _transitions;
public Order()
{
// Определяем правила переходов: (Текущее состояние, Событие) -> Новое состояние
_transitions = new Dictionary<(OrderState, string), OrderState>
{
{ (OrderState.New, "Pay"), OrderState.Paid },
{ (OrderState.Paid, "Ship"), OrderState.Shipped },
{ (OrderState.Shipped, "Deliver"), OrderState.Delivered },
{ (OrderState.New, "Cancel"), OrderState.Cancelled },
{ (OrderState.Paid, "Cancel"), OrderState.Cancelled }
};
}
public bool TryProcessEvent(string eventName)
{
var key = (CurrentState, eventName);
if (_transitions.TryGetValue(key, out var newState))
{
CurrentState = newState;
Console.WriteLine($"Order state changed to {CurrentState} after event '{eventName}'");
return true;
}
Console.WriteLine($"Invalid transition from {CurrentState} on event '{eventName}'");
return false;
}
}
// Использование
var order = new Order();
order.TryProcessEvent("Pay"); // OK: New -> Paid
order.TryProcessEvent("Ship"); // OK: Paid -> Shipped
order.TryProcessEvent("Pay"); // Ошибка: Нет перехода из Shipped по событию Pay
Зачем это нужно?
- Упрощение сложной логики: Вместо множества
if-elseилиswitchпо флагам используется чётко определённая таблица переходов. - Предсказуемость: Все возможные состояния и переходы явно описаны.
- Лёгкость тестирования: Можно протестировать каждый переход независимо.
- Соблюдение инвариантов: Невозможны недопустимые переходы (например, отменить уже доставленный заказ).
State Machine и async/await в .NET:
Компилятор C# преобразует асинхронные методы (async/await) в машину состояний (State Machine). Это структура, реализующая интерфейс IAsyncStateMachine, которая:
- Хранит текущую позицию выполнения метода (в виде целого числа
state). - «Поднимает» локальные переменные в поля структуры, чтобы их значения сохранялись между
await. - Управляет продолжением выполнения после завершения асинхронной операции.
Почему так сделано? Это позволяет разбить метод на логические шаги, приостанавливать выполнение без блокировки потока и возобновлять его с нужного места, что и создаёт иллюзию последовательного асинхронного кода.