mirror of
https://github.com/GeWuYou/GFramework.git
synced 2026-03-22 10:34:30 +08:00
feat(state): 添加状态机异步操作支持
- 实现了异步注销状态功能 UnregisterAsync - 添加了异步状态切换检查 CanChangeToAsync - 实现了异步状态切换功能 ChangeToAsync - 添加了异步回退到上一状态 GoBackAsync - 支持同步状态(IState)和异步状态(IAsyncState)的统一管理 - 提供了异步状态转换过程中的回调机制 - 完善了异步状态切换的核心逻辑处理 - [release ci]
This commit is contained in:
parent
1f724103bd
commit
a5daadea96
@ -2,6 +2,7 @@ namespace GFramework.Core.Abstractions.state;
|
|||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 状态机接口,用于管理状态的注册、切换和验证
|
/// 状态机接口,用于管理状态的注册、切换和验证
|
||||||
|
/// 支持同步和异步状态操作
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public interface IStateMachine
|
public interface IStateMachine
|
||||||
{
|
{
|
||||||
@ -22,6 +23,12 @@ public interface IStateMachine
|
|||||||
/// <typeparam name="T">要注销的状态类型,必须实现IState接口</typeparam>
|
/// <typeparam name="T">要注销的状态类型,必须实现IState接口</typeparam>
|
||||||
IStateMachine Unregister<T>() where T : IState;
|
IStateMachine Unregister<T>() where T : IState;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 异步从状态机中注销指定类型的状态
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">要注销的状态类型,必须实现IState接口</typeparam>
|
||||||
|
Task<IStateMachine> UnregisterAsync<T>() where T : IState;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 检查是否可以切换到指定类型的状态
|
/// 检查是否可以切换到指定类型的状态
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -29,6 +36,13 @@ public interface IStateMachine
|
|||||||
/// <returns>如果可以切换则返回true,否则返回false</returns>
|
/// <returns>如果可以切换则返回true,否则返回false</returns>
|
||||||
bool CanChangeTo<T>() where T : IState;
|
bool CanChangeTo<T>() where T : IState;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 异步检查是否可以切换到指定类型的状态
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">目标状态类型,必须实现IState接口</typeparam>
|
||||||
|
/// <returns>如果可以切换则返回true,否则返回false</returns>
|
||||||
|
Task<bool> CanChangeToAsync<T>() where T : IState;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 切换到指定类型的状态
|
/// 切换到指定类型的状态
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -36,6 +50,13 @@ public interface IStateMachine
|
|||||||
/// <returns>如果成功切换则返回true,否则返回false</returns>
|
/// <returns>如果成功切换则返回true,否则返回false</returns>
|
||||||
bool ChangeTo<T>() where T : IState;
|
bool ChangeTo<T>() where T : IState;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 异步切换到指定类型的状态
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">要切换到的状态类型,必须实现IState接口</typeparam>
|
||||||
|
/// <returns>如果成功切换则返回true,否则返回false</returns>
|
||||||
|
Task<bool> ChangeToAsync<T>() where T : IState;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 检查指定类型的状态是否已注册
|
/// 检查指定类型的状态是否已注册
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -74,6 +95,12 @@ public interface IStateMachine
|
|||||||
/// <returns>如果成功回退则返回true,否则返回false</returns>
|
/// <returns>如果成功回退则返回true,否则返回false</returns>
|
||||||
bool GoBack();
|
bool GoBack();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 异步回退到上一个状态
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>如果成功回退则返回true,否则返回false</returns>
|
||||||
|
Task<bool> GoBackAsync();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 清空状态历史记录
|
/// 清空状态历史记录
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@ -4,6 +4,7 @@ namespace GFramework.Core.state;
|
|||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 状态机实现类,用于管理状态的注册、切换和生命周期
|
/// 状态机实现类,用于管理状态的注册、切换和生命周期
|
||||||
|
/// 同时支持同步状态(IState)和异步状态(IAsyncState)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class StateMachine(int maxHistorySize = 10) : IStateMachine
|
public class StateMachine(int maxHistorySize = 10) : IStateMachine
|
||||||
{
|
{
|
||||||
@ -63,6 +64,45 @@ public class StateMachine(int maxHistorySize = 10) : IStateMachine
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 异步注销指定类型的状态
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">要注销的状态类型</typeparam>
|
||||||
|
public async Task<IStateMachine> UnregisterAsync<T>() where T : IState
|
||||||
|
{
|
||||||
|
IState? stateToUnregister;
|
||||||
|
|
||||||
|
lock (_lock)
|
||||||
|
{
|
||||||
|
var type = typeof(T);
|
||||||
|
if (!States.TryGetValue(type, out stateToUnregister)) return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果当前状态是要注销的状态,则先执行退出逻辑
|
||||||
|
if (Current == stateToUnregister)
|
||||||
|
{
|
||||||
|
if (Current is IAsyncState asyncState)
|
||||||
|
await asyncState.OnExitAsync(null);
|
||||||
|
else
|
||||||
|
Current.OnExit(null);
|
||||||
|
|
||||||
|
Current = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
lock (_lock)
|
||||||
|
{
|
||||||
|
// 从历史记录中移除该状态的所有引用
|
||||||
|
var tempStack = new Stack<IState>(_stateHistory.Reverse());
|
||||||
|
_stateHistory.Clear();
|
||||||
|
foreach (var historyState in tempStack.Where(s => s != stateToUnregister))
|
||||||
|
_stateHistory.Push(historyState);
|
||||||
|
|
||||||
|
States.Remove(typeof(T));
|
||||||
|
}
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 检查是否可以切换到指定类型的状态
|
/// 检查是否可以切换到指定类型的状态
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -76,6 +116,26 @@ public class StateMachine(int maxHistorySize = 10) : IStateMachine
|
|||||||
return Current?.CanTransitionTo(target) ?? true;
|
return Current?.CanTransitionTo(target) ?? true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 异步检查是否可以切换到指定类型的状态
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">目标状态类型</typeparam>
|
||||||
|
/// <returns>如果可以切换则返回true,否则返回false</returns>
|
||||||
|
public async Task<bool> CanChangeToAsync<T>() where T : IState
|
||||||
|
{
|
||||||
|
if (!States.TryGetValue(typeof(T), out var target))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (Current == null) return true;
|
||||||
|
|
||||||
|
// 如果当前状态是异步状态,使用异步方法
|
||||||
|
if (Current is IAsyncState asyncState)
|
||||||
|
return await asyncState.CanTransitionToAsync(target);
|
||||||
|
|
||||||
|
// 否则使用同步方法
|
||||||
|
return Current.CanTransitionTo(target);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 切换到指定类型的状态
|
/// 切换到指定类型的状态
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -102,6 +162,43 @@ public class StateMachine(int maxHistorySize = 10) : IStateMachine
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 异步切换到指定类型的状态
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">目标状态类型</typeparam>
|
||||||
|
/// <returns>如果成功切换则返回true,否则返回false</returns>
|
||||||
|
/// <exception cref="InvalidOperationException">当目标状态未注册时抛出</exception>
|
||||||
|
public async Task<bool> ChangeToAsync<T>() where T : IState
|
||||||
|
{
|
||||||
|
IState target;
|
||||||
|
|
||||||
|
lock (_lock)
|
||||||
|
{
|
||||||
|
// 检查目标状态是否已注册
|
||||||
|
if (!States.TryGetValue(typeof(T), out target!))
|
||||||
|
throw new InvalidOperationException("State not registered.");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 验证当前状态是否可以转换到目标状态(异步)
|
||||||
|
if (Current != null)
|
||||||
|
{
|
||||||
|
bool canTransition;
|
||||||
|
if (Current is IAsyncState asyncState)
|
||||||
|
canTransition = await asyncState.CanTransitionToAsync(target);
|
||||||
|
else
|
||||||
|
canTransition = Current.CanTransitionTo(target);
|
||||||
|
|
||||||
|
if (!canTransition)
|
||||||
|
{
|
||||||
|
await OnTransitionRejectedAsync(Current, target);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
await ChangeInternalAsync(target);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 检查指定类型的状态是否已注册
|
/// 检查指定类型的状态是否已注册
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -178,6 +275,38 @@ public class StateMachine(int maxHistorySize = 10) : IStateMachine
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 异步回退到上一个状态
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>如果成功回退则返回true,否则返回false</returns>
|
||||||
|
public async Task<bool> GoBackAsync()
|
||||||
|
{
|
||||||
|
IState? previousState = null;
|
||||||
|
|
||||||
|
// 循环查找有效的历史状态
|
||||||
|
while (previousState == null)
|
||||||
|
{
|
||||||
|
lock (_lock)
|
||||||
|
{
|
||||||
|
if (_stateHistory.Count == 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
var candidate = _stateHistory.Pop();
|
||||||
|
|
||||||
|
// 检查状态是否仍然注册
|
||||||
|
if (States.ContainsValue(candidate))
|
||||||
|
{
|
||||||
|
previousState = candidate;
|
||||||
|
}
|
||||||
|
// 如果状态已被注销,继续循环尝试更早的状态
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 回退时不添加到历史记录
|
||||||
|
await ChangeInternalWithoutHistoryAsync(previousState);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 清空状态历史记录
|
/// 清空状态历史记录
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -207,6 +336,32 @@ public class StateMachine(int maxHistorySize = 10) : IStateMachine
|
|||||||
OnStateChanged(old, Current);
|
OnStateChanged(old, Current);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 异步内部状态切换方法(不记录历史),用于回退操作
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="next">下一个状态实例</param>
|
||||||
|
protected virtual async Task ChangeInternalWithoutHistoryAsync(IState next)
|
||||||
|
{
|
||||||
|
if (Current == next) return;
|
||||||
|
|
||||||
|
var old = Current;
|
||||||
|
await OnStateChangingAsync(old, next);
|
||||||
|
|
||||||
|
if (old is IAsyncState asyncOld)
|
||||||
|
await asyncOld.OnExitAsync(next);
|
||||||
|
else
|
||||||
|
old?.OnExit(next);
|
||||||
|
|
||||||
|
Current = next;
|
||||||
|
|
||||||
|
if (Current is IAsyncState asyncCurrent)
|
||||||
|
await asyncCurrent.OnEnterAsync(old);
|
||||||
|
else
|
||||||
|
Current.OnEnter(old);
|
||||||
|
|
||||||
|
await OnStateChangedAsync(old, Current);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 内部状态切换方法,处理状态切换的核心逻辑
|
/// 内部状态切换方法,处理状态切换的核心逻辑
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -248,6 +403,53 @@ public class StateMachine(int maxHistorySize = 10) : IStateMachine
|
|||||||
OnStateChanged(old, Current);
|
OnStateChanged(old, Current);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 异步内部状态切换方法,处理状态切换的核心逻辑
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="next">下一个状态实例</param>
|
||||||
|
protected virtual async Task ChangeInternalAsync(IState next)
|
||||||
|
{
|
||||||
|
// 检查是否为相同状态,避免不必要的切换
|
||||||
|
if (Current == next) return;
|
||||||
|
|
||||||
|
var old = Current;
|
||||||
|
await OnStateChangingAsync(old, next);
|
||||||
|
|
||||||
|
// 将当前状态添加到历史记录
|
||||||
|
lock (_lock)
|
||||||
|
{
|
||||||
|
if (Current != null)
|
||||||
|
{
|
||||||
|
_stateHistory.Push(Current);
|
||||||
|
|
||||||
|
// 限制历史记录大小
|
||||||
|
if (_stateHistory.Count > maxHistorySize)
|
||||||
|
{
|
||||||
|
// 移除最旧的记录(栈底元素)
|
||||||
|
var tempStack = new Stack<IState>(_stateHistory.Reverse().Skip(1));
|
||||||
|
_stateHistory.Clear();
|
||||||
|
foreach (var state in tempStack.Reverse()) _stateHistory.Push(state);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 执行退出逻辑(异步或同步)
|
||||||
|
if (old is IAsyncState asyncOld)
|
||||||
|
await asyncOld.OnExitAsync(next);
|
||||||
|
else
|
||||||
|
old?.OnExit(next);
|
||||||
|
|
||||||
|
Current = next;
|
||||||
|
|
||||||
|
// 执行进入逻辑(异步或同步)
|
||||||
|
if (Current is IAsyncState asyncCurrent)
|
||||||
|
await asyncCurrent.OnEnterAsync(old);
|
||||||
|
else
|
||||||
|
Current.OnEnter(old);
|
||||||
|
|
||||||
|
await OnStateChangedAsync(old, Current);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 当状态转换被拒绝时的回调方法
|
/// 当状态转换被拒绝时的回调方法
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -257,6 +459,17 @@ public class StateMachine(int maxHistorySize = 10) : IStateMachine
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 当状态转换被拒绝时的异步回调方法
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="from">源状态</param>
|
||||||
|
/// <param name="to">目标状态</param>
|
||||||
|
protected virtual Task OnTransitionRejectedAsync(IState from, IState to)
|
||||||
|
{
|
||||||
|
OnTransitionRejected(from, to);
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 当状态即将发生改变时的回调方法
|
/// 当状态即将发生改变时的回调方法
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -266,6 +479,17 @@ public class StateMachine(int maxHistorySize = 10) : IStateMachine
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 当状态即将发生改变时的异步回调方法
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="from">源状态</param>
|
||||||
|
/// <param name="to">目标状态</param>
|
||||||
|
protected virtual Task OnStateChangingAsync(IState? from, IState to)
|
||||||
|
{
|
||||||
|
OnStateChanging(from, to);
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 当状态改变完成后的回调方法
|
/// 当状态改变完成后的回调方法
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -274,4 +498,15 @@ public class StateMachine(int maxHistorySize = 10) : IStateMachine
|
|||||||
protected virtual void OnStateChanged(IState? from, IState? to)
|
protected virtual void OnStateChanged(IState? from, IState? to)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 当状态改变完成后的异步回调方法
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="from">源状态</param>
|
||||||
|
/// <param name="to">目标状态</param>
|
||||||
|
protected virtual Task OnStateChangedAsync(IState? from, IState? to)
|
||||||
|
{
|
||||||
|
OnStateChanged(from, to);
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user