设计模式之状态机模式

一、状态机模式介绍

状态机模式(State Machine Pattern)是一种用于描述对象行为的软件设计模式,属于行为型设计模式。在状态机模式中,对象的行为取决于其内部状态,并且在不同的状态下,对象可能会有不同的行为。这种模式通常涉及定义一组状态以及状态之间的转换规则,从而实现对对象行为的精确控制。

1、状态机模式的基本概念

状态机类图:

状态机模式主要包含以下几个要素:

  1. 状态(State):表示对象所处的特定状态。每个状态都定义了对象在该状态下的行为。
  2. 上下文(Context):上下文是包含状态机的对象。它维护了当前状态,并在状态之间的转换发生时更新状态。
  3. 转换(Transition):描述了对象从一个状态转移到另一个状态的过程。它通常受到一些条件或触发事件的影响。
  4. 动作(Action):动作是状态转换期间可能执行的操作或行为。这些动作可以是更新状态、执行计算、发送消息等。

2、状态机模式的特点

  1. 清晰的状态管理:通过明确定义系统的所有可能状态以及在这些状态之间的转换,帮助开发者清晰地管理和跟踪系统的状态。
  2. 简化复杂逻辑:将复杂的条件分支逻辑转换为状态图,使得逻辑更加直观易懂。
  3. 易于维护和扩展:状态机的结构使得对系统的修改和扩展变得更加容易。通过添加新的状态和转换规则,可以轻松适应需求的变化。
  4. 提高可测试性:由于状态机的行为是预定义的,因此可以更系统地进行测试,有助于确保系统的正确性和可靠性。

3、状态机模式的应用场景

状态机模式在多种应用场景中都有广泛的应用,包括但不限于以下几个方面:

  1. 游戏开发:用于游戏中的角色状态管理,如角色的移动、攻击、防御等状态。
  2. 嵌入式系统:用于描述设备的状态和状态转移,如自动售货机、电梯控制等。
  3. 网络通信:用于管理网络连接的状态,如连接建立、数据传输、连接关闭等。
  4. UI设计:用于管理UI元素的交互逻辑,如按钮的点击状态、表单的输入验证状态等。

二、状态机模式的实现例子

下面是一个简单的Java状态机模式例子。在这个例子中,我们将模拟一个简单的交通信号灯系统,它有三种状态:红灯(Red)、绿灯(Green)、黄灯(Yellow)。每个状态都有一个特定的行为,即打印出当前灯的颜色,并且每个状态都可以转换到下一个状态。

首先,我们定义一个TrafficLightState接口,它表示交通信号灯的所有可能状态:

public interface TrafficLightState {  void change(TrafficLightContext context);  
}

然后,我们为每种状态实现这个接口:

public class RedLightState implements TrafficLightState {  @Override  public void change(TrafficLightContext context) {  System.out.println("红灯亮");  context.setState(new GreenLightState());  }  
}  public class GreenLightState implements TrafficLightState {  @Override  public void change(TrafficLightContext context) {  System.out.println("绿灯亮");  context.setState(new YellowLightState());  }  
}  public class YellowLightState implements TrafficLightState {  @Override  public void change(TrafficLightContext context) {  System.out.println("黄灯亮");  context.setState(new RedLightState());  }  
}

接下来,我们定义TrafficLightContext类,它包含了当前的状态,并且提供了一个方法来改变状态:

public class TrafficLightContext {  private TrafficLightState state;  public TrafficLightContext() {  this.state = new RedLightState();  }  public void setState(TrafficLightState state) {  this.state = state;  }  public void change() {  state.change(this);  }  
}

最后,我们创建一个客户端来模拟交通信号灯的状态变化:

public class Client {  public static void main(String[] args) {  TrafficLightContext context = new TrafficLightContext();  // 模拟状态变化  context.change();  context.change();  context.change();  context.change();  context.change();  }  
}

在这个例子中,TrafficLightContext类维护了当前的交通信号灯状态,并且提供了一个change方法来改变状态。每个状态类都实现了TrafficLightState接口,并且在其change方法中定义了下一个状态。客户端通过调用TrafficLightContextchange方法来模拟交通信号灯的状态变化。 

现实中的状态转变,比这个复杂多了,一个状态节点可能有多个action操作,类似订单状态的流转,无法直接套用状态机模式,应该有记录状态变迁的全景图(核心要素:当前状态,当前状态可选动作,动作执行后状态迁移)。

以下是一个简单的例子,记录当前状态,可选动作及执行动作后状态的一个例子,用于约束状态的变迁,。

package demo;import java.util.HashMap;
import java.util.Map;public class StateMachine {/*** key:当前状态 ,value: Map<String, String>,可选的动作及后续状态,key:xxxAction,value:nextState*/private Map<String, Map<String, String>> stateMap;public StateMachine() {stateMap = new HashMap<String, Map<String, String>>();// 初始状态可以执行的Action及执行后的动作Map<String, String> initActionMap = new HashMap<String, String>();initActionMap.put("runAction", "run");stateMap.put("init", initActionMap);// run状态下可以执行的动作Map<String, String> runActionMap = new HashMap<String, String>();runActionMap.put("stopAction", "stop");runActionMap.put("sleepAction", "sleep");runActionMap.put("endAction", "end");stateMap.put("run", runActionMap);// sleep状态下可以执行的动作Map<String, String> sleepActionMap = new HashMap<String, String>();sleepActionMap.put("runAction", "run");stateMap.put("sleep", sleepActionMap);// stop状态下可以执行的动作Map<String, String> stopActionMap = new HashMap<String, String>();stopActionMap.put("runAction", "run");stateMap.put("stop", stopActionMap);}public String getNextState(String curState, String action) {Map<String, String> curStateMap = stateMap.get(curState);if (curStateMap == null) {System.out.println("curState error");return "";}String nextState = curStateMap.get(action);if (nextState == null) {System.out.println("acction error");return "";}return nextState;}public static void main(String[] args) {StateMachine sm = new StateMachine();String nextState = sm.getNextState("init", "runAction");System.out.println(nextState);nextState = sm.getNextState("run", "stopAction");System.out.println(nextState);nextState = sm.getNextState("stop", "runAction");System.out.println(nextState);nextState = sm.getNextState("run", "endAction");System.out.println(nextState);}}

三、总结

        状态机模式是一种强大的工具,能够帮助开发者在软件开发中处理复杂的逻辑和状态管理问题。通过明确定义系统的状态和转换规则,状态机模式使得系统的行为更加清晰、可控和易于维护。同时,状态机模式还具有广泛的应用场景和灵活的实现方式,适用于多种复杂的软件开发需求。

如果状态模式对你有用,记得点赞收藏。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/370821.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Java信号量semaphore的原理与使用方法

Semaphore的基本概念 在Java中&#xff0c;Semaphore是位于java.util.concurrent包下的一个类。它的核心就是维护了一个许可集。简单来说&#xff0c;就是有一定数量的许可&#xff0c;线程需要先获取到许可&#xff0c;才能执行&#xff0c;执行完毕后再释放许可。 那么&…

Unity 简单载具路线 Waypoint 导航

前言 在游戏开发和导航系统中&#xff0c;"waypoint" 是指路径中的一个特定位置或点。它通常用于定义一个物体或角色在场景中移动的目标位置或路径的一部分。通过一系列的 waypoints&#xff0c;可以指定复杂的移动路径和行为。以下是一些 waypoint 的具体用途&…

YoloV8改进策略:Block改进|轻量实时的重参数结构|最新改进|即插即用(全网首发)

摘要 本文使用重参数的Block替换YoloV8中的Bottleneck&#xff0c;GFLOPs从165降到了116&#xff0c;降低了三分之一&#xff1b;同时&#xff0c;map50-95从0.937涨到了0.947。 改进方法简单&#xff0c;只做简单的替换就行&#xff0c;即插即用&#xff0c;非常推荐&#xf…

【leetcode52-55图论、56-63回溯】

图论 回溯【56-63】 46.全排列 class Solution:def permute(self, nums):result []self.backtracking(nums, [], [False] * len(nums), result)return resultdef backtracking(self, nums, path, used, result):if len(path) len(nums):result.append(path[:])returnfor i …

pdf怎么转换成图片格式文件,pdf文档怎么转换成图片格式

在数字化时代&#xff0c;pdf文件转换成图片格式是一种常见的操作&#xff0c;无论是在工作还是日常生活中&#xff0c;我们总会遇到需要将pdf文件转换为图片的需求。这可能是因为图片格式更易于分享、展示或编辑。那么&#xff0c;如何高效地将pdf转换成图片呢&#xff1f;本文…

QListWidget 缩略图IconMode示例

1、实现的效果如下&#xff1a; 2、实现代码 &#xff08;1&#xff09;头文件 #pragma once #include <QtWidgets/QMainWindow> #include "ui_QListViewDemo.h" enum ListDataType { ldtNone -1, ldtOne 0, ldtTwo 1, }; struct ListData…

Error in onLoad hook: “SyntaxError: Unexpected token u in JSON at position 0“

1.接收页面报错 Error in onLoad hook: "SyntaxError: Unexpected token u in JSON at position 0" Unexpected token u in JSON at position 0 at JSON.parse (<anonymous>) 2.发送页面 &#xff0c;JSON.stringify(item) &#xff0c;将对象转换为 JSO…

计算机网络——数据链路层(点对点协议PPP)

点对点协议PPP的概述 对于点对点的链路&#xff0c;目前使用得最广泛的数据链路层协议是点对点协议 PPP (Point-to-Point Protocol)。 它主要应用于两个场景&#xff1a; 用户计算机与ISP之间的链路层协议就是点对点协议 PPP&#xff0c;1999年公布了回以在以太网上运行的PPP协…

事务(数据库)

是一组操作的集合&#xff0c;是一个不可分割的工作单位&#xff0c;事物会把所有的操作作为一个整体一起向系统提交或撤销操作请求&#xff0c;这些操作要么同时成功&#xff0c;要么同时失败 create table account(id int auto_increment primary key comment 主键ID,name va…

人工智能在病理切片虚拟染色及染色标准化领域的系统进展分析|文献速递·24-07-07

小罗碎碎念 本期文献主题&#xff1a;人工智能在病理切片虚拟染色及染色标准化领域的系统进展分析 这一期文献的速递&#xff0c;是有史以来数量最大的一次&#xff0c;足足有十一篇&#xff0c;本来打算分两期写&#xff0c;但是为了知识的系统性&#xff0c;我决定咬咬牙&…

昇思MindSpore学习笔记5-01生成式--LSTM+CRF序列标注

摘要&#xff1a; 记录昇思MindSpore AI框架使用LSTMCRF模型分词标注的步骤和方法。包括环境准备、score计算、Normalizer计算、Viterbi算法、CRF组合,以及改进的双向LSTMCRF模型。 一、概念 1.序列标注 标注标签输入序列中的每个Token 用于抽取文本信息 分词(Word Segment…

常见的Java运行时异常

常见的Java运行时异常 1、ArithmeticException&#xff08;算术异常&#xff09;2、ClassCastException &#xff08;类转换异常&#xff09;3、IllegalArgumentException &#xff08;非法参数异常&#xff09;4、IndexOutOfBoundsException &#xff08;下标越界异常&#xf…

dell Vostro 3690安装win11 23h2 方法

下载rufus-4.5.exe刻U盘去除限制 https://www.dell.com/support/home/zh-cn/product-support/product/vostro-3690-desktop/drivers dell官网下载驱动解压到U盘 https://dl.dell.com/FOLDER09572293M/2/Intel-Rapid-Storage-Technology-Driver_88DM9_WIN64_18.7.6.1010_A00_01…

ros1仿真导航机器人 navigation

仅为学习记录和一些自己的思考&#xff0c;不具有参考意义。 1navigation导航框架 2导航设置过程 &#xff08;1&#xff09;启动仿真环境 roslaunch why_simulation why_robocup.launch &#xff08;2&#xff09;启动move_base导航、amcl定位 roslaunch why_simulation nav…

基于Maximin的异常检测方法(MATLAB)

异常存在于各个应用领域之中&#xff0c;往往比正常所携带的信息更多也更为重要。例如医疗系统中疾病模式&#xff0c;信用卡消费中的欺诈行为&#xff0c;数据库中数据泄露&#xff0c;大型机器故障&#xff0c;网络入侵行为等。大数据技术体系的快速兴起与发展&#xff0c;加…

使用Spring Boot和自定义缓存注解优化应用性能

在现代应用开发中&#xff0c;缓存是提高系统性能和响应速度的关键技术之一。Spring Boot提供了强大的缓存支持&#xff0c;但有时我们需要更灵活的缓存控制。本文将介绍如何使用Spring Boot和自定义缓存注解来优化应用性能。 1. 为什么需要自定义缓存注解&#xff1f; Sprin…

【ue5】虚幻5同时开多个项目

正常开ue5项目我是直接在桌面点击快捷方式进入 只会打开一个项目 如果再想打开一个项目需要进入epic 再点击启动就可以再开一个项目了

步进电机改伺服电机

步进电机&#xff1a; 42&#xff1a;轴径5mm 57&#xff1a;轴径8mm 86&#xff1a;轴径14mm 【86CME120闭环】// 12牛米 伺服电机&#xff1a; 40&#xff1a; 60&#xff1a; 80&#xff1a; 86&#xff1a; ECMA——C 1 0910 R S 4.25A 轴径…

分享大厂对于缓存操作的封装

hello&#xff0c;伙伴们好久不见&#xff0c;我是shigen。发现有两周没有更新我的文章了。也是因为最近比较忙&#xff0c;基本是993了。 缓存大家再熟悉不过了&#xff0c;几乎是现在任何系统的标配&#xff0c;并引申出来很多的问题&#xff1a;缓存穿透、缓存击穿、缓存雪崩…

UEC++ 虚幻5第三人称射击游戏(二)

UEC++ 虚幻5第三人称射击游戏(二) 派生榴弹类武器 新建一个继承自Weapon的子类作为派生榴弹类武器 将Weapon类中的Fire函数添加virtual关键字变为虚函数让榴弹类继承重写 在ProjectileWeapon中重写Fire函数,新建生成投射物的模版变量 Fire函数重写逻辑 代码//生成的投射物U…