Библиотека конечных автоматов без сохранения состояния - подходящий способ структурирования?
Как люди структурируют свой код при использовании библиотеки состояния без C#?
https://github.com/nblumhardt/stateless
Меня особенно интересует, как это связано с введенными зависимостями и правильным подходом к ответственности и правильному расслоению.
Моя текущая структура включает в себя следующее:
public class AccountWf
{
private readonly AspNetUser aspNetUser;
private enum State { Unverified, VerificationRequestSent, Verfied, Registered }
private enum Trigger { VerificationRequest, VerificationComplete, RegistrationComplete }
private readonly StateMachine<State, Trigger> machine;
public AccountWf(AspNetUser aspNetUser, AccountWfService userAccountWfService)
{
this.aspNetUser = aspNetUser;
if (aspNetUser.WorkflowState == null)
{
aspNetUser.WorkflowState = State.Unverified.ToString();
}
machine = new StateMachine<State, Trigger>(
() => (State)Enum.Parse(typeof(State), aspNetUser.WorkflowState),
s => aspNetUser.WorkflowState = s.ToString()
);
machine.Configure(State.Unverified)
.Permit(Trigger.VerificationRequest, State.VerificationRequestSent);
machine.Configure(State.VerificationRequestSent)
.OnEntry(() => userAccountWfService.SendVerificationRequest(aspNetUser))
.PermitReentry(Trigger.VerificationRequest)
.Permit(Trigger.VerificationComplete, State.Verfied);
machine.Configure(State.Verfied)
.Permit(Trigger.RegistrationComplete, State.Registered);
}
public void VerificationRequest()
{
machine.Fire(Trigger.VerificationRequest);
}
public void VerificationComplete()
{
machine.Fire(Trigger.VerificationComplete);
}
public void RegistrationComplete()
{
machine.Fire(Trigger.RegistrationComplete);
}
}
Должны ли мы реализовывать все процессы (вызов служб) в хуке OnEntry или реализовывать процессы снаружи после того, как переход состояния будет проверен на предмет его разрешения? Интересно, как сделать управление транзакциями, если так.
Полагаю, что мне нужно несколько лучших советов от тех, кто уже что-то реализовал, используя безгражданство и как подойти к структуре кода.
1 ответ
Прежде чем обратиться к самой структуре, пара замечаний:
OnEntry
действия выполняются только в случае успешного срабатывания триггера.Сработавшие триггеры, которые не разрешены в текущем состоянии,
InvalidOperationException
, Рассмотрим переопределениеOnUnhandledTrigger
если вы не ожидаете исключения (я обнаружил, что регистрация необработанных триггеров является хорошим подходом к поиску недостатков в логике).
Мое эмпирическое правило для OnEntry
/OnExit
структурирование заключается в том, что любое творение и логика будут размещены OnEntry
и любая необходимая очистка сделана OnExit
,
Так что в вашем случае, учитывая, что вы используете внедренные зависимости (и если вы не берете их в свои руки, то есть кто-то другой будет управлять их жизненным циклом), вы можете разместить всю свою логику OnEntry
,
Имея это в виду, структура вашего конечного автомата в настоящее время прекрасно работает.
И последнее замечание: имейте в виду, что триггеры запуска из одного и того же потока, который продвигает конечный автомат и выполняет логику конечного автомата, могут и приведут к исключениям переполнения стека (см. Здесь, как решить проблему автоматического продвижения).