Что такое стейт-машина

Ответ

Стейт-машина (конечный автомат) — это модель поведения системы, где состояние объекта изменяется в ответ на события. Состоит из:

  • Состояний (States) — возможные положения системы (например, IDLE, LOADING, SUCCESS)
  • Переходов (Transitions) — правила смены состояний при событиях
  • Действий (Actions) — операции при переходе/состоянии

Пример для загрузки данных:

sealed class State {
    object Idle : State()
    object Loading : State()
    data class Success(val data: String) : State()
    data class Error(val message: String) : State()
}

fun handleEvent(event: Event, currentState: State): State {
    return when (currentState) {
        is State.Idle -> when (event) {
            Event.StartLoading -> State.Loading
            else -> currentState
        }
        is State.Loading -> when (event) {
            Event.DataLoaded -> State.Success(event.data)
            Event.Error -> State.Error(event.message)
            else -> currentState
        }
        else -> currentState
    }
}

Используется для:

  • Четкого управления сложными потоками (аутентификация, UI-логика)
  • Предсказуемости — каждое состояние явно определено
  • Упрощения тестирования

Ответ 18+ 🔞

Да ты посмотри, что люди придумали, чтобы мозги не расплавились от сложной логики! Стейт-машина, конечный автомат — звучит-то как, будто из роботов терминаторов вытащили. А по сути, просто модель, которая описывает, как твоя система или объект себя ведёт.

Представь себе: у тебя есть объект, и он может быть в разных состояниях. Как человек: то спит (IDLE), то бежит на работу (LOADING), то получил зарплату (SUCCESS), а то начальник наорал (ERROR). Всё просто, ёпта.

Вот из чего эта штука состоит, разложу по полочкам:

  • Состояния (States) — это конкретные позы, в которых система может находиться. Как будто у тебя лампочка: выключена, горит, мигает. В коде их явно объявляют, чтобы не было неожиданностей, типа "а чё это у меня кнопка удаления появилась, когда данные ещё не загрузились?".
  • Переходы (Transitions) — это правила, ёбаный рот, по которым система перепрыгивает из одного состояния в другое. Не просто так, а в ответ на какое-то событие. Нажал кнопку "старт" (StartLoading) — перешёл из "ожидания" в "загрузку". Без переходов это был бы просто труп, а не машина.
  • Действия (Actions) — ну это уже по желанию. Что должно произойти, когда ты вошёл в состояние или когда из него выпрыгнул. Например, при переходе в LOADING начать реально качать данные с сервера, а при переходе в SUCCESS — отобразить их на экране.

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

sealed class State {
    object Idle : State() // Просто ждём, ничего не делаем
    object Loading : State() // Крутимся, грузимся
    data class Success(val data: String) : State() // Всё заебок, данные в кармане
    data class Error(val message: String) : State() // Всё пиздец, вот ошибка
}

fun handleEvent(event: Event, currentState: State): State {
    return when (currentState) {
        is State.Idle -> when (event) {
            Event.StartLoading -> State.Loading // Есть событие "старт" — поехали грузить
            else -> currentState // Игнорируем всё остальное, остаёмся в Idle
        }
        is State.Loading -> when (event) {
            Event.DataLoaded -> State.Success(event.data) // Данные пришли — ура!
            Event.Error -> State.Error(event.message) // Ошибка пришла — печалька
            else -> currentState // Пока грузим, на другие события не отвлекаемся
        }
        else -> currentState // Из Success или Error просто так не выпрыгнешь
    }
}

А зачем это всё, спрашивается, нужно? Да затем, чувак!

  • Чтобы не сойти с ума от сложных сценариев. Вся твоя аутентификация, UI-логика кнопок, загрузка данных — всё это превращается из спагетти-кода в понятную схему. Посмотрел на состояния и переходы — и сразу ясно, что и когда может случиться. Доверия ебать ноль к коду, где состояния меняются как попало, а тут — полный порядок.
  • Предсказуемость. Каждое состояние явно описано. Не может быть такого, что ты одновременно и "загружаешься", и "показываешь ошибку". Или что кнопку "сохранить" можно нажать до того, как данные валидны. Всё контролируется.
  • Тестирование упрощается в овердохуища раз. Тебе не надо гадать, в каком порядке тыкать кнопки, чтобы сломать приложение. Ты просто берёшь состояние, подаёшь событие и проверяешь, что получилось нужное новое состояние. Красота же!

Короче, если в твоём коде больше трёх if-ов, которые проверяют, в каком же положении сейчас объект, — это верный знак, что пора задуматься о стейт-машине. Иначе потом сам от себя охуеешь, пытаясь понять, почему оно работает не так.