一杯咖啡带你读懂状态机

状态机的简单介绍

最近公司做棋牌的项目,当时还是不理解什么是状态机,当一个项目做完之后,大脑里已经有了一个状态机的概念,所以今天就与大家分享出来,由于本人的技术博浅,有很多地方没有理解通透的地方,请望大神指点,抱拳了。

什么是状态机?

我理解的状态机就是,当一个事件触发之后,就会去寻找一个相对应的大的状态,然后在到大的状态里去寻找小的状态,然后执行完毕,给用户返回。

可能本人理解的不是多通透,在此边查资料边学习,与大家一起分享。

一丶状态模式

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

状态模式主要解决的是当控制一个对象状态转换的条件表达式过于复杂时的情况,把状态的判断逻辑转移到表示不同状态的一系列类当中,可以把复杂的逻辑简化,当然如果这个状态判断很简单,那就没有必要用 "状态模式" 了。

状态模式结构图

State类,抽象状态类,定义一个接口以封装与Context的一个特定状态相关的行为

abstract class State
{
    public abstract void Handle(Context context) ;
}

State类

ConcreteState类,具体状态,每一个子类实现以个与Context的一个状态相关行为

ConcreteState类

Context类,维护一个ConcreteState子类的实列,这个实列定义当前的状态

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);            # 对请求做处理,并设置下一状态
    }
}                

Context类

客户端代码

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的子类之间,来减少相互依赖,好比把整个版面改成一个又一个的活字,此时候就容易维护和扩展了。

什么时候应该考虑使用状态模式呢?

当一个对象的行为取决于它的状态,并且它必须在运行时刻根据状态改变它的行为时,就可以考虑使用状态模式了。

参考设计模式举例 - 工作状态

代码结构图

抽象状态类,定义一个抽象方法"写程序"

public abstract class State
{
    public abstract void WriteProgram(Work w);
}

抽象状态类

上午和中午工作状态类

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点,则转入中午工作状态
        }
    }
}

上午工作状态类

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点则转入下午工作状态
        }
    }
}

中午工作状态

下午和傍晚工作状态类

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();
      }
    }
}

下午工作状态

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点,则转入睡眠工作状态
         }
    }
}

晚间工作状态

睡眠状态和下班休息状态类

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()
    # 工作初始化为上午工作状态,即上午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);
    }

}

工作类

客户端代码

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点 不行了,睡着了

状态机的理解,大概就是这样,从一个大的状态切换到一个小的状态。

时间: 2024-10-06 04:32:16

一杯咖啡带你读懂状态机的相关文章

少啰嗦!一分钟带你读懂Java的NIO和经典IO的区别

1.引言 很多初涉网络编程的程序员,在研究Java NIO(即异步IO)和经典IO(也就是常说的阻塞式IO)的API时,很快就会发现一个问题:我什么时候应该使用经典IO,什么时候应该使用NIO? 在本文中,将尝试用简明扼要的文字,阐明Java NIO和经典IO之间的差异.典型用例,以及这些差异如何影响我们的网络编程或数据传输代码的设计和实现的. 本文没有复杂理论,也没有像网上基它文章一样千篇一律的复制粘贴,有的只是接地气的通俗易懂,希望能给你带来帮助. (本文同步发布于:http://www.5

分分钟带你读懂 ButterKnife 的源码

为什么要写这一系列的博客呢? 因为在 Android 开发的过程中, 泛型,反射,注解这些知识进场会用到,几乎所有的框架至少都会用到上面的一两种知识,如 Gson 就用到泛型,反射,注解,Retrofit 也用到泛型,反射,注解 .学好这些知识对我们进阶非常重要,尤其是阅读开源框架源码或者自己开发开源框架. 前言 ButterKnife 这个开源库火了有一段时间了,刚开始它的实现原理是使用反射实现的,性能较差.再后面的 版本中逐渐使用注解+放射实现,性能提高了不少. ButterKnife是基于

Nginx系列教程(三)| 一文带你读懂 Nginx 的负载均衡

作者:JackTian 微信公众号:杰哥的IT之旅(ID:Jake_Internet) LAMP 系列导读 01. LAMP 系列教程(一)| 详解 Linux 环境下部署 HTTPD 服务 02. LAMP 系列教程(二)| 如何在 Linux 环境下部署 AWStats 分析系统来监控 Web 站点? 03. LAMP 系列教程(三)| 一文读懂 HTTPD 服务的访问控制 04. LAMP 系列教程(四)| MySQL 数据库系统(一) 05. LAMP 系列教程(五)| MySQL 数据

从源码入手,一文带你读懂Spring AOP面向切面编程

之前<零基础带你看Spring源码--IOC控制反转>详细讲了Spring容器的初始化和加载的原理,后面<你真的完全了解Java动态代理吗?看这篇就够了>介绍了下JDK的动态代理. 基于这两者的实现上,这次来探索下Spring的AOP原理.虽然AOP是基于Spring容器和动态代理,但不了解这两者原理也丝毫不影响理解AOP的原理实现,因为大家起码都会用. AOP,Aspect Oriented Programming,面向切面编程.在很多时候我们写一些功能的时候,不需要用到继承这么

Nginx系列教程(二)| 一文带你读懂Nginx的正向与反向代理

作者:JackTian 微信公众号:杰哥的IT之旅(ID:Jake_Internet) LAMP 系列导读 01. LAMP 系列教程(一)| 详解 Linux 环境下部署 HTTPD 服务 02. LAMP 系列教程(二)| 如何在 Linux 环境下部署 AWStats 分析系统来监控 Web 站点? 03. LAMP 系列教程(三)| 一文读懂 HTTPD 服务的访问控制 04. LAMP 系列教程(四)| MySQL 数据库系统(一) 05. LAMP 系列教程(五)| MySQL 数据

5分钟带你读懂事务隔离性与隔离级别

前言 我们在上一章节中介绍过数据库的带你了解数据库中事务的ACID特性的相关用法.本章节主要来介绍下数据库中一个非常重要的知识点事务的隔离级别.如有错误还请大家及时指出~ 问题: 事务的隔离级别有哪些? 如果并发事务没有进行隔离,会出现什么问题? 以下都是采用mysql数据库 在多个事务并发做数据库操作的时候,如果没有有效的避免机制,就会出现种种问题.大体上有以下问题: 一.引发的问题 在并发事务没有进行隔离的情况下,会发生如下问题. 问题一:脏读 脏读指一个事务读取了另外一个事务未提交的数据.

顾嘉:5分钟带你读懂《在线》逻辑

互联网成了基础设施,是创新平台:数据成了生产资料,是自然资源 :计算成了公共服务,是能源动力. ——王坚:<在线> 在我的记忆里,云计算.物联网.大数据是近年来被媒体和产业界炒得最热的几个概念了.然而时至今日,尽管有一大批创业公司以大无畏的勇气踏上了探索前路的征途,我们依然很少在现实工作和生活中真切地感受到这几个新技术带来的变化. 除了少部分出类拔萃的企业,大部分产品依旧停留在发布会的PPT中,还没来得及面世就被资本的力量洗刷殆尽.这背后自然有“物竞天择”的无常,也有市场竞争的残酷,但从主观上

一篇带你读懂TCP之“滑动窗口”协议

前言 你现在的努力,是为了以后有更多的选择. 在上一篇文章通过"表白"方式,让我们快速了解网络七层协议了解了网络七层协议. 接下来我们要把重心放在网络传输的可靠性上面.一起来看TCP协议,它是如何解决网络传输不可靠的问题.这其中有个很关键的部分,就是我们的滑动窗口协议. 从工程学角度上,我们来看一看滑动窗口协议,它到底解决了一个怎样的问题? 滑动窗口协议: TCP协议的使用 维持发送方/接收方缓冲区 缓冲区是 用来解决网络之间数据不可靠的问题,例如丢包,重复包,出错,乱序 在TCP协议

嘉益仕(Litns)带您读懂MES系统:选型篇

自从智能制造概念提出以来,制造执行系统MES在国内掀起了新一波的热潮.众多企业在技术发展.政策导向和自身需要的推动下,纷纷上马MES请添加链接描述项目. 由此也带动了MES软件开发企业的快速发展.一夜之间MES软件开发企业遍地开花,MES产品层出不穷,智能化.敏捷化.信息化.数字化--各种名词.概念.方案的密集炒作轰炸,让真正想上MES系统的企业着实应接不暇,颇有"乱花渐欲迷人眼"之感. 本篇小编将给大家讲解MES选型过程中需要遇到的各方面问题,希望嘉益仕(Litins)能为您的MES