Как стать автором
Обновить

Комментарии 5

"Охрененно" круто, но только почему-то во всех приличных книжках используют термин "конечный автомат", а не "“Finite-state machine”? Я имею в виду книжки на "русском" языке, даже если они и переведены с иноземного!

Да, спасибо за замечание. Мне искать информацию в оригинальных терминах проще. Добавил еще вариант с локализованным вариантом.

НЛО прилетело и опубликовало эту надпись здесь

Стейт-машина – это полезный паттерн, который поможет вам запрограммировать множество состояний и переходов между ними когда это необходимо.

Тут нужно оговорить что сам паттерн State в статье не рассмотрен. Потому что никакого отношения к enum'ам он не имеет. Наоборот, это уход от enum'ов к ООП.

Паттерн state на Swift обычно реализуют примерно так:

1. Формируется список методов которые описывают внешние действия
protocol State {
func startCall() -> State
func endCall() -> State
}

2. Реализуется возможные состояния:
class InactiveState: State {
func startCall() -> State {
print("Call is active")
return StartedState()
}

func endCall() -> State {
print("Error: can't end the call, call is already inactive")
return self
}
}

class ActiveState: State {
func startCall() -> State {
print("Error: can't start the call, call is already active")
return self
}

func endCall() -> State {
print("Call is active")
return InactiveState()
}
}


3. Далее класс state используется в следующем виде:
class StateUser {
private var state: State = InitialState()

func makeCall() {
self.state = state.startCall()
self.state = state.endCall()
}
}

В чем плюсы паттерна:

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

  • Обработка конкретного состояния ограничено конкретным классов

  • Список воздействия и состояния развязаны. Список воздействий определяются списком методов State'а, а список состояний - списком классов.

Я активно занимался внедрением Finite-State Machine у себя на работе и безусловно это одно из самых лучших паттернов в мобильной разработке. Большая часть работы приложения это реакция на события, это может быть состояние об Интернет соединении, запуск приложения, аутентификация пользователя и т.п. В результате бизнес логика может распределена по зоне ответственности более детально. В тоже самое время состояния очень легко тестировать, потому как они отвечают только за переход от текущего состояние в некое следующее по заданным правилам.

В целом состояние можно описать следующим образом:

Определение состояния по своей сути
Определение состояния по своей сути

Тип состояния содержит список состояний, список событий и функцию редуктера (reducer), которая мутирует состояние.

Сама по себе машина состояния это просто менеджер или тот кто владеет состоянием и может его изменить через редуктор. Здесь важно понимать что извне состояние нельзя изменить в обход машины состояния. Можно только прочитать текущее значение или подписаться не его изменение.

Изменение состояния через машину состояния
Изменение состояния через машину состояния
Запрет на изменение состояния в обход владельца состояния
Запрет на изменение состояния в обход владельца состояния

Для реализации данного подхода вам необходимо определить протокол состояния который может выглядеть следующий образом:

protocol StateType: Equatable {
    associatedtype Event
    associatedtype Command = Void
    
    /// The initial state.
    static var initial: Self { get }
    
    /// Updates the current state to a new state caused by a given event.
    @discardableResult
    mutating func reduce(with event: Event) -> Command
}

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

Ну и последнее приведу более менее близкий к реальности пример состояния: https://gist.github.com/buh/63e1dd41b267bb65baacf03b8557786a

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

Зарегистрируйтесь на Хабре, чтобы оставить комментарий