面试官竟然是个小黑子,问我用过状态机吗

embedded/2024/10/22 17:25:12/

状态机的组成

状态机是一种抽象的数学模型,描述了对象或系统在特定时间点可能处于的各种状态以及状态之间的转换规则。它由一组状态、事件、转移和动作组成,用于模拟对象在不同条件下的行为和状态变化。

image-20240423094124100

状态机包括以下基本组成部分:

  • 状态(State):表示对象或系统当前的状态,例如开、关、就绪等。
  • 事件(Event):触发状态转换的动作或条件,例如按钮点击、消息到达等。
  • 转移(Transition):定义了从一个状态到另一个状态的转换规则,通常与特定事件相关联。
  • 动作(Action):在状态转换过程中执行的操作或行为,例如更新状态、记录日志等。

状态机,也就是 State Machine ,不是指一台实际机器,而是指一个数学模型。说白了,一般就是指一张状态转换图。例如,根据自动门的运行规则,我们可以抽象出下面这么一个图。

image-20240423095540911

简单实现

在计算机中,状态机通常用编程语言来实现。在 C、C++、Java、Python 等编程语言中,可以通过使用 switch-case 语句、if-else 语句、状态转移表等来实现状态机。在下面还有更加优雅的方式,使用 Spring 状态机 来实现。

if-else 实现状态机

在上面的示例中,我们使用 if-else 结构根据当前活动来控制音乐的播放状态,并执行相应的行为。代码如下:

java">public class BasketballMusicStateMachineUsingIfElse {private boolean isPlayingMusic;public BasketballMusicStateMachineUsingIfElse() {this.isPlayingMusic = false; // 初始状态为音乐未播放}public void playMusic() {if (!isPlayingMusic) {System.out.println("Music starts playing...");isPlayingMusic = true;}}public void stopMusic() {if (isPlayingMusic) {System.out.println("Music stops playing...");isPlayingMusic = false;}}public void performActivity(String activity) {if ("basketball".equals(activity)) {System.out.println("Music~");playMusic(); // 打篮球时播放音乐} else if ("sing_rap".equals(activity)) {System.out.println("哎哟你干嘛!");stopMusic(); // 唱跳Rap时停止音乐} else {System.out.println("Invalid activity!");}}public static void main(String[] args) {BasketballMusicStateMachineUsingIfElse stateMachine = new BasketballMusicStateMachineUsingIfElse();// 测试状态机stateMachine.performActivity("basketball"); // 打篮球,音乐开始播放stateMachine.performActivity("sing_rap"); // 唱跳Rap,音乐停止播放stateMachine.performActivity("basketball"); // 再次打篮球,音乐重新开始播放}
}
switch-case 实现状态机

在这个示例中,我们使用 switch-case 结构根据不同的活动来控制音乐的播放状态,并执行相应的行为。代码如下:

java">public class BasketballMusicStateMachineUsingSwitchCase {private boolean isPlayingMusic;public BasketballMusicStateMachineUsingSwitchCase() {this.isPlayingMusic = false; // 初始状态为音乐未播放}public void playMusic() {if (!isPlayingMusic) {System.out.println("Music starts playing...");isPlayingMusic = true;}}public void stopMusic() {if (isPlayingMusic) {System.out.println("Music stops playing...");isPlayingMusic = false;}}public void performActivity(String activity) {switch (activity) {case "basketball":System.out.println("Music ~");playMusic(); // 打篮球时播放音乐break;case "sing_rap":System.out.println("哎哟 你干嘛 ~");stopMusic(); // 唱跳Rap时停止音乐break;default:System.out.println("Invalid activity!");}}public static void main(String[] args) {BasketballMusicStateMachineUsingSwitchCase stateMachine = new BasketballMusicStateMachineUsingSwitchCase();// 测试状态机stateMachine.performActivity("basketball"); // 打篮球,音乐开始播放stateMachine.performActivity("sing_rap"); // 唱跳Rap,音乐停止播放stateMachine.performActivity("basketball"); // 再次打篮球,音乐重新开始播放}
}

是不是感觉状态机其实经常在我们的日常使用中捏~,接下来带大家使用更优雅的状态机 Spring 状态机。

image-20240423100302874
使用 Spring 状态机

1)引入依赖

<dependency><groupId>org.springframework.statemachine</groupId><artifactId>spring-statemachine-core</artifactId><version>2.0.1.RELEASE</version>
</dependency>

2)定义状态和事件的枚举

代码如下:

java">public enum States {IDLE,       // 空闲状态PLAYING_BB, // 打篮球状态SINGING     // 唱跳Rap状态
}
public enum Event {START_BB_MUSIC, // 开始播放篮球音乐事件STOP_BB_MUSIC   // 停止篮球音乐事件
}

3)配置状态机

代码如下:

java">@Configuration
@EnableStateMachine
public class BasketballMusicStateMachineConfig extends EnumStateMachineConfigurerAdapter<States, Event> {@Autowiredprivate BasketballMusicStateMachineEventListener eventListener;@Overridepublic void configure(StateMachineConfigurationConfigurer<States, Event> config) throws Exception {config.withConfiguration().autoStartup(true).listener(eventListener); // 设置状态机事件监听器}@Overridepublic void configure(StateMachineStateConfigurer<States, Event> states) throws Exception {states.withStates().initial(States.IDLE).states(EnumSet.allOf(States.class));}@Overridepublic void configure(StateMachineTransitionConfigurer<States, Event> transitions) throws Exception {transitions.withExternal().source(States.IDLE).target(States.PLAYING_BB).event(Event.START_BB_MUSIC).and().withExternal().source(States.PLAYING_BB).target(States.SINGING).event(Event.STOP_BB_MUSIC).and().withExternal().source(States.SINGING).target(States.PLAYING_BB).event(Event.START_BB_MUSIC);}
}

4)定义状态机事件监听器

代码如下:

java">@Component
public class BasketballMusicStateMachineEventListener extends StateMachineListenerAdapter<States, Event> {@Overridepublic void stateChanged(State<States, Event> from, State<States, Event> to) {if (from.getId() == States.IDLE && to.getId() == States.PLAYING_BB) {System.out.println("开始打篮球,music 起");} else if (from.getId() == States.PLAYING_BB && to.getId() == States.SINGING) {System.out.println("唱跳,你干嘛");} else if (from.getId() == States.SINGING && to.getId() == States.PLAYING_BB) {System.out.println("继续打篮球,music 继续");}}
}

5)编写单元测试

java">@SpringBootTest
class ChatApplicationTests {@Resourceprivate StateMachine<States, Event> stateMachine;@Testvoid contextLoads() {//开始打球,music 起stateMachine.sendEvent(Event.START_BB_MUSIC);//开始唱跳,你干嘛stateMachine.sendEvent(Event.STOP_BB_MUSIC);//继续打球,music 继续stateMachine.sendEvent(Event.START_BB_MUSIC);}
}

效果如下:

image-20240423103523546

在上面的示例中,我们定义了一个状态机,用于控制在打篮球时音乐的播放和唱跳 Rap 的行为。通过触发事件来执行状态转移,并通过事件监听器监听状态变化并执行相应的操作。

image-20240423103604502


http://www.ppmy.cn/embedded/10526.html

相关文章

SpringBoot常用20个注解及其作用

1、SpringBootApplication: 这是一个组合注解&#xff0c;包括了Configuration、EnableAutoConfiguration 和 ComponentScan。它标识了一个主程序类&#xff0c;用于启动 Spring Boot 应用。 2、RestController: 这个注解用于标识一个类&#xff0c;表示这个类中的所有方…

Office疑难杂症-Word页码重复无法修改

在现代办公环境中&#xff0c;Microsoft Office 套件扮演着不可或缺的角色&#xff0c;尤其是 Word 文档处理软件&#xff0c;在日常生活和工作中的应用广泛。然而&#xff0c;即使是这样成熟的软件&#xff0c;也不免有一些令人头疼的技术问题。本文将详细介绍如何解决Word中页…

Git | 分支管理

Git | 分支管理 文章目录 Git | 分支管理1、理解分支2、创建分支&&切换分支3、合并分支4、删除分支5、合并冲突6、分支管理策略合并分支模式实际工作中分支策略bug分支删除临时分支 1、理解分支 分支就类似分身。 在版本回退中&#xff0c;每次提交Git都会将修改以git…

2.微服务技术

微服务技术对比 DubboSpringCloudSpringCloudAlibaba注册中心zookeeper&#xff0c;RedisEureka,ConsulNacos,Eureka服务远程调用Dubbo协议Feign(http协议)Dubbo,Feign配置中心SpringCloudConfigSpringCloudConfig,Nacos服务网关SpringCloudGateway,ZuulSpringCloudGateway,Zu…

.net core8 自定义一个中间件

在.NET Core 8中自定义一个中间件&#xff0c;基本步骤与之前的.NET Core版本相似。中间件是ASP.NET Core请求处理管道的一个组件&#xff0c;它们可以在请求处理过程中被调用。下面是如何创建和使用一个自定义中间件的步骤&#xff1a; 第一步&#xff1a;创建中间件类 创建…

基于深度神经网络的图像识别技术研究

基于深度神经网络的图像识别技术是目前人工智能领域的研究热点之一&#xff0c;其强大的特征提取和模式识别能力使得图像识别任务取得了显著的进展。以下是对基于深度神经网络的图像识别技术的研究探讨。 首先&#xff0c;深度神经网络通过构建多层次的神经元连接&#xff0c;…

机器学习方法在测井解释上的应用-以岩性分类为例

机器学习在测井解释上的应用越来越广泛&#xff0c;主要用于提高油气勘探和开发的效率和精度。通过使用机器学习算法&#xff0c;可以从测井数据中自动识别地质特征&#xff0c;预测岩石物理性质&#xff0c;以及优化油气储层的评估和管理。 以下是机器学习在测井解释中的一些…

【DRAM存储器二十八】DDR4介绍-DDR4 SDRAM的主要技术特性之ODT,为什么要新增RTT_PARK?

👉个人主页:highman110 👉作者简介:一名硬件工程师,持续学习,不断记录,保持思考,输出干货内容 参考资料:《镁光DDR4数据手册》 、《JESD79-4B》 ODT DDR4的ODT相对DDR3又有更新。我们从DDR2到DDR4一起回顾一下。DDR2的终端电阻为RTT(NOM),由EMR的EMR的bit2和bi…