哪位能简单工厂模式介绍介绍下什么是状态机模式

:转载时请以超链接形式标明文章原始出处和作者信息及本声明
什么是状态机设计一个状态机来解决问题
  本文会考虑如何从一个常规问题描述中设计一个状态机。一开始,我们使用一个来自硬件设计教科书的经典例题。正如我们即将看到的,解决一个具体问题可以有不止一种状态机设计方法。
  基本原理   状 态机通常用来解决某些面向控制的问题,其控制流可以被画成在不同的状态之间变换。关于状态机有很多不同的定义和实际的描述。从理论层面来说,状态机是通过 改变状态来响应某些激励的一种自动响应。例如,一个具体的常规表达式的匹配可以被描述成这样一种自动响应。它会在输入字符串后经过一系列状态。如果达到了 目标状态,那么输入字符串和这个常规表达式匹配。   在控制软件中,常说状态机计算模型是基于有限性和确定性。这意味着可能的状态数或状态组合是有限的,以及在某一时刻状态机仅处于一个状态。稍后我们会看到,同一时刻仅处于一个状态的规则可以稍微放松,但现有状态是可确定的这一属性是非常重要的。
  如果你对于软件中实现的状态机是个新手,那么记住下面的这些概念是最重要的:
  状态:一个状态可以视为对系统当前状况的一种速记描述。举个简单的例子,考虑一个外围器件,有如下的顶层工作模式:开、关和待命。
     事件:事件是输入状态机的输入信息。事件可能会引起状态机改变状态。在待命模式下按下电视机的开启键就是一种事件,希望电视机重新工作,或者说是转换到开启状态。   转 换: 转换是从一个状态到另一个状态的有方向的路径。转换通常会标上事件名称,表明假如状态机处于起始状态时某一特定事件的发生会引起这次转换。最后结果是状态 机改变状态到该转换的目标状态。对于复杂事件,或者为了增加状态机表示法的表达能力,一个转换通常被保护条件保护着。转换的发生必须要满足相应的保护条 件。
     动作:动作是状态机在给定点及时做出的行为。典型地,动作在环境中执行某一任务,如对 I/O 器件的读写或类似的任务。动作可以和转换相结合,或者它们可以被设定成某一状态的进入或退出动作。
     上面这些概念是状态机设计方法的一些基本概念,是我们所能找到的 UML建模语言的子集。
  在基本概念的基础上进一步提高   现 在,我们来看一下经典课本中的面向状态的问题的例子,并一起来找出合适的状态机实现方法。实际上,我们会看到两个不同的解决方案,来说明对某一具体问题, 最好的解决方法是不存在的。两种方法都各有优劣,假如你要选择其中一个方法,又或者想用一个完全不同的方法,这都要依赖于你如何权衡。具体问题的描述如 下:   "一条繁忙的高速公路和一条很少使用的农场道路相交。农场道路边放一检测器,当有车辆需要穿过高速公路时会发出信号 C。交通灯控制器的工作原理如下:只要农场道路上没有检测到车辆,高速公路方向就一直保持是绿灯;如果农场道路上检测到车辆,则高速公路方向的交通灯从黄 灯变成红灯,而农场方向的交通灯变成绿灯;只要在农场道路上检测到车辆,其交通灯就保持绿灯,且不会超过一段预设的时间间隔以保证高速公路上的车流畅通; 假如这些条件满足,农场道路方向交通灯从绿变黄再变红,高速公路方向交通灯变绿;即使此时有车辆等着要过高速公路,高速公路方向的交通灯在预设的时间段内 还是保持绿灯。[From KATZ, Randy H., Contemporary Logic Design. University of California, Berkeley. 1994]"
本练习在编写时是从硬件角度考虑的,所以我们有一定的自由空间来考虑如何翻译该信息使其更好地适应软件环境。注意,本例中使用的惯例是黄灯总是由自己点亮。而世界上的其他地方使用的惯例可能不同。但这并不会影响这个问题的难度,它只是简化了我们跟踪颜色组合的难度。
  设计状态机有一个很简单的方法,描述如下:
  1.识别事件和动作   2.识别状态   3. 按层次分组   4.按并发分组
并不是说你一定要遵守这些特定的步骤才能取得成功。但如果能在一开始的时候就看清问题的事件和动作,以及其所存在的可能状态,那肯定会在你建立解决方案的结构时是有帮助的。而且你无论选择什么工具和实现方法,这都是正确的。
  继续深入研究   首先,我们来查看问题的描述找出可能的事件和动作。在状态机中,什么构成了一个事件呢?简而言之,事件就是可能会令状态机改变状态并执行某些动作的一种触发器。在交通灯的例子中,我们能找到很多潜在事件:
  农场道路上有车辆到来这一事件会对交通的状态函数有影响;
  在问题的描述中有好几个时间隔;
  高速公路上为绿灯的最小时间。这也可以作为农场道路上为绿灯的固定时间。
  两条道路上变成黄灯或由黄灯变成红灯或绿灯所需的延迟。   延迟间隔本身不是事件,但一个间隔的终止可以视为一个事件。我们可以得到两个有效的事件,一个是两条路上为绿灯时的长间隔事件,另一个是交通灯从绿转红或从红转绿的灯序列的短暂而统一的延时。
  根据以上描述,我们得到三个事件,分别称为 FarmRoadTrafficEvent,LongTimerEvent 和 ShortTimerEvent。
在 当前事件中,什么组成了一个动作呢?改变交通灯的颜色就是一个典型的动作。唯一的问题是在两条路上换灯是一个动作还是两个动作。***很简单。我们可以认为 是两个动作,每个动作管一条路,也可以看成一个动作。我选择把它视为两个不同的动作,理由稍后会说明。我把这两个动作称为SetFarmRoadLight() 和 SetHighwayLight() ,每个动作有一个颜色参数,表明所要显示的颜色。   这里的想法是我们所选的事件在某些情况下会触发交通的颜色的变化。 此外,我们需要某种跟踪时间间隔的方法,因此我们引入了一个特殊的动作,称为定时动作,其目的是对特定间隔开始定时,并在定时时间到是跟踪所出发的事件。为简单起见,我们称这个定时动作为 TimerAction()。
  要掌握交通灯系统的控制逻辑,我们需要了解可能的状态和其间的转换。第一个方案会用到下列观察结果:
  在 任何时间点交通灯都会表现为下列颜色组合之一:{GREEN, RED}, {YELLOW, RED}, {RED, RED}, {RED, YELLOW}, {RED, GREEN}, {RED, YELLOW}。从交通灯的工作原理可知,要使两条路上的车辆不相撞,很显然已经没有别的颜色组合了。每对括号中的第一个颜色是高速公路上的交通灯的颜 色。   上述颜色组合有固定的显示序列:{GREEN, RED}, {YELLOW, RED}, {RED, RED}, {RED, YELLOW}, {RED, GREEN}, {RED, YELLOW}, {RED, RED}, {YELLOW, RED} ,然后又从头开始。
  把上述序列中的每一项都视为一个可能的状态,这并不牵强附会,因为它在给定时间本来就是系统的实际状态。状态间的转换会由不同颜色变化的不同定时间隔来触发。如果我们假设序列从高速公路上为绿灯开始,那么整个序列由 FarmRoadTrafficEvent 来触发开始。 细心的读者可能已经注意到上面颜色组合的序列中有些是重复的。如都为红灯的组合出现了两次。我们应该把它们作为一个状态还是两个状态?我选择把序列中不同位置的项作为独立的状态。这意味着状态间的转换保持最简单。   现在,我们有了最基本的东西,即一系列事件、一些动作、一系列候选状态。   下面你可以看到一个用 UML 标记设计的图。
     现 在,我们画了一个圆环形的状态图,其转换由相应的事件标明。状态间还有改变交通灯颜色的进入动作。正如我们所看到的,只有开始状态需要设置两个灯的状态以 保证序列恰当启动。其他状态都只需改变一个前一状态的灯的颜色。这就是我为什么使用两个不同的动作函数!开始状态由一个来自初始状态(左上角的小圈)引出 的转换指出。   UML 使用初始状态和由它引出转换来指出所需的开始状态,这意味着我们可以直接在框图上指出系统的初始化。这个初始转换无需事件且比较含蓄。   从状态机的角度来说,这个设计基本完整,但它缺少对高速公路交通灯为绿灯间隔期间的处理。我们可以用很多方法来解决这个问题,但下列方法看起来够简单:
通过在 GreenH_RedF 状态中创建一个状态机来在模型中引入一个小的层次。
  这个状态机有两个状态和一个初始伪状态组成的。当进入周围的大状态时,NewGreen状态也同时被激活。
当由进入GreenH_RedF 所激发的长定时间隔终止时,我们让小状态机改变状态到 FarmRoadEventOK 。现在我们知道高速公路上的最小绿灯间隔已解决,如果有车的话农场道路上的灯变绿也是OK 的了。 保持高速公路上最小绿灯间隔所需的最后一点是从GreenH_RedF 状态转换出来的保护。这个转换只有在FarmRoadEventOK 状态被激活时才能被触发。这可以称为转换的正状态条件或正同步。变化结果可在下图看出。
     这个方案并不完美,因为它不能解决这个问题:在高速公路最小绿灯间隔期间到达农场道路的车辆被堵住了,直到间隔终止后另一辆车到来才能向前行驶。要解决这个问题,我们需要记录任何在绿灯间隔期间发生的FarmRoadTrafficEvent ,这样我们就可以在间隔终止时采取适当的动作。这里我们不再讨论该问题的完整解决方案,但假如你想要设计一个方案,下列方法会给你一些继续下去的提示: 引入一个状态机内部标志位变量,在每次高速公路上为绿灯状态时被初始化为零 在高速公路绿灯状态引入一个"内部反应",假如收到 FarmRoadTrafficEvent (可能NewGreen 作为保护状态 ),就把标志位置 1
FarmRoadEventOK 状态中的一个"进入反应"会发出一个信号,假如进入状态时标志位为 1 的话。(信号是一种可由状态机本身发送的特殊事件。) 由这个信号触发到黄灯的转换,短间隔定时器开始工作。 解决这个问题还有其他方法,但需要更多的UML 语句,而这是我想在这里避免的。 软件状态机和对应的硬件的不同之处在于软件状态机需要检测并对硬件环境中的事件作出反应。这就是说软件状态机的计算模型是基于一个检测事件(一种对由分立步骤组成的事件周期作出反应),而硬件状态机可以在某一引脚上的信号改变时"同时"作出反应。
(尽管实际的门的反转当然是位级的分立行为。)例如,一系列硬件信号可以在一个门中结合成一个事件,当一些信号的组合到达输入端时。在软件环境中,你需要让中断处理器或器件驱动来做这个结合的工作,或者让状态机来做。(除非你已控制整个硬件设计。)
一个不同的状态   正如前面承诺的,我们现在来看一个解决相同问题但完全不同的方法。这次我们不会研究地那么深入,但我们会从基于问题方程的观察开始: 农场道路上的交通灯和高速公路上的交通灯可以视为逻辑上完全独立的实体。这就是说它们可以建模成两个独立的状态机。 两个状态机之间有很多依赖关系:a) 农场道路交通灯必须能通过某种方式得知高速公路交通灯何时变成红灯,这样它才能开始到绿灯的转换。让高速公路的状态机在达到红灯状态时发送一个信号给另一个状态机,这样就能解决这个问题。b) 两个灯也共享定时间隔,和第一个模型中一样。 这两个状态机是同一个顶层状态机的两个平行区域。这样的好处是我们可以把整个解决方案看作是一个系统建立于分隔的准独立元素。下面是该解决方案的框图:
        这个解决方案还有个好处就是我们可以把状态框的颜色设置成该状态中交通灯的颜色。如果我们手头正好有模拟状态机的工具,那么我们就能在用事件触发状态机时看到交通灯切换颜色。   如果仔细查看这个设计,你就会发现它实际上有两种短的定时事件。要知道原因,可以看一下状态机中的***状态,无论哪个。请做这样一个实验,让离开***状态 的两个转换由同一事件触发。将会发生什么?我们在这个模型中引入了一个逻辑矛盾:由于一个确定的状态机经一个事件触发后产生的转换数量不能大于一,因此我 们必须在离开状态的转换上有一个单一的事件。(或者它们必须有互相排斥的保护条件.)
这种问题在非常规设计中很难发现,尤其是在用笔和纸来设计的情况下。如果在客户交付阶段运行的时候发生这种逻辑矛盾的错误,要找出问题出在哪里是很困难的。使用有模型检测功能的工具会给你在设计工作中带来很大的信心,不用担心最后会出现逻辑矛盾、死锁或相似的问题。   我们需要处理两个不同的短的定时事件,这让本解决方案比前一个要更复杂一点,但另一方面,我们用到的状态机的数量更少,因而可能导致运行时的代码尺寸更小。   舍入误差   我们已经看到了如何对同一个问题使用两种不同的状态机设计法来实现功能相同的解决方案。你选择哪个方法-或者你自己想出了一个完全不同的方法-这实际上并不重要,但通常情况下方法越简单越好。在状态机设计中使用图形化的设计工具是一种上升到抽象层面的非常简洁明了的方法,因为一个好的工具能够支持代码生成、测试、模拟和模型检测等功能。
巧合的是, IAR visualSTATE 正好提供这些特点。 转自:/website1/1.0.1.0/484/2/   
历史上的今天:【图文】有限状态机介绍_百度文库
两大类热门资源免费畅读
续费一年阅读会员,立省24元!
评价文档:
有限状态机介绍
上传于||暂无简介
大小:548.50KB
登录百度文库,专享文档复制特权,财富值每天免费拿!
你可能喜欢11777人阅读
unity3d(26)
State模式的定义: 不同的状态,不同的行为;或者说,每个状态有着相应的行为.
State模式在实际使用中比较多,适合&状态的切换&.因为我们经常会使用If elseif else 进行状态切换, 如果针对状态的这样判断切换反复出现,我们就要联想到是否可以采取State模式了.
不只是根据状态,也有根据属性.如果某个对象的属性不同,对象的行为就不一样,这点在数据库系统中出现频率比较高,我们经常会在一个数据表的尾部,加上property属性含义的字段,用以标识记录中一些特殊性质的记录,这种属性的改变(切换)又是随时可能发生的,就有可能要使用State.
在实际使用,类似开关一样的状态切换是很多的,但有时并不是那么明显,取决于你的经验和对系统的理解深度.
这里要阐述的是&开关切换状态& 和& 一般的状态判断&是有一些区别的, & 一般的状态判断&也是有 if..elseif结构,例如:
    if (which==1) state=&hello&;
    else if (which==2) state=&hi&;
    else if (which==3) state=&bye&;
这是一个 & 一般的状态判断&,state值的不同是根据which变量来决定的,which和state没有关系.如果改成:
    if (state.euqals(&bye&)) state=&hello&;
    else if (state.euqals(&hello&)) state=&hi&;
    else if (state.euqals(&hi&)) state=&bye&;
这就是 &开关切换状态&,是将state的状态从&hello&切换到&hi&,再切换到&&bye&;在切换到&hello&,好象一个旋转开关,这种状态改变就可以使用State模式了.
如果单纯有上面一种将&hello&--&&hi&--&&bye&--&&hello&这一个方向切换,也不一定需要使用State模式,因为State模式会建立很多子类,复杂化,但是如果又发生另外一个行为:将上面的切换方向反过来切换,或者需要任意切换,就需要State了.
public class Context{
  private Color state=
  public void push(){
    //如果当前red状态 就切换到blue
    if (state==Color.red) state=Color.
    //如果当前blue状态 就切换到green
    else if (state==Color.blue) state=Color.
    //如果当前black状态 就切换到red
    else if (state==Color.black) state=Color.
    //如果当前green状态 就切换到black
    else if (state==Color.green) state=Color.
    Sample sample=new Sample(state);
    sample.operate();
  public void pull(){
    //与push状态切换正好相反
    if (state==Color.green) state=Color.
    else if (state==Color.black) state=Color.
    else if (state==Color.blue) state=Color.
    else if (state==Color.red) state=Color.
    Sample2 sample2=new Sample2(state);
    sample2.operate();&
在上例中,我们有两个动作push推和pull拉,这两个开关动作,改变了Context颜色,至此,我们就需要使用State模式优化它.
另外注意:但就上例,state的变化,只是简单的颜色赋值,这个具体行为是很简单的,State适合巨大的具体行为,因此在,就本例,实际使用中也不一定非要使用State模式,这会增加子类的数目,简单的变复杂.
例如: 银行帐户, 经常会在Open 状态和Close状态间转换.
例如: 经典的TcpConnection, Tcp的状态有创建 侦听 关闭三个,并且反复转换,其创建 侦听 关闭的具体行为不是简单一两句就能完成的,适合使用State
例如:信箱POP帐号, 会有四种状态, start HaveUsername Authorized quit,每个状态对应的行为应该是比较大的.适合使用State
例如:在工具箱挑选不同工具,可以看成在不同工具中切换,适合使用State.如 具体绘图程序,用户可以选择不同工具绘制方框 直线 曲线,这种状态切换可以使用State.
State需要两种类型实体参与:
1.state manager 状态管理器 ,就是开关 ,如上面例子的Context实际就是一个state manager, 在state manager中有对状态的切换动作.
2.用抽象类或接口实现的父类,,不同状态就是继承这个父类的不同子类.
以上面的Context为例.我们要修改它,建立两个类型的实体.
第一步: 首先建立一个父类:
public abstract class State{
  public abstract void handlepush(Context c);
  public abstract void handlepull(Context c);
  public abstract void getcolor();
父类中的方法要对应state manager中的开关行为,在state manager中 本例就是Context中,有两个开关动作push推和pull拉.那么在状态父类中就要有具体处理这两个动作:handlepush() handlepull(); 同时还需要一个获取push或pull结果的方法getcolor()
下面是具体子类的实现:
public class BlueState extends State{
  public void handlepush(Context c){
     //根据push方法&如果是blue状态的切换到green& ;
     c.setState(new GreenState());
  public void handlepull(Context c){
     //根据pull方法&如果是blue状态的切换到red& ;
    c.setState(new RedState());
  public abstract void getcolor(){ return (Color.blue)}
同样 其他状态的子类实现如blue一样.
第二步: 要重新改写State manager 也就是本例的Context:
public class Context{
  private Sate state= //我们将原来的 Color state 改成了新建的S
  //setState是用来改变state的状态 使用setState实现状态的切换
  pulic void setState(State state){
    this.state=
  public void push(){
    //状态的切换的细节部分,在本例中是颜色的变化,已经封装在子类的handlepush中实现,这里无需关心
    state.handlepush(this);
    //因为sample要使用state中的一个切换结果,使用getColor()
    Sample sample=new Sample(state.getColor());
    sample.operate();
  public void pull(){
    state.handlepull(this);
    Sample2 sample2=new Sample2(state.getColor());
    sample2.operate();
至此,我们也就实现了State的refactorying过程.
以上只是相当简单的一个实例,在实际应用中,handlepush或handelpull的处理是复杂的.
状态模式优点:
(1) 封装转换过程,也就是转换规则
(2) 枚举可能的状态,因此,需要事先确定状态种类。
状态模式可以允许客户端改变状态的转换行为,而状态机则是能够自动改变状态,状态机是一个比较独立的而且复杂的机制,具体可参考一个状态机开源项目:
状态模式在工作流或游戏等各种系统中有大量使用,甚至是这些系统的核心功能设计,例如政府OA中,一个批文的状态有多种:未办;正在办理;正在批示;正在审核;已经完成等各种状态,使用状态机可以封装这个状态的变化规则,从而达到扩充状态时,不必涉及到状态的使用者。
在网络游戏中,一个游戏活动存在开始;开玩;正在玩;输赢等各种状态,使用状态模式就可以实现游戏状态的总控,而游戏状态决定了游戏的各个方面,使用状态模式可以对整个游戏架构功能实现起到决定的主导作用。
状态模式实质:
使用状态模式前,客户端外界需要介入改变状态,而状态改变的实现是琐碎或复杂的。
使用状态模式后,客户端外界可以直接使用事件Event实现,根本不必关心该事件导致如何状态变化,这些是由状态机等内部实现。
这是一种Event-condition-State,状态模式封装了condition-State部分。
每个状态形成一个子类,每个状态只关心它的下一个可能状态,从而无形中形成了状态转换的规则。如果新的状态加入,只涉及它的前一个状态修改和定义。
状态转换有几个方法实现:一个在每个状态实现next(),指定下一个状态;还有一种方法,设定一个StateOwner,在StateOwner设定stateEnter状态进入和stateExit状态退出行为。
状态从一个方面说明了流程,流程是随时间而改变,状态是截取流程某个时间片。
关 于状态机的一个极度确切的描述是它是一个有向图形,由一组节点和一组相应的转移函数组成。状态机通过响应一系列事件而“运行”。每个事件都在属于“当前” 节点的转移函数的控制范围内,其中函数的范围是节点的一个子集。函数返回“下一个”(也许是同一个)节点。这些节点中至少有一个必须是终态。当到达终态, 状态机停止。&
包含一组状态集(states)、一个起始状态(start state)、一组输入符号集(alphabet)、一个映射输入符号和当前状态到下一状态的转换函数(transition function)的计算模型。当输入符号串,模型随即进入起始状态。它要改变到新的状态,依赖于转换函数。在有限状态机中,会有有许多变量,例如,状态 机有很多与动作(actions)转换(Mealy机)或状态(摩尔机)关联的动作,多重起始状态,基于没有输入符号的转换,或者指定符号和状态(非定有 限状态机)的多个转换,指派给接收状态(识别者)的一个或多个状态,等等。
有 限状态机是一种概念性机器,它能采取某种操作来响应一个外部事件。具体采取的操作不仅能取决于接收到的事件,还能取决于各个事件的相对发生顺序。之所以能 做到这一点,是因为机器能跟踪一个内部状态,它会在收到事件后进行更新。为一个事件而响应的行动不仅取决于事件本身,还取决于机器的内部状态。另外,采取 的行动还会决定并更新机器的状态。这样一来,任何逻辑都可建模成一系列事件/状态组合。
unity 扣扣群
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:176410次
积分:2082
积分:2082
排名:第14527名
原创:39篇
转载:21篇
评论:14条
(1)(1)(1)(1)(2)(1)(4)(5)(1)(3)(2)(7)(3)(3)(3)(6)(1)(1)(11)(3)

参考资料

 

随机推荐