聊一聊状态机

聊一聊状态机

最近接手维护一个老项目,项目中使用到了状态机,还接到一个需求需要在原有的流程中新增一个流程节点。由于项目中使用到了状态机,所以在做技术方案的时候需要梳理下整个业务的流程,然后再确定新增的节点怎么添加。在梳理的过程中也和同事聊了下状态机,对什么时候在项目是否有必要使用状态机都发表了下自己的观点。那么我们从什么是状态机?状态机的优缺点?什么时候适合用状态机?状态模式和领域驱动设计有关系吗?这几个方面来聊下装机。

一、什么是状态机

1.状态机的定义

状态机,又称有限状态自动机(Finite State Machine,FSM),是现实事物运行规则抽象而成的一个数学模型。它由状态寄存器和组合逻辑电路构成,能够根据控制信号按照预先设定的状态进行状态转移,是协调相关信号动作、完成特定操作的控制中心。

状态机主要分为两大类:第一类,若输出只和状态有关而与输入无关,则称为 Moore 状态机;第二类,输出不仅和状态有关而且和输入有关系,则称为 Mealy 状态机。

2.举个例子

我们以汽车的变速箱来当做状态机来举个🌰例子,如果是自动挡的变速箱,那么变速对应的每个档位就一个状态,如P档是表示停状态、N档是发动起空转状态、D 档是行驶状态、R 档倒车状态。而每一次的换挡行为就都会改变变速箱的状态,这个换挡行为就相当于状态的状态转换事件。状态机的状态转换事件都会有限制,而变速箱上的状态转换限制是物理限制,以我雪佛兰为例,从P档转换到D档,需要从 P 档 -> N 档- > R 档 -> D 档按顺序转换,不能直接从 P 档转到D档。

二、状态机怎么玩

1.状态机的组成

状态(State)

确定状态:明确系统的各个状态,变速箱的各个档位就相当于状态机的状态。

状态转移(Transition)

确定转移:定义状态之间的转移,并确定在满足什么条件时进行转移。在变速箱上面每次换挡都是一次状态转移。

行为动作(Action)

定义动作:针对不同的状态,定义对应的动作,这些动作可能是在进入状态时进行,退出状态时进行,或者在特定转移时进行。

事件(Event)

事件:也可以叫做 Trigger,表达的意思都一样,就是要执行某个操作的触发器或口令:当状态机处于某个状态时,只有外界告诉状态机要干什么事情的时候,状态机才会去执行具体的行为,来完成外界想要它完成的操作。

2.状态机图

了解基础知识后,再画出状态图,就可以按照状态图来写代码去实现这个状态机的逻辑了

三、状态机有用吗

1.状态机给我们带来了什么

在前面的章节里面我们介绍了什么是状态机,和怎么使用状态机。在开发的日常开发中,我们总会有这样的思考,状态机的代码那么复杂,复杂的代码可能拖慢了我们的开发进度,我们有必要使用状态机吗?那么这里面我们就来分析下状态机可以给我们带来什么,而又有哪些不好的地方。

先来说说优点
  1. 易于理解和设计:状态机可以使业务模型清晰,开发人员可以更好地理解业务逻辑。
  2. 易于维护和扩展:状态机设计模式,在开发人员进行维护和扩展代码时是比较方便的。
  3. 可以支持复杂模型:状态机模型在复杂的业务模型中,大大减少了开发和维护的时间。
哪些地方不好用
  1. 代码复杂性:状态机编程需要较多接口和实现类,因此代码复杂度会高一点,理解难度也会高一点。
  2. 运行效率:状态机编程因为需要经常创建状态机实例,运行效率会稍微较一点。
  3. 难以调试:状态机编程的代码设计模式用的会比较多,调试的时候跳转会比较复杂。

总的来讲就是状态机是使用起来的时候是方便的,也有利于后期维护和扩展,但是使用成本比较高,技术上对程序员有一定的门槛。但是这些都是从技术上来讲的,如果从其他的维度来看会不会有些不同呢?

2.状态机在业务上可以带来什么

前面说了状态机的优劣,都是以技术的角度去看的。然而如果换一个从业务的角度来看状态机可以带来什么。

从业务来讲
  1. 清晰的业务流转过程:在设计状态机的时候需要确定整个业务所有的状态,和状态对应的流转过程,做完这个设计对应因为的流转过程会非常的清晰。虽然业务流程是产品经理来设计的,但是在做技术分析的时候充分的讨论和确定业务流转过程在技术上的可行性是很重要的,它可以让产品经理和技术人员对这个新的产品有更加深刻的理解,对业务的流转过程更加清晰。
  2. 清晰的业务边界:一个技术上的设计模式,可以对业务上提供哪些帮助呢?在这么多设计模式中状态模式是一个比较偏向也业务的的设计模式,简单的说就是使用状态模式必须有对应的业务场景,每一个状态模式只能为对应的业务场景服务。如果某个业务上使用了状态机,那么这个业务这个状态机不会只是单独的在某个业务实现上使用了状态机,而一定是在某个模块的整个生命周期上使用了状态机。举个例子一个订单流程使用状态机,订单流程有【下单】->【支付】->【发货】->【确定收款】结果几个状态。如果使用了状态机就不能只对某个流程节点比如【下单】使用状态机其他其他节点不使用, 单独使用状态机的话这个状态机就是不完整的。而如果一个订单流程都使用了状态机,那么你会发现这个状态机的边界,刚好是这个订单流程的业务边界。

四、状态模式和领域驱动设计中有关系吗

领域驱动设计是软件开发的一种方式,问题复杂的地方通过将具体实现和一个不断改进的核心业务概念的模型连接解决。这个概念是 Eric Evans 提出的,关于领域驱动设计的定义,Glossary of Domain-Driven Design Terms,网上有很多这里就不详细介绍了。

1.减少沟通成本

前面我们聊了状态机,现在又突然跳到 DDD(领域驱动设计)这两个有什么关系,这里就有必要说下DDD里面的一种开发思想就是让领域专家和技术专家建立共同的语言去一起开发一个系统。而状态机刚好是把这个业务流程,用技术上的语言表达出来,这样技术专家和领域专家会有一个通用的模型是去描述各自要表达的思想,从而更好进行沟通和开发。

2.辅助领域模型设计

对于状态机出来说除了可降低领域专家和技术专家的沟通成本,并且在辅助领域模型设计方面还有以下几点帮助:

  1. 辅助实体设计:前面说到状态机在业务上的可以帮忙划清业务边界,而 DDD 里面分析清楚各个实体的业务边界是一个比较困难的事情。然而如果业务页面里面有使用状态机,那么这个状态机的业务边界差不多刚好就是一个实体的业务边界。而且如果这个状态机就自状态的话,那么子状态机很有可能当前实体的一个子实体。如果一个状态机有多个子状态机,而这个状态机就很有可能是一个聚合根也叫做根实体。这个分析可能不会有每次都对,但是对新手刚开始使用 DDD 的时候对实体设计无从下手的时候是一个很好的设计思路
  2. 辅助领域事件设计:状态机除了了可以辅助实体设计,对领域事件的设计也是有帮助的。因为状态机上每次状态转换都会对应一个动作,而这个动作是在状态机上的,如果这个状态机是一个实体,那么这个状态机上的动作就有可能会触发一个领域事件。虽然状态机不能直接帮助领域事件的设计,但是可以为领域事件的设计缩小范围,因为一般情况下只有实体的状态发生变化了才会产生领域事件。
  3. 其他设计方面的帮助:其他方面的话因为状态机可以让我们找到业务的实体,那么在设计的时候有时候不好区分的值对象和实体,在确认了实体以后,那剩下的应该就是值对象了。还有就是在确认了实体和聚合根后,业务的界限上下文就清晰起来了,帮助界限上下文的划分。

3.做个小结

对于状态模式辅助 DDD 的设计这个方面来说,状态机的一些概念和 DDD 里面的一些概念是有些相似的。对于一些刚接触 DDD 的人来讲,通过先分析一个业务的状态模式,然后再以状态模式去用 DDD 的思想设计系统是有些帮助的。从这个方面来讲状态模式是可以帮助新人去理解 DDD,降低一些 DDD 入门的门槛。但是如果要用好 DDD 的话,光靠状态模式是远远不够的,DDD 是一套完整的软件设计的方法论,而状态机只是状态模式的一种实现。

五、最后做个大总结

1.什么时候时候适合用状态机

状态机的入门有一定的门槛但不是太高,在使用前最好是听取下经验的技术人员建议再确定是否使用状态机,如果给一点具体建议的话个人感觉需要考虑以下几点:

  1. 状态数量:如果业务的状态超过 3 个,可以考虑使用状态机,如果状态超过 8 就很有必要使用状态机。
  2. 分支流程比较多:如果一个业务流程的流转从头到尾都的流转状态类型超过 3 种,就有必须要使用使用状态机。
  3. 流程状态可能有经常变更的:如果一个业务刚开始只是开发了一个基础版本,后面经过迭代会逐渐完善整个业务流程,这个时候就有很有必要使用状态机。
  4. 有经验的开发者:如果团队内有多位状态机开发的技术人员,那么使用状态机是种不错的选项。因为既是状态机提高代码的复杂度,但对有经验的开发者来说并不会降低他们的开发速度和质量。

2.状态机可以给我们带来什么

状态机作为一种设计模式,除了在技术上可以让我们的代码变动更加的灵活和易于扩展以外,它更大的优点是在可以在做技术分析的时候让我们更加清晰地理解整个业务流程。个人觉得在项目中是不是要使用状态机不是重点,重点是使用状态机的思想去分析业务流程,只要能清晰的理解业务流程,不管用什么方式去实现这个业务都会是事半功倍的。

推荐阅读

自助取数平台探索与实践

ES分片均衡策略分析与改进

浅析 5 种 React 组件设计模式

图数据库由浅入深

测试用例设计心得

招贤纳士

政采云技术团队(Zero),Base 杭州,一个富有激情和技术匠心精神的成长型团队。规模 500 人左右,在日常业务开发之外,还分别在云原生、区块链、人工智能、低代码平台、中间件、大数据、物料体系、工程平台、性能体验、可视化等领域进行技术探索和实践,推动并落地了一系列的内部技术产品,持续探索技术的新边界。此外,团队还纷纷投身社区建设,目前已经是 google flutter、scikit-learn、Apache Dubbo、Apache Rocketmq、Apache Pulsar、CNCF Dapr、Apache DolphinScheduler、alibaba Seata 等众多优秀开源社区的贡献者。

如果你想改变一直被事折腾,希望开始折腾事;如果你想改变一直被告诫需要多些想法,却无从破局;如果你想改变你有能力去做成那个结果,却不需要你;如果你想改变你想做成的事需要一个团队去支撑,但没你带人的位置;如果你想改变本来悟性不错,但总是有那一层窗户纸的模糊......如果你相信相信的力量,相信平凡人能成就非凡事,相信能遇到更好的自己。如果你希望参与到随着业务腾飞的过程,亲手推动一个有着深入的业务理解、完善的技术体系、技术创造价值、影响力外溢的技术团队的成长过程,我觉得我们该聊聊。任何时间,等着你写点什么,发给 zcy-tc@cai-inc.com

微信公众号

文章同步发布,政采云技术团队公众号,欢迎关注

相关推荐
Estar.Lee4 小时前
查手机号归属地免费API接口教程
android·网络·后端·网络协议·tcp/ip·oneapi
2401_857610036 小时前
SpringBoot社团管理:安全与维护
spring boot·后端·安全
凌冰_7 小时前
IDEA2023 SpringBoot整合MyBatis(三)
spring boot·后端·mybatis
码农飞飞7 小时前
深入理解Rust的模式匹配
开发语言·后端·rust·模式匹配·解构·结构体和枚举
一个小坑货7 小时前
Rust 的简介
开发语言·后端·rust
monkey_meng7 小时前
【遵守孤儿规则的External trait pattern】
开发语言·后端·rust
Estar.Lee8 小时前
时间操作[计算时间差]免费API接口教程
android·网络·后端·网络协议·tcp/ip
新知图书8 小时前
Rust编程与项目实战-模块std::thread(之一)
开发语言·后端·rust
盛夏绽放9 小时前
Node.js 和 Socket.IO 实现实时通信
前端·后端·websocket·node.js
Ares-Wang9 小时前
Asp.net Core Hosted Service(托管服务) Timer (定时任务)
后端·asp.net