状态模式 有限状态机

一、例子

参考大话设计模式-状态模式

abstract class State {
    public abstract function writeProgram($w);
}

//上午工作状态
class ForenoonState extends State {

    public function writeProgram($w) {
        if($w->hour < 12) {
            echo '当前时间:'.$w->hour.'点 上午工作,精神百倍。
'; } else { $w->setState(new NoonState()); $w->writeProgram(); } } } //中午工作状态 class NoonState extends State { public function writeProgram($w) { if($w->hour < 13) { echo '当前时间:'.$w->hour.'点 饿了,午饭;犯困,午休。
'; } else { $w->setState(new AfternoonState()); $w->writeProgram(); } } } //下午工作状态 class AfternoonState extends State { public function writeProgram($w) { if($w->hour < 17) { echo '当前时间:'.$w->hour.'点 下午工作状态还不错,继续努力。
'; } else { $w->setState(new EveningState()); $w->writeProgram(); } } } //晚间工作状态 class EveningState extends State { public function writeProgram($w) { if($w->taskFinished) { $w->setState(new RestState()); $w->writeProgram(); } else { if($w->hour < 21) { echo '当前时间:'.$w->hour.'点 加班哦,疲劳至极。
'; } else { $w->setState(new SleepingState()); $w->writeProgram(); } } } } //睡眠状态 class SleepingState extends State { public function writeProgram($w) { echo '当前时间:'.$w->hour.'点 不行了,睡着了。
'; } } //下班休息状态 class RestState extends State { public function writeProgram($w) { echo '当前时间:'.$w->hour.'点下班回家了。
'; } } //工作 class Work { private $current; public function __set($key, $value) { $this->$key = $value; } public function __get($key) { if(isset($this->$key)) { return $this->$key; } else { return NULL; } } public function __construct() { $this->current = new ForenoonState(); } private $hour; private $TaskFinished = false; public function setState($s) { $this->current = $s; } public function writeProgram() { $this->current->writeProgram($this); } } $emergencyProjects = new Work(); $emergencyProjects->hour = 9; $emergencyProjects->writeProgram(); $emergencyProjects->hour = 10; $emergencyProjects->writeProgram(); $emergencyProjects->hour = 12; $emergencyProjects->writeProgram(); $emergencyProjects->hour = 13; $emergencyProjects->writeProgram(); $emergencyProjects->hour = 14; $emergencyProjects->writeProgram(); $emergencyProjects->hour = 17; $emergencyProjects->writeProgram(); $emergencyProjects->taskFinished = false; $emergencyProjects->hour = 19; $emergencyProjects->writeProgram(); $emergencyProjects->hour = 22; $emergencyProjects->writeProgram();
二、状态模式与职责链模式区别

参考职责链模式VS状态模式
回忆一下职责链模式:

        /*
         * 先来一个程序猿 这里给他一个三万以内的随机值表示需要申请的差旅费
         */
        ProgramApe ape = new ProgramApe((int) (Math.random() * 30000));

        /*
         * 再来四个老大
         */
        Leader leader = new GroupLeader();
        Leader director = new Director();
        Leader manager = new Manager();
        Leader boss = new Boss();

        /*
         * 设置老大的上一个老大
         */
        leader.setLeader(director);
        director.setLeader(manager);
        manager.setLeader(boss);

        // 处理申请
        leader.handleRequest(ape);
    }

职责链模式与状态模式的最大的不同是设置自己的下一级的问题上,状态模式是在类的设计阶段就定好的,不能在客户端改变,而职责链的下一级是在客户端自己来确定的。这样各有什么优缺点呢?

在类的设计阶段设定(状态模式)的好处是不用客户来确定下一状态,也就减少了客户设置错误的问题,客户也不用知道状态的具体结构,同时存在灵活性差,耦合度高的问题,从上面的例子可以看到,因为作用域的问题,ConStateC一定要写在ConStateB之前,ConStateB一定要写在ConStateA之前,顺序不能乱。而在客户端设定(职责链模式)要求客户对各个类的职责要有所了解,并能正确设置好职责链,并加大设置出错的风险。但是它也比较灵活,也不存在刚才在状态模式中说的耦合和作用域问题。

三、有限状态机

参考讲解“有限状态机”最简单最易懂的例子,来自《数学之美》
以下内容摘自吴军的《数学之美》第113页:

一个有限状态机是一个特殊的有向图,它包括一些状态(节点)和连接这些状态的有向弧。下图是一个识别中国地址的有限状态机的简单例子。


Paste_Image.png

每一个有限状态机都有一个开始状态和一个终止状态,以及若干中间状态,每一条弧上带有从一个状态进入下一个状态的条件。比如,在上图中,当前的状态是“省”,如果遇到一个词组和(区)县名有关,就进入状态“区县”;如果遇到的下一个词组和城市有关,那么我们就进入“市”的状态,如此等等。如果一条地址能从状态机的起始状态经过状态机的若干中间状态,走到终止状态,那么这条地址则有效,否则无效。比如说,“北京市双清路83号”对于上面的有限状态来讲有效,而“上海市辽宁省马家庄”则无效(因为无法从“市”走回到“省”)。

四、有限状态机在游戏中的应用

参考Unity 游戏框架搭建 (四) 简易有限状态机

状态模式 有限状态机_第1张图片
一个跑酷的例子

主角从跑状态切换到跳状态,从跳状态切换到二段跳状态,这里的切换就是指状态的转移。状态的转移是有条件的,比如主角从跑状态不可以直接切换到二段跳状态。但是可以从二段跳状态切换到跑状态。
  另外,一个基本的状态有:进入状态、退出状态、接收输入、转移状态等动作。但是仅仅作为跑酷的角色的状态管理来说,只需要转移状态就足够了。有兴趣的同学可以自行扩展。

如何实现?

恰好之前看到过一个还算简易的实现(简易就是指我能看得懂- -,希望大家也是),原版是用lua实现的,我的跑酷游戏是用C#实现的,所以直接贴出C#代码。

using UnityEngine;  
using System.Collections;  
using System.Collections.Generic;  
public class FSM {  
    // 定义函数指针类型
    public delegate void FSMTranslationCallfunc();    /// 
    /// 状态类
    /// 
    public class FSMState
    {
        public string name;

        public FSMState(string name)
        {
            this.name = name;
        }
        /// 
        /// 存储事件对应的条转
        /// 
        public Dictionary  TranslationDict 
        = new Dictionary();
    }
    /// 
    /// 跳转类
    /// 
    public class FSMTranslation
    {
        public FSMState fromState;
        public string name;
        public FSMState toState;
        public FSMTranslationCallfunc callfunc; // 回调函数

        public FSMTranslation(FSMState fromState,string name, 
        FSMState toState,FSMTranslationCallfunc callfunc)
        {
            this.fromState = fromState;
            this.toState   = toState;
            this.name = name;
            this.callfunc = callfunc;
        }
    }
    // 当前状态
    private FSMState mCurState;

    Dictionary  StateDict = new Dictionary();
    /// 
    /// 添加状态
    /// 
    /// State.
    public void AddState(FSMState state)
    {
        StateDict [state.name] = state;
    }
    /// 
    /// 添加条转
    /// 
    /// Translation.
    public void AddTranslation(FSMTranslation translation)
    {
        StateDict [translation.fromState.name].TranslationDict [translation.name] = translation;
    }
    /// 
    /// 启动状态机
    /// 
    /// State.
    public void Start(FSMState state)
    {
        mCurState = state;
    }
    /// 
    /// 处理事件
    /// 
    /// Name.
    public void HandleEvent(string name)
    {
        if (mCurState != null && mCurState.TranslationDict.ContainsKey(name)) {
            Debug.LogWarning ("fromState:" + mCurState.name);

            mCurState.TranslationDict [name].callfunc ();
            mCurState = mCurState.TranslationDict [name].toState;


            Debug.LogWarning ("toState:" + mCurState.name);
        }
    }
}

//        Idle,               闲置
//        Run,                跑
//        Jump,               一段跳
//        DoubleJump,         二段跳
//        Die,                挂彩

        // 创建状态
        FSM.FSMState idleState = new FSM.FSMState("idle");
        FSM.FSMState runState  = new FSM.FSMState("run");
        FSM.FSMState jumpState = new FSM.FSMState("jump");
        FSM.FSMState doubleJumpState = new FSM.FSMState("double_jump");
        FSM.FSMState dieState  = new FSM.FSMState("die");
        // 创建跳转
        FSM.FSMTranslation touchTranslation1 = new 
        FSM.FSMTranslation(runState,"touch_down",jumpState,Jump);
        FSM.FSMTranslation touchTranslation2 = new 
        FSM.FSMTranslation(jumpState,"touch_down",doubleJumpState,DoubleJump);

        FSM.FSMTranslation landTranslation1 = new FSM.FSMTranslation(jumpState,"land",runState,Run);
        FSM.FSMTranslation landTranslation2 = new FSM.FSMTranslation(doubleJumpState,"land",runState,Run);

        // 添加状态
        PlayerModel.Instance ().fsm.AddState (idleState);
        PlayerModel.Instance ().fsm.AddState (runState);
        PlayerModel.Instance ().fsm.AddState (jumpState);
        PlayerModel.Instance ().fsm.AddState (doubleJumpState);
        PlayerModel.Instance ().fsm.AddState (dieState);

        // 添加跳转
        PlayerModel.Instance ().fsm.AddTranslation (touchTranslation1);
        PlayerModel.Instance ().fsm.AddTranslation (touchTranslation2);
        PlayerModel.Instance ().fsm.AddTranslation (landTranslation1);
        PlayerModel.Instance ().fsm.AddTranslation (landTranslation2);

        PlayerModel.Instance ().fsm.Start (runState);

你可能感兴趣的:(状态模式 有限状态机)