feat(task-0002): implement state controller interface with cancellation support and update task status

- Refactor BootStatesController to implement IStatesController interface
- Move state dictionary creation into constructor, remove static helper method
- Add CancellationToken validation before state transitions in StatesController
- Track current state presence with _hasCurrentState flag for safety
- Update TASK-0002 with Ready status

Выполнена задача TASK-0002 и обновлён статус:
- Рефакторинг BootStatesController для реализации интерфейса IStatesController
- Перемещено создание словаря состояний в конструктор, удалён статический вспомогательный метод
- Добавлена валидация CancellationToken перед переходами между состояниями в StatesController
- Добавлен флаг _hasCurrentState для отслеживания текущего состояния
- Обновлён статус TASK-0002 до Ready
This commit is contained in:
2026-05-27 04:04:59 +07:00
parent 535ca1a1b5
commit 2f745ba328
3 changed files with 28 additions and 14 deletions
+4
View File
@@ -1,5 +1,9 @@
# TASK-0002: Базовая архитектура Boot Flow # TASK-0002: Базовая архитектура Boot Flow
## Статус
Ready
## Цель ## Цель
Создать минимальную архитектурную основу для boot flow: сервисный lifecycle, state-контракты и generic state controller. Создать минимальную архитектурную основу для boot flow: сервисный lifecycle, state-контракты и generic state controller.
@@ -1,29 +1,31 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Threading;
using Cysharp.Threading.Tasks;
using QuizPleaseTest.Common.StateMachine; using QuizPleaseTest.Common.StateMachine;
namespace QuizPleaseTest.Boot.States namespace QuizPleaseTest.Boot.States
{ {
public class BootStatesController : StatesController<BootStateCode> public class BootStatesController : IStatesController<BootStateCode>
{ {
private readonly StatesController<BootStateCode> _statesController;
public BootStatesController( public BootStatesController(
SplashState splashState, SplashState splashState,
LoadState loadState, LoadState loadState,
MenuState menuState) MenuState menuState)
: base(CreateStates(splashState, loadState, menuState))
{ {
} _statesController = new StatesController<BootStateCode>(
new Dictionary<BootStateCode, IState>
private static IReadOnlyDictionary<BootStateCode, IState> CreateStates(
SplashState splashState,
LoadState loadState,
MenuState menuState)
{
return new Dictionary<BootStateCode, IState>
{ {
{ BootStateCode.Splash, splashState }, { BootStateCode.Splash, splashState },
{ BootStateCode.Load, loadState }, { BootStateCode.Load, loadState },
{ BootStateCode.Menu, menuState } { BootStateCode.Menu, menuState }
}; });
}
public UniTask EnterStateAsync(BootStateCode code, CancellationToken ct)
{
return _statesController.EnterStateAsync(code, ct);
} }
} }
} }
@@ -9,6 +9,7 @@ namespace QuizPleaseTest.Common.StateMachine
{ {
private readonly IReadOnlyDictionary<TEnum, IState> _states; private readonly IReadOnlyDictionary<TEnum, IState> _states;
private IState _currentState; private IState _currentState;
private bool _hasCurrentState;
public StatesController(IReadOnlyDictionary<TEnum, IState> states) public StatesController(IReadOnlyDictionary<TEnum, IState> states)
{ {
@@ -17,18 +18,25 @@ namespace QuizPleaseTest.Common.StateMachine
public async UniTask EnterStateAsync(TEnum code, CancellationToken ct) public async UniTask EnterStateAsync(TEnum code, CancellationToken ct)
{ {
ct.ThrowIfCancellationRequested();
if (!_states.TryGetValue(code, out IState newState)) if (!_states.TryGetValue(code, out IState newState))
{ {
throw new InvalidOperationException($"State is not registered: {code}"); throw new InvalidOperationException($"State is not registered: {code}");
} }
if (_currentState != null) if (_hasCurrentState)
{ {
await _currentState.ExitAsync(ct); await _currentState.ExitAsync(ct);
_currentState = null;
_hasCurrentState = false;
} }
ct.ThrowIfCancellationRequested();
await newState.EnterAsync(ct);
_currentState = newState; _currentState = newState;
await _currentState.EnterAsync(ct); _hasCurrentState = true;
} }
} }
} }