状态机的简单介绍
最近公司做棋牌的项目,当时还是不理解什么是状态机,当一个项目做完之后,大脑里已经有了一个状态机的概念,所以今天就与大家分享出来,由于本人的技术博浅,有很多地方没有理解通透的地方,请望大神指点,抱拳了。
什么是状态机?
我理解的状态机就是,当一个事件触发之后,就会去寻找一个相对应的大的状态,然后在到大的状态里去寻找小的状态,然后执行完毕,给用户返回。
可能本人理解的不是多通透,在此边查资料边学习,与大家一起分享。
一丶状态模式
状态模式(State):当一个对象的内在状态改变时允许改变其行为,这个对象看起来像是改变了其类。
状态模式主要解决的是当控制一个对象状态转换的条件表达式过于复杂时的情况,把状态的判断逻辑转移到表示不同状态的一系列类当中,可以把复杂的逻辑简化,当然如果这个状态判断很简单,那就没有必要用 "状态模式" 了。
状态模式结构图
State类,抽象状态类,定义一个接口以封装与Context的一个特定状态相关的行为
![](https://yqfile.alicdn.com/img_1c53668bcee393edac0d7b3b3daff1ae.gif?x-oss-process=image/resize,w_1400/format,webp)
![](https://yqfile.alicdn.com/img_405b18b4b6584ae338e0f6ecaf736533.gif?x-oss-process=image/resize,w_1400/format,webp)
abstract class State { public abstract void Handle(Context context) ; }
ConcreteState类,具体状态,每一个子类实现以个与Context的一个状态相关行为
![](https://yqfile.alicdn.com/img_1c53668bcee393edac0d7b3b3daff1ae.gif?x-oss-process=image/resize,w_1400/format,webp)
Context类,维护一个ConcreteState子类的实列,这个实列定义当前的状态
![](https://yqfile.alicdn.com/img_1c53668bcee393edac0d7b3b3daff1ae.gif?x-oss-process=image/resize,w_1400/format,webp)
![](https://yqfile.alicdn.com/img_405b18b4b6584ae338e0f6ecaf736533.gif?x-oss-process=image/resize,w_1400/format,webp)
class Context { private State state; public Context (State state) # 定义 Context的初始状态 { this.state = state; } public State State # 可读写的状态属性,用于读取当前状态和设置新状态 { get ( return state ;) set { state = value; Console.WriteLine("当前状态:" + state.GetType().Name); } } public void Request() { state.Handle(this); # 对请求做处理,并设置下一状态 } }
客户端代码
![](https://yqfile.alicdn.com/img_1c53668bcee393edac0d7b3b3daff1ae.gif?x-oss-process=image/resize,w_1400/format,webp)
![](https://yqfile.alicdn.com/img_405b18b4b6584ae338e0f6ecaf736533.gif?x-oss-process=image/resize,w_1400/format,webp)
state void Main (string[] args) { Context c = new Context(new ConcreteStateA()); # 设置Context的初始状态为ConcreteStateA c.Request(); c.Request(); c.Request(); c.Request(); # 不断请求,同事更改状态 Console.Read(); }
状态模式的好处与坏处
状态模式的好处是将于特定状态相关的行为局部化,并且将不同的状态的行为分割开来。
将特定的状态相关的行为都放入一个对象中,由于所有与状态相关的代码都存在与某个ConcreteState中,所以通过定义新的子类可以很容易地增加新的状态和转换。
这样做的目的是什么?
这样做的目的说白了就是为了消除庞大的条件分之语句,大的分之判断会使得它们难以修改和扩展,就想刻板和印刷一样,任何改动都是致命的,状态模式通过把各种状态转移逻辑分布到State的子类之间,来减少相互依赖,好比把整个版面改成一个又一个的活字,此时候就容易维护和扩展了。
什么时候应该考虑使用状态模式呢?
当一个对象的行为取决于它的状态,并且它必须在运行时刻根据状态改变它的行为时,就可以考虑使用状态模式了。
参考设计模式举例 - 工作状态
代码结构图
抽象状态类,定义一个抽象方法"写程序"
![](https://yqfile.alicdn.com/img_1c53668bcee393edac0d7b3b3daff1ae.gif?x-oss-process=image/resize,w_1400/format,webp)
![](https://yqfile.alicdn.com/img_405b18b4b6584ae338e0f6ecaf736533.gif?x-oss-process=image/resize,w_1400/format,webp)
public abstract class State { public abstract void WriteProgram(Work w); }
上午和中午工作状态类
![](https://yqfile.alicdn.com/img_1c53668bcee393edac0d7b3b3daff1ae.gif?x-oss-process=image/resize,w_1400/format,webp)
![](https://yqfile.alicdn.com/img_405b18b4b6584ae338e0f6ecaf736533.gif?x-oss-process=image/resize,w_1400/format,webp)
pulic 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(); # 超过12点,则转入中午工作状态 } } }
![](https://yqfile.alicdn.com/img_1c53668bcee393edac0d7b3b3daff1ae.gif?x-oss-process=image/resize,w_1400/format,webp)
![](https://yqfile.alicdn.com/img_405b18b4b6584ae338e0f6ecaf736533.gif?x-oss-process=image/resize,w_1400/format,webp)
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(); # 超过13点则转入下午工作状态 } } }
下午和傍晚工作状态类
![](https://yqfile.alicdn.com/img_1c53668bcee393edac0d7b3b3daff1ae.gif?x-oss-process=image/resize,w_1400/format,webp)
![](https://yqfile.alicdn.com/img_405b18b4b6584ae338e0f6ecaf736533.gif?x-oss-process=image/resize,w_1400/format,webp)
public class AfternoonState : State { public override void WriteProgram (Work w) { if (w.Hour < 17) { Console.WriteLine("当前时间:{0}点 下午状态还不错,继续努力", w.Hour;) } else { w.SetState(new EveningState()); # 超过17点,则转入傍晚工作状态 w.WriteProgram(); } } }
![](https://yqfile.alicdn.com/img_1c53668bcee393edac0d7b3b3daff1ae.gif?x-oss-process=image/resize,w_1400/format,webp)
![](https://yqfile.alicdn.com/img_405b18b4b6584ae338e0f6ecaf736533.gif?x-oss-process=image/resize,w_1400/format,webp)
public class EveningState : State { public override void WriteProgram(Work w) { if (w.TaskFinished) { w.SetState(new RestState()); # 如果完成任务,则转入下班状态 w.WriteProgram(); } else { w.SetState(new SleepingState()); w.WriteProgram(); # 超过21点,则转入睡眠工作状态 } } }
睡眠状态和下班休息状态类
![](https://yqfile.alicdn.com/img_1c53668bcee393edac0d7b3b3daff1ae.gif?x-oss-process=image/resize,w_1400/format,webp)
![](https://yqfile.alicdn.com/img_405b18b4b6584ae338e0f6ecaf736533.gif?x-oss-process=image/resize,w_1400/format,webp)
public class SleepingState : State { public override void WriteProgram(Work w) { Console.WriteLine("当前时间:{0}点不行了,睡着了。", w.Hour); } }
![](https://yqfile.alicdn.com/img_1c53668bcee393edac0d7b3b3daff1ae.gif?x-oss-process=image/resize,w_1400/format,webp)
![](https://yqfile.alicdn.com/img_405b18b4b6584ae338e0f6ecaf736533.gif?x-oss-process=image/resize,w_1400/format,webp)
public class RestState : State { public override void WriteProgram(Work w) { Console.WriteLine("当前时间:{0}点下班回家了", w.Hour); } }
工作类
![](https://yqfile.alicdn.com/img_1c53668bcee393edac0d7b3b3daff1ae.gif?x-oss-process=image/resize,w_1400/format,webp)
![](https://yqfile.alicdn.com/img_405b18b4b6584ae338e0f6ecaf736533.gif?x-oss-process=image/resize,w_1400/format,webp)
public class Work { private State current; public Work() # 工作初始化为上午工作状态,即上午9点开始上班 { 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); } }
客户端代码
![](https://yqfile.alicdn.com/img_1c53668bcee393edac0d7b3b3daff1ae.gif?x-oss-process=image/resize,w_1400/format,webp)
![](https://yqfile.alicdn.com/img_405b18b4b6584ae338e0f6ecaf736533.gif?x-oss-process=image/resize,w_1400/format,webp)
static void Main(string[] args); { //紧急项目 Work emergencyProjects = new Work(); energencyProjects.Hour = 9; Work emergencyProjects = new Work(); energencyProjects.Hour = 10; Work emergencyProjects = new Work(); energencyProjects.Hour = 12; Work emergencyProjects = new Work(); energencyProjects.Hour = 13; Work emergencyProjects = new Work(); energencyProjects.Hour = 14; Work emergencyProjects = new Work(); energencyProjects.Hour = 17; //emergencyProjects.WorkFinished = true; emergencyProjects.WorkFinished = false; Work emergencyProjects = new Work(); energencyProjects.Hour = 19; Work emergencyProjects = new Work(); energencyProjects.Hour = 22; Console.Read(); }
结果表现如下
1 当前时间:10点 上午工作, 精神百倍 2 当前时间:12点 饿了,午饭:犯困,午休 3 当前时间:13点 下午状态还不错,继续努力 4 当前时间:14点 下午状态还不错,继续努力 5 当前时间:17点 加班哦,疲劳之极 6 当前时间:19点 加班哦,疲劳之极 7 当前时间:22点 不行了,睡着了
状态机的理解,大概就是这样,从一个大的状态切换到一个小的状态。