Родительские состояния
Состояния могут содержать другие состояния, также известные как дочерние состояния. Эти дочерние состояния активны только тогда, когда активно родительское состояние.
Дочерние состояния вложены в свои родительские состояния. Родительские состояния также известны как составные состояния.
Совет
Посмотрите наше видео "Parent and child states" на YouTube (1m6s).
В видеоплеере выше состояние Opened является родительским для состояний Playing, Paused и Stopped. Эти состояния, их переходы и события вложены внутри состояния Opened.
Корневое состояние¶
Сама машина состояний является родительским состоянием! Это корневое состояние, и оно всегда активно.
Нормально иметь машину состояний без других состояний. Это полезно для моделирования простой машины состояний, которая только обрабатывает события, выполняя действия в переходах.
Вот пример простой машины подсчёта с событиями increment, decrement и reset, и без состояний, кроме неявного корневого состояния верхнего уровня:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | |
Начальное состояние¶
Начальное состояние родительского состояния — это состояние, в которое происходит вход при входе в родительское состояние. Родительские состояния должны иметь начальное состояние.
Вы указываете начальное состояние через свойство initial родительского состояния, которое является ключом начального состояния в объекте states:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | |
Даже если родительское состояние никогда не является прямой целью и вместо этого нацелены его дочерние состояния, указание начального состояния в свойстве .initial обязательно. В этом случае свойство .initial может быть любым из дочерних состояний.
Переходы в родительских состояниях¶
Переход, нацеленный на родительское состояние, войдёт в родительское состояние и его начальное состояние. Если это начальное состояние является родительским состоянием, то будет введено начальное состояние этого состояния и так далее.
Когда получено событие, сначала проверяются переходы на самых глубоких дочерних узлах, чтобы увидеть, включены ли они этим событием. Если переходы не включены, то проверяются переходы на родительском состоянии. Если переходы на родительском состоянии не включены, то проверяется родитель родителя и так далее.
Переходы на родительском состоянии могут быть нацелены на дочерние (или потомковые) состояния. Это полезно для моделирования перехода, который должен перейти в определённое дочернее состояние независимо от того, какое дочернее состояние в данный момент активно.
Переходы на дочернем состоянии могут быть нацелены на родительское состояние, хотя это не распространено. Переход от дочернего состояния к его родителю (или предку) также войдёт в начальное состояние родителя.
Дочерние финальные состояния¶
Когда достигается дочернее финальное состояние родительского состояния, это родительское состояние считается «завершённым». Переход onDone этого родительского состояния выполняется автоматически.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | |
Моделирование¶
При проектировании машин состояний с родительскими состояниями следуйте этим лучшим практикам:
Начните с плоской структуры, затем вкладывайте¶
- Начните с плоской структуры состояний и вводите родительские состояния только тогда, когда появляются паттерны
- Избегайте преждевременной абстракции — пусть поведение машины состояний определяет структуру
- Рефакторьте в родительские состояния, когда замечаете повторяющиеся паттерны или общее поведение
Распространённые паттерны для родительских состояний¶
- Общие переходы: Когда несколько состояний имеют одинаковые исходящие переходы, рассмотрите их группировку под родительским состоянием
- Подпроцессы: Используйте родительские состояния для моделирования отдельных подпроцессов или фаз вашего приложения
- Общий вход/выход: Если несколько состояний имеют общие действия входа или выхода, они могут принадлежать одному родительскому состоянию
- Группы состояний: Группируйте связанные состояния, которые представляют разные аспекты одной функции или компонента
Советы по проектированию родительских состояний¶
- Держите иерархию как можно более мелкой — глубокая вложенность может сделать машину состояний труднее для понимания
- Каждое родительское состояние должно иметь чёткую, единственную ответственность
- Используйте описательные имена, отражающие назначение родительского состояния
- Рассмотрите использование параллельных состояний для действительно независимых подпроцессов
- Документируйте назначение каждого родительского состояния комментариями
Когда избегать родительских состояний¶
- Когда состояния не разделяют никакого общего поведения или переходов
- Когда иерархия сделает машину состояний более сложной без добавления ценности
- Когда состояния представляют полностью независимые функции
Пример: Валидация формы¶
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | |
В этом примере родительское состояние validating группирует связанные состояния, которые обрабатывают процесс валидации, разделяя общие переходы и представляя чёткий подпроцесс.
Шпаргалка по родительским состояниям¶
Шпаргалка: создание родительских состояний¶
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | |