Я хочу реализовать GUI как конечный автомат. Я думаю, что есть некоторые преимущества и недостатки этого, но это не тема этих вопросов.
После некоторого прочтения об этом я нашел несколько способов моделирования конечного автомата в C ++ и остановился на 2, но я не знаю, какой метод может лучше подойти для моделирования GUI.
Представьте конечный автомат в виде списка состояний с помощью следующих методов:
OnEvent(...);
OnEnterState(...);
OnExitState(...);
От StateMachine::OnEvent(...)
Я пересылаю мероприятие на CurrentState::OnEvent(...)
и здесь принимается решение сделать переход или нет. На переходе звоню CurrentState::OnExitState(...)
, NewState::OnEnterState()
а также CurrentState = NewState;
При таком подходе государство будет тесно связано с действиями, но State
может усложниться, когда из одного состояния я могу перейти в несколько состояний, и мне придется выполнять разные действия для разных переходов.
Представлять конечный автомат в виде списка переходов со следующими свойствами:
InitialState
FinalState
OnEvent(...)
DoTransition(...)
От StateMachine::OnEvent(...)
Я пересылаю событие на все переходы, где InitialState
имеет то же значение, что и CurrentState
в состоянии машины. Если условие перехода выполнено, цикл останавливается, DoTransition
метод называется и CurrentState
установлен в Transition::FinalState
,
С таким подходом Transition
будет очень просто, но число переходов может стать очень большим. Также станет сложнее отслеживать, какие действия будут выполнены, когда одно государство получит событие.
Какой подход, по вашему мнению, лучше для моделирования GUI. Знаете ли вы другие представления, которые могут быть лучше для моей проблемы?
Вот третий вариант:
symbol
(увидеть ниже)OnEvent
метод, который возвращает symbol
От StateMachine::OnEvent(...)
события направляются State::OnEvent
который возвращает symbol
— результат исполнения. StateMachine
затем на основе текущего состояния и возвращаемого символа решает,
OnExitState
а также OnEnterState
призван к соответствию состоянийПример матрицы для 3 состояний и 3 символов
0 1 2
1 2 0
2 0 1
В этом примере, если машина находится в любом состоянии (0,1,2)
а также State::OnEvent
возвращает символ 0
(первая строка в матрице) — остается в том же состоянии
Второй ряд говорит, что если текущее состояние 0
и возвращенный символ 1
переход в состояние 1
, Для государства 1
-> государство 2
и для государства 2
-> государство 0
,
Схожий третий ряд говорит, что для символа 2
, государство 0
-> государство 2
, государство 1
-> государство 0
, государство 2
-> государство 1
Суть этого бытия:
symbols
будет, вероятно, намного ниже, чем у штатов.DB_ERROR
иначе NETWORK_ERROR
вы просто меняете таблицу переходов и не трогаете реализацию состояний.Я не знаю, ожидаете ли вы такого ответа, но я использую, чтобы иметь дело с такими конечными автоматами прямым способом.
Используйте переменную состояния перечислимого типа (возможные состояния). В каждом обработчике событий GUI проверьте значение состояния, например, с помощью оператора switch. Выполните все необходимые обработки, соответственно, и установите следующее значение состояния.
Легкий и гибкий. Поддержание регулярности кода делает его читабельным и «формальным».
Я лично предпочел бы первый метод, который вы сказали. Я нахожу второй довольно нелогичным и чрезмерно сложным. Наличие одного класса для каждого состояния просто и легко, если затем вы установите правильные обработчики событий в OnEnterState и удалите их в OnExitState, ваш код будет чистым, и все будет содержаться в соответствующем состоянии, что позволяет легко читать.
Вы также избежите использования огромных операторов switch для выбора правильного обработчика событий или процедуры для вызова, поскольку все, что делает состояние, прекрасно видно внутри самого состояния, что делает код конечного автомата коротким и простым.
И последнее, но не менее важное, этот способ кодирования — это точный перевод от рисования конечного автомата на любой язык, который вы будете использовать.
Я предпочитаю действительно простой подход для такого рода кода.
switch
заявление или if
цепь и установить следующее состояние.Таким образом, нет никаких дополнительных структур метаданных управления конечным автоматом и нет кода для управления этими метаданными. Только ваши бизнес-данные и логика перехода. А действия могут напрямую проверять и изменять все переменные-члены, включая текущее состояние.
Недостатком является то, что вы не можете добавить дополнительные элементы данных, локализованные в одном состоянии. Что не является реальной проблемой, если у вас действительно большое количество штатов.
Я считаю, что это также приводит к более надежной конструкции, если вы всегда настраиваете все атрибуты пользовательского интерфейса при входе в каждое состояние, вместо того, чтобы делать предположения о предыдущем параметре и создавать поведения выхода-состояния для восстановления инвариантов перед переходами состояний. Это применимо независимо от того, какую схему вы используете для реализации переходов.
Вы также можете рассмотреть возможность моделирования желаемого поведения с помощью сети Петри. Это было бы предпочтительным, если вы хотите реализовать более сложное поведение, поскольку оно позволяет вам точно определить все возможные сценарии и предотвратить взаимные блокировки.
Эта библиотека может быть полезна для реализации конечного автомата для управления вашим графическим интерфейсом: Двигатель PTN