程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> C# >> C#入門知識 >> 一個形態機的完成

一個形態機的完成

編輯:C#入門知識

一個形態機的完成。本站提示廣大學習愛好者:(一個形態機的完成)文章只能為提供參考,不一定能成為您想要的結果。以下是一個形態機的完成正文


話不多說,先看代碼:

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);

以上就是本文的全部內容,希望本文的內容對大家的學習或許任務能帶來一定的協助,同時也希望多多支持!

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved