重点关注transition函数和MoveNext函数。
bool IContext<T>.transition(IState next)
{
IContext<T> context= this as IContext<T>;
if (context.CurrentState == null || context.CurrentState.Nexts.Contains(next))
{
//前件处理
var key = Tuple.Create(next, context.CurrentState);
if (context.Handles.ContainsKey(key) && context.Handles[key] !=null)
if (!context.Handles[key](next, context.CurrentState,ref this.data))
return false;
context.CurrentState = next;
return true;
}
return false;
}
做的事也很简单,就是调用前件处理程序,处理成功就转移状态,否则退出。
bool IEnumerator.MoveNext()
{
//后件处理
IContext<T> context = this as IContext<T>;
IState current = context.CurrentState;
if (current == null)
throw new Exception("必须设置初始状态");
if (context.CurrentState.Selector != null)
{
IState next= context.CurrentState.Selector(context.CurrentState);
return context.transition(next);
}
return false;
}
MoveNext通过选择器来选择下一个状态。
总的来说,我这个状态机的实现只是一个框架,没有什么功能,但是我感觉是比较容易编写状态转移目录树的。
用户首先要创建一组状态,然后建立目录树结构。我的实现比较粗糙,因为用户要分别构建目录树,前件处理器,还有后件选择器这三个部分。编写测试代码的时候,我写了9个状态的网状结构,结果有点眼花缭乱。要是能统一起来估计会更好一些。
要关注的是第一个状态,和最后的状态的构造,否则无法停机,嵌入死循环。
//测试代码
//---------创建部分---------
string mess = "";//3
IState s3 = new State() { Name = "s3" };
//2
IState s2 = new State() { Name = "s2" };
//1
IState s1 = new State() { Name = "s1" };
//---------组合起来---------
s1.Nexts = new List<IState> { s2, s3 };
s2.Nexts = new List<IState> { s1, s3 };
s3.Nexts = new List<IState> { }; //注意end写法
//---------上下文---------
//transition
IContext<int> cont = new Context<int> { CurrentState=s1};//begin
cont.Value = 0;
//---------状态处理器---------
HandleType<int> funcLaji = (IState current, IState previous, ref int v) => { mess += $"{current.Name}:垃圾{previous.Name}n"; v++; return true; };
//1
cont.Handles.Add(Tuple.Create(s1 , default(IState)), funcLaji);
cont.Handles.Add(Tuple.Create(s1, s2), funcLaji);
//2
cont.Handles.Add(Tuple.Create(s2, s1), funcLaji);
//3
cont.Handles.Add(Tuple.Create(s3, s1), funcLaji);
cont.Handles.Add(Tuple.Create(s3, s2), funcLaji);
//---------状态选择器---------
var rval = new Random();
Func<int,int> round = x => rval.Next(x);
s1.Selector = st => round(2)==0? s2:s3;
s2.Selector = st => round(2)==0? s1:s3;










