2020年7月25日 星期六

狀態機 模式

using System.Collections;
using System.Collections.Generic;

/*
    泛用型 狀態機

    可以讓使用者 專注寫狀態就好

    對外直接使用 AI<T>

    撰寫邏輯使用繼承 State
    State內取用 樣板資料 來取得客製化數據 來做對應的變化

    事件取用方式?

    對外事件操作方式
        取得data後 可自行註冊內部事件

    定義資料
        這裡面定義可能要處理的資料與行為
    定義狀態類別 : state
        這裡面使用資料
    定義AI : AI<資料>
        讓外部取得data連結 然後做控制
        AI本身就是執行動作
*/

/// <summary>聖淨之風</summary>
namespace Aether
{
    /// <summary>行為</summary>
    public class AI<T> where T : new()
    {
        /// <summary>狀態機</summary>
        Context context = new Context();

        /// <summary>建構式</summary>
        public AI()
        {
            context.data = new T();
        }
        /// <summary>執行動作</summary>
        public void RunAction()
        {
            context.RunAction();
        }
        /// <summary>取得目前狀態</summary>
        /// <returns>目前狀態</returns>
        public string GetState()
        {
            return context.GetState();
        }
        /// <summary>取得資料</summary>
        /// <returns>回傳資料</returns>
        public T GetData()
        {
            return (T)context.data;
        }
    }
    /// <summary>狀態機</summary>
    public class Context
    {
        /// <summary>資料</summary>
        public object data = null;
        /// <summary>狀態池 - 減少new的使用</summary>
        Dictionary<string, State> stateDict = new Dictionary<string, State>();
        /// <summary>目前狀態</summary>
        State stateNow;

        /// <summary>更換狀態</summary>
        /// <typeparam name="T">狀態類別</typeparam>
        public void ChangeState<T>() where T : State, new()
        {   //取得狀態
            string l_strClassName = typeof(T).Name;
            State l_state = stateDict[l_strClassName];
            if(l_state == null)
            {
                l_state = new T();
                stateDict.Add(l_strClassName, l_state);
            }

            stateNow = l_state;
            stateNow.SetContext(this);
        }
        /// <summary>執行動作</summary>
        public void RunAction()
        {
            stateNow.RunAction();
        }
        /// <summary>取得目前狀態</summary>
        /// <returns>目前狀態</returns>
        public string GetState()
        {
            return stateNow.GetClassName();
        }
        /// <summary>取得資料</summary>
        /// <typeparam name="T">類型</typeparam>
        /// <returns>類型</returns>
        public T GetData<T>()
        {
            return (T)data;
        }
    }
    /// <summary>狀態</summary>
    public class State
    {
        /// <summary>狀態機</summary>
        protected Context context = null;

        /// <summary>設定狀態機</summary>
        /// <param name="i_context"></param>
        public void SetContext(Context i_context)
        {
            context = i_context;
        }
        /// <summary>運作行為</summary>
        public virtual void RunAction()
        {
        }
        /// <summary>取得類別名稱</summary>
        /// <returns>類別名稱</returns>
        public string GetClassName()
        {
            return this.GetType().Name;
        }
    }
}

沒有留言:

張貼留言