Защищенные переходы¶
Часто вам нужно, чтобы переход между состояниями происходил только при соблюдении определенных условий состояния (конечных или расширенных) или события. Например, предположим, что вы создаете машину для формы поиска и хотите, чтобы поиск был разрешен только в том случае, если:
- пользователю разрешен поиск (
.canSearchв этом примере) - поисковый запрос
queryне пустой
Это хороший вариант использования для «защищенного перехода», который является переходом, который происходит только в том случае, если выполняется какое-то условие (cond). Переход с условием называется защищенным переходом (guarded transition).
Защитные функции¶
Защитная функция (condition function) (также известная как защитник — guard), указанная в свойстве .cond перехода в виде строки или объекта условия со свойством {type: '...'} и принимает 3 параметра:
| Параметр | Тип | Описание |
|---|---|---|
context | object | Контекст автомата |
event | object | сработавшее событие |
condMeta | object | мета-данные |
Объект condMeta включает следующие свойства:
cond— объект исходного состоянияstate— состояние машины до перехода_event— SCXML событие
Возвращает
true или false, что определяет, будет ли осуществлен переход.
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 39 40 41 42 43 44 45 46 47 48 49 | |
Перейдите на вкладку Events и отправьте событие типа {"type": "SEARCH", "query": "something"} в визуализаторе:
https://stately.ai/viz?gist=09af23963bfa1767ce3900f2ae730029
Если cond возвращает false, то переход не будет выбран, и переход не будет происходить из этого узла состояния. Если все переходы в дочернем состоянии имеют защитные функции, которые возвращают false и позволяют их выбрать, то событие будет передано в родительское состояние и обработано там.
Пример использования с контекстом context:
1 2 3 4 5 6 7 8 9 10 11 | |
Подсказка
Реализации защитных функций можно быстро прототипировать, задав свойство cond прямо в конфигурации автомата:
1 2 3 4 5 6 | |
Сериализация защитных функций¶
Защитные функции могут (и должны) быть сериализованы как строка или объект со свойством {type: '...'}. Детали реализации защитной функции указаны в свойстве guards параметров автомата, где key — это тип type защитной функции (указанный как строка или объект), а значение — это функция, которая принимает три параметра:
context— текущий контекст автоматаevent— событие, которое вызвало потенциальный переход-
guardMeta— объект мета-данных о защитной функции и переходе:-
cond— исходный объектcond,
-
state— состояние автомата то потенциального перехода
Рефакторинг приведенного выше примера:
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 | |
Кастомизированные защитные функции¶
Начиная с версии 4.4+
Иногда, предпочтительнее сериализовать в JSON не только состояние переходов, но и логику защитных функций, определив её как объект с соответствующими данными:
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 | |
Несколько защитных функций¶
Если вы хотите, чтобы одно событие переходило в разные состояния в определенных ситуациях, вы можете предоставить массив условных переходов. Каждый переход будет проверяться по порядку, и будет выполнен первый переход, для которого защитная функция cond вернет true.
Например, вы можете смоделировать дверь, которая прослушивает событие OPEN, переходит в состояние 'opened', если вы администратор, или переходит в состояние 'closed.error', если значение alert истинно, или переходит в состояние 'closed.idle' в противном случае.
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 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 | |
Внимание
Функция cond всегда должна быть чистой функцией, которая ссылается только на параметры контекста context и события event.
Подсказка
Не злоупотребляйте защитными условиями. Если что-то может быть представлено дискретно как два или более отдельных события вместо нескольких conds для одного события, предпочтительнее избегать cond и вместо этого использовать несколько типов событий.
Защитная функция in¶
Свойство in принимает идентификатор состояния в качестве аргумента и возвращает true тогда и только тогда, когда этот узел состояния активен в текущем состоянии. Например, мы можем добавить защитную функцию к светофору:
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 | |
Когда защитная функция in присутствует с другими защитными функциями cond в том же переходе, все защитные функции должны вернуть true, чтобы переход был выполнен.
Подсказка
Использование защитных функций in обычно является признаком того, что автомат можно реорганизовать таким образом, чтобы в их использовании не было необходимости. По возможности избегайте защитных функций in.