国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 編程 > C# > 正文

一個狀態機的實現

2019-10-29 21:14:47
字體:
來源:轉載
供稿:網友

話不多說,先看代碼:

interface IState {  string Name { get; set; }  //后件處理  IList<IState> Nexts { get; set; }  Func<IState /*this*/, IState /*next*/> Selector { get; set; }   } class State : IState {  public string Name { get; set; } = "State";  IList<IState> IState.Nexts { get; set; } = new List<IState>();  public Func<IState, IState> Selector { get; set; } }

狀態比較簡單,一個Name標識,一個后件狀態列表,然后一個狀態選擇器。

比如狀態a,可以轉移到狀態b,c,d,那么選擇器就是其中一個。至于怎么選,就讓用戶來定義實際的選擇器了。

delegate bool HandleType<T>(IState current, IState previous,ref T value); interface IContext<T> : IEnumerator<T>, IEnumerable<T> {  //data  T Value { get; set; }  //前件處理  IDictionary<Tuple<IState/*this*/, IState/*previous*/>, HandleType<T>> Handles { get; set; }  IState CurrentState { get; set; }  bool transition(IState next); }

和狀態類State關注后件狀態不同,上下文類Context關注前件狀態。當跳轉到一個新的狀態,這個過程中就要根據當前狀態來實施不同的策略。比如想進入狀態c,根據當前狀態是a, b,d 有不同的處理程序。這種轉移處理程序,是一一對應的,所以用了 Tuple<進入的狀態,當前狀態> 來描述一個跳轉鏈。然后用Dictionary 捆綁相關的處理程序。

上下文會攜帶 T Value 數據,要怎么處理這種數據?我是通過ref 參數來傳遞給處理程序。因為我不想IState 關心上下文的構造,它只需要關注實際的數據 T value;

上下文保存數據和當前狀態,然后通過transiton 讓用戶控制狀態的轉移。這里面有一個重復,因為IState有選擇器來控制狀態轉移了。為什么要這么處理?我是為了構造一個跳轉序列。引入IEnumerator和IEnumerable接口,然狀態可以在選擇器的作用下自動跳轉,然后用foreach 讀取結果序列(只是不知道有什么用)。

class Context<T> : IContext<T> {  T data;  T IContext<T>.Value { get=>data ; set=>data = value; }  IDictionary<Tuple<IState, IState>, HandleType<T>> IContext<T>.Handles { get; set; }    = new Dictionary<Tuple<IState, IState>, HandleType<T>>();  public IState CurrentState { get; set;}  T IEnumerator<T>.Current => (this as IContext<T>).Value ;  object IEnumerator.Current => (this as IContext<T>).Value;  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;  }  void IEnumerator.Reset()  {   throw new NotImplementedException();  }  #region IDisposable Support  private bool disposedValue = false; // 要檢測冗余調用  protected virtual void Dispose(bool disposing)  {   if (!disposedValue)   {    if (disposing)    {     // TODO: 釋放托管狀態(托管對象)。    }    // TODO: 釋放未托管的資源(未托管的對象)并在以下內容中替代終結器。    // TODO: 將大型字段設置為 null。    disposedValue = true;   }  }  // TODO: 僅當以上 Dispose(bool disposing) 擁有用于釋放未托管資源的代碼時才替代終結器。  // ~Context() {  // // 請勿更改此代碼。將清理代碼放入以上 Dispose(bool disposing) 中。  // Dispose(false);  // }  // 添加此代碼以正確實現可處置模式。  void IDisposable.Dispose()  {   // 請勿更改此代碼。將清理代碼放入以上 Dispose(bool disposing) 中。   Dispose(true);   // TODO: 如果在以上內容中替代了終結器,則取消注釋以下行。   // GC.SuppressFinalize(this);  }  IEnumerator<T> IEnumerable<T>.GetEnumerator()  {   return this;  }  IEnumerator IEnumerable.GetEnumerator()  {   return this;  }  #endregion }

重點關注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;

構造完畢后,就可以使用這個狀態機了。

//選擇器跳轉   mess += "選擇器跳轉:/n------------------------/n";foreach (var stor in cont)    mess+=$"狀態轉變次數:{stor}/n";//直接控制跳轉mess += "/n直接控制狀態跳轉:/n------------------------/n";cont.transition(s1);cont.transition(s2);cont.transition(s3);

以上就是本文的全部內容,希望本文的內容對大家的學習或者工作能帶來一定的幫助,同時也希望多多支持VEVB武林網!


注:相關教程知識閱讀請移步到c#教程頻道。
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 田林县| 常山县| 东城区| 浪卡子县| 习水县| 德惠市| 福安市| 岱山县| 鸡泽县| 五莲县| 永福县| 定南县| 胶南市| 抚远县| 德昌县| 长寿区| 神农架林区| 河南省| 寻乌县| 阿克苏市| 甘德县| 海伦市| 临泉县| 瑞昌市| 新丰县| 子长县| 岳普湖县| 南京市| 虎林市| 三门县| 白河县| 伽师县| 巴青县| 德庆县| 蓬莱市| 涟源市| 福泉市| 府谷县| 丰顺县| 临武县| 青岛市|