Разбить конечный автомат на несколько классов с помощью библиотеки Stateless
В решении на C#, над которым я работаю, ядро логики приложения реализовано в виде конечного автомата с помощью (очень хорошей) библиотеки Stateless. Существуют и другие части бизнес-логики, смоделированные в ряде других классов, для различных областей и функций, которые показывает приложение, но именно они являются основными изменениями в основных состояниях приложения.
Хотя каждый переход состояния довольно прост сам по себе (уведомление о событиях, установка eventArgs, прослушивание других событий, ...), и я использую подсостояния, когда это применимо, для меня это начинает выглядеть как- то слишком большим. Я понимаю, что это не точная мера, но если вы посмотрите и подумаете о подсостояниях, вы можете в конечном итоге обнаружить, что они могут быть отдельными конечными автоматами сами по себе.
Есть ли очевидный способ пропустить создание отдельной машины состояний (так сказать) с Stateless, отображающей каждый конечный автомат в отдельный класс (и файл)?
Первые проблемы с блокировками, которые приходят мне в голову (особенно вторая):
конечный автомат, состоящий из одного большого элемента, запускает события при всех изменениях состояния: после разделения каждый конечный автомат запускает каждый собственный триггер. Поэтому лучше было бы иметь фасад, собирающий все события и повторно запускающий их для клиентов, чтобы скрыть множество конечных автоматов (в конце концов, они являются деталями реализации для клиентов).
Подсостояния без сохранения состояния заботятся о пузырчатых спусках вверх по цепочке состояния / подсостояния, а также вниз. Так, например, для данного состояния
A
имея подсостояния, можно определить триггер (в одном месте,A
Настроить), что заставит конечный автомат уйтиA
независимо от того, в каком подсостоянииA
мы будем. Как это работает с отдельными подсостоящими машинами?
1 ответ
Как вы упомянули, определение хороших подсостояний действительно полезно для возможности абстрагировать части большого конечного автомата. Это также может быть полезно, если вы поместите определение суперсостояния и его подсостояний плюс все охранники и действия входа / выхода / перехода в одном классе.
Согласился с вашим предложением по пункту 1. Клиент должен видеть его как 1 конечный автомат.
Что касается пункта 2, я предлагаю определить некоторый интерфейс между вашим подчиненным автоматом и супер-автоматом через внутренние триггеры.
Давайте назовем ваш супер-конечный автомат A и ваш вспомогательный конечный автомат B. A вызовет событие, такое как StartB, которое переместит B из какого-то состояния Idle в состояние InProgress, то есть запустит вспомогательный конечный автомат. Тем временем А переходит в какое-то состояние WaitingForB. Когда B завершается со своим подпроцессом, он запускает событие типа BComplete на A. А затем продолжит с остальной частью своего процесса.
Вы можете иметь A и B совместно использовать один и тот же набор возможных триггеров, но B также может определять свой собственный (меньший) набор триггеров или на уровне, который соответствует подпроцессу, который он абстрагирует. Я думаю, что наиболее разумно абстрагировать подсистему B от вашего конечного автомата A, состоящего из одной большой части, если B не нужно реагировать на тот же полный набор триггеров, что и на A.