js状态模式 状态者模式的应用场景

状态模式,当一个对象的内在状态改变时允许改变其行为,这个对象看起来是改变了其类。

状态模式主要解决的是当控制一个对象状态转换的条件表达式过于复杂时的情况。把状态的判断逻辑转移到表示不同状态的一系列类当中,可以把复杂的判断逻辑简化。

既然状态者模式是对已有对象的状态进行抽象,则自然就有抽象状态者类和具体状态者类,而原来已有对象需要保存抽象状态者类的引用,通过调用抽象状态者的行为来改变已有对象的行为。经过上面的分析,状态者模式的结构图也就很容易理解了,具体结构图如下图示。

js状态模式
状态者模式的应用场景

从上图可知,状态者模式涉及以下三个角色:

  • Account类:维护一个State类的一个实例,该实例标识着当前对象的状态。
  • State类:抽象状态类,定义了一个具体状态类需要实现的行为约定。
  • SilveStater、GoldState和RedState类:具体状态类,实现抽象状态类的每个行为。

C#状态模式:

namespace 状态模式
{
    class Program
    {
        static void Main(string[] args)
        {
            //紧急项目
            Work 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.WorkFinished = true;
            emergencyProjects.TaskFinished = false;

            emergencyProjects.WriteProgram();
            emergencyProjects.Hour = 19;
            emergencyProjects.WriteProgram();
            emergencyProjects.Hour = 22;
            emergencyProjects.WriteProgram();


            Console.Read();
        }
    }


    //抽象状态
    public abstract class State
    {
        public abstract void WriteProgram(Work w);
    }

    //上午工作状态
    public class ForenoonState : State
    {
        public override void WriteProgram(Work w)
        {
            if (w.Hour < 12)
            {
                Console.WriteLine("当前时间:{0}点 上午工作,精神百倍", w.Hour);
            }
            else
            {
                w.SetState(new NoonState());
                w.WriteProgram();
            }
        }
    }

    //中午工作状态
    public class NoonState : State
    {
        public override void WriteProgram(Work w)
        {
            if (w.Hour < 13)
            {
                Console.WriteLine("当前时间:{0}点 饿了,午饭;犯困,午休。", w.Hour);
            }
            else
            {
                w.SetState(new AfternoonState());
                w.WriteProgram();
            }
        }
    }

    //下午工作状态
    public class AfternoonState : State
    {
        public override void WriteProgram(Work w)
        {
            if (w.Hour < 17)
            {
                Console.WriteLine("当前时间:{0}点 下午状态还不错,继续努力", w.Hour);
            }
            else
            {
                w.SetState(new EveningState());
                w.WriteProgram();
            }
        }
    }

    //晚间工作状态
    public class EveningState : State
    {
        public override void WriteProgram(Work w)
        {
            if (w.TaskFinished)
            {
                w.SetState(new RestState());
                w.WriteProgram();
            }
            else
            {
                if (w.Hour < 21)
                {
                    Console.WriteLine("当前时间:{0}点 加班哦,疲累之极", w.Hour);
                }
                else
                {
                    w.SetState(new SleepingState());
                    w.WriteProgram();
                }
            }
        }
    }

    //睡眠状态
    public class SleepingState : State
    {
        public override void WriteProgram(Work w)
        {
            Console.WriteLine("当前时间:{0}点 不行了,睡着了。", w.Hour);
        }
    }

    //下班休息状态
    public class RestState : State
    {
        public override void WriteProgram(Work w)
        {
            Console.WriteLine("当前时间:{0}点 下班回家了", w.Hour);
        }
    }

    //工作
    public class Work
    {
        private State current;
        public Work()
        {
            current = new ForenoonState();
        }

        private double hour;
        public double Hour
        {
            get { return hour; }
            set { hour = value; }
        }

        private bool finish = false;
        public bool TaskFinished
        {
            get { return finish; }
            set { finish = value; }
        }


        public void SetState(State s)
        {
            current = s;
        }

        public void WriteProgram()
        {
            current.WriteProgram(this);
        }
    }
}

在以下情况下可以考虑使用状态者模式。

  • 当一个对象状态转换的条件表达式过于复杂时可以使用状态者模式。把状态的判断逻辑转移到表示不同状态的一系列类中,可以把复杂的判断逻辑简单化。
  • 当一个对象行为取决于它的状态,并且它需要在运行时刻根据状态改变它的行为时,就可以考虑使用状态者模式。

javascript版本的状态机:

var Light = function(){
        this.currState = FSM.off;  //设置当前状态
        this.button = null;
    };

    Light.prototype.init = function(){
        var button = document.createElement('button'),
        self = this;

        button.innerHTML = '已关灯';
        this.button = document.body.appendChild(button);

        this.button.onclick = function(){
            self.currState.buttonWasPressed.call(self);    //把请求委托给FSM状态机
        }
    };

    var FSM = {
        off:{
            buttonWasPressed:function(){
                console.log('关灯');
                this.button.innerHTML = '下一次按我是开灯';
                this.currState = FSM.on;
            }
        },
        on:{
             buttonWasPressed:function(){
                console.log('开灯');
                this.button.innerHTML = '下一次按我是关灯';
                this.currState = FSM.off;
            }
        }
    };

    var light = new Light();
    light.init();

实际项目中的其他状态机:

var FSM = {
        walk:{
            attack:function(){
                console.log('攻击');
            },
            defense:function(){
                console.log('防御');
            },
            jump:function(){
                console.log('跳跃');
            }
        },

        attack:{
            walk:function(){
                console.log('攻击的时候不能行走');
            },
            defense:function(){
                console.log('攻击的时候不能防御');
            },
            jump:function(){
                console.log('攻击的时候不能跳跃');
            }
        }
    };  

状态模式的电灯程序:

var  Light = function(){
        this.currState = FSM.off;  //设置当前状态
    };

    Light.prototype.init = function(){
        self = this;

        this.button.onclick = function(){
            self.currState.buttonWasPressed.call(self);    //把请求委托给FSM状态机
        }
    };

    var FSM = {
        off:{
            buttonWasPressed:function(){
                console.log('弱光');
                this.currState = FSM.weak;
            }
        },
        weak:{
             buttonWasPressed:function(){
                console.log('强光');
                this.currState = FSM.strong;
            }
        },
        strong:{
             buttonWasPressed:function(){
                console.log('关灯');
                this.currState = FSM.off;
            }
        }
    };

    var light = new Light();
    light.init();

状态模式-水的三态变化

用js模拟物理现象,实现水的三态变化,初中物理课我们都学过,物质具有三态变化,气态 -> 液态 -> 固态 或者 固态 -> 液态 -> 气态,但是不可以气态 -> 固态,或者固态 -> 气态,是需要经过液态过度的,否则就违反了自然规律。所以这种状态的变化非常适合用状态模式来实现。代码如下:

var Water = function(){
        this.currState = FSM.gas;  //设置当前状态
        this.h3 = null;
    };

    Water.prototype.init = function(){
        var button1 = document.createElement('button'),
            button2 = document.createElement('button'),
            button3 = document.createElement('button'),
            h3 = document.createElement('h3'),
            self = this;
           
        button1.innerHTML = '100度以上';
        button1.onclick = function(){
            self.currState.gas.call(self);
        }
       
        button2.innerHTML = '0-100度';
        button2.onclick = function(){
            self.currState.liquid.call(self);
        }
       
        button3.innerHTML = '0度以下';
        button3.onclick = function(){
            self.currState.solid.call(self);
        }
       
        document.body.appendChild(button1);
        document.body.appendChild(button2);
        document.body.appendChild(button3);
        this.h3 = document.body.appendChild(h3);
    };

    var FSM = {
        gas:{ //气态
            liquid:function(){
                console.log('液态');
                this.h3.innerHTML = '液态';
                this.currState = FSM.liquid;
            },
            solid:function(){
                console.log('气态不能变化为固态');
                alert('气态不能变化为固态');
            }
        },
        liquid:{ //液态
            solid:function(){
                console.log('固态');
                this.h3.innerHTML = '固态';
                this.currState = FSM.solid;
            },
            gas:function(){
                console.log('气态');
                this.h3.innerHTML = '气态';
                this.currState = FSM.gas;
            }
        },
        solid:{ //固态
            gas:function(){
                console.log('固态不能变化为气态');
                alert('固态不能变化为气态');
            },
            liquid:function(){
                console.log('液态');
                this.h3.innerHTML = '液态';
                this.currState = FSM.liquid;
            }
        }
    };
    var water = new Water();
    water.init();