Я разрабатываю приложение Windows Service некоторой сложности, и мне нужен способ постепенного перехода между состояниями.Поскольку каждое состояние может нуждаться в инициализации / очистке, должен существовать механизм, который координирует переходы между ними и гарантирует, что из любого данного состояния могут быть достигнуты только допустимые состояния.Указанные состояния являются знакомыми состояниями службы Windows:
Stopped|Running|Paused|StopPending|StartPending|PausePending|ContinuePending
Я разработал систему, которая кажется , чтобы сделать это правильно, но мне любопытноесть ли у него недостатки, которые я просто еще не наткнулся, и / или есть ли более проверенные и проверенные шаблоны / лучшие практики, которые я мог бы или должен использовать вместо этого.
Это реализовано в классе Bootstrapperкоторый предоставляет методы, соответствующие командам, которые я должен ожидать от службы Windows: Start, Stop, Pause, Continue (чтобы команда OnStart службы просто вызывала метод Start класса, OnStop будет вызывать Stop и т. д.):
В служебном коде (это VB.Net, но мне пришлось использовать здесь // для комментариев, поскольку в листинге кода, казалось, что-то не так):
Sub OnStart()
Bootstrapper.Start()
End Sub
В Start()
метод моего класса (здесь я пропускаю потоки и обработку исключений и другую логику для простоты):
Public Sub Start()
If RequestState(State.Running) = True Then
// Log success
Else
// Log failure
End If
End Sub
Тогда внутри моего класса есть аналогичный набор приватных OnStart()
, OnStop()
, OnPause()
и OnContinue()
методы, которые выполняют фактическую инициализацию / очистку для каждого состояния:
Private Function OnStart() As Boolean
SetState(State.StartPending)
// Do something
Return SetState(State.Running)
End Function
Как вы можете видеть выше, есть вызовы для двух других методов - RequestState()
иSetState()
.Вот где на самом деле имеет место логика, и она работает следующим образом:
Команда отправляется приложению (Start, Stop, Pause или Continue).Получающий метод вызывает RequestState()
с желаемым конечным состоянием, передаваемым в качестве параметра.Если это состояние было достижимым, оно возвращает True
, в противном случае False
.
RequestState()
будет использовать конструкции Select
для определения правильного действия на основе текущего состояния и запрошенного состояния.
SetState()
фактически устанавливает состояние приложения и после этого проверяет, есть ли какое-то «следующее» состояние «в очереди» (это так, чтобы процесс StartPending мог завершиться и закончиться вСостояние выполнения, до того, как будет введена команда Пауза.)
Простите, если я представлю эти методы в беспорядочном порядке, но с того места, где я сижу, показалось, что это правильный способ представить функциональность.Вот методы RequestState()
и SetState()
(извините за большую длину, но я чувствовал, что это было необходимо для полноты):
Private _currentState As State
Private _nextState As State
Private Function RequestState(ByVal requestedState As State) As Boolean
Select Case requestedState
Case State.StartPending, State.StopPending, State.PausePending, State.ContinuePending, State.Exception, State.None
Throw New ArgumentException(requestedState.ToString & " cannot be requested directly.")
Case Else
_nextState = requestedState
Select Case _currentState
Case State.Exception
Return False
Case State.Stopped
Select Case requestedState
Case State.Stopped
Return True
Case State.Running
Return OnStart()
Case Else
Return False
End Select
Case State.Running
Select Case requestedState
Case State.Stopped
Return OnStop()
Case State.Running
Return True
Case State.Paused
Return OnPause()
Case Else
Return False
End Select
Case State.Paused
Select Case requestedState
Case State.Stopped
Return OnStop()
Case State.Running
Return OnContinue()
Case State.Paused
Return True
Case Else
Return False
End Select
Case State.StartPending
Select Case requestedState
Case State.Stopped
_nextState = State.Stopped
Return True
Case State.Running
Return True
Case State.Paused
_nextState = State.Paused
Return True
Case Else
Return False
End Select
Case State.StopPending
Select Case requestedState
Case State.Stopped
Return True
Case State.Running
_nextState = State.Running
Return True
Case Else
Return False
End Select
Case State.ContinuePending
Select Case requestedState
Case State.Stopped
_nextState = State.Stopped
Return True
Case State.Running
Return True
Case State.Paused
_nextState = State.Paused
Return True
Case Else
Return False
End Select
Case State.PausePending
Select Case requestedState
Case State.Stopped
_nextState = State.Stopped
Return True
Case State.Running
_nextState = State.Running
Return True
Case State.Paused
Return True
Case Else
Return False
End Select
Case Else
Return False
End Select
End Select
End Function
Private Function SetState(ByVal newState As State) As Boolean
_currentState = newState
If newState = State.Running OrElse newState = State.Stopped OrElse newState = State.Paused Then
If _currentState = _nextState Then
Return True
End If
Return RequestState(_nextState)
Else
Return True
End If
End Function