【设计模式-4.6】行为型——状态模式

article/2025/6/22 19:29:38

说明:本文介绍行为型设计模式之一的状态模式

定义

状态模式(State Pattern)也叫作状态机模式(State Machine Pattern),允许对象在内部状态发生改变时改变它的行为,对象看起来好像修改了它的类,属于行为型设计模式。(引自《设计模式就该这样学》P348)

“对象看起来好像修改了它的类”,指对象的状态发生改变后,与之对应的行为也会发生改变(当然,这取决于你的业务逻辑)。


状态模式中类的行为是由状态决定的,在不同的状态下有不同的行为。其意图是让一个对象在其内部改变的时候,行为也随之改变。状态模式的核心是状态与行为绑定,不同的状态对应不同的行为。(引自《设计模式就该这样学》P348)

这段讲的很好。

灯的状态

灯的状态简单来分,只有两种,开的和熄灭的,所以更换灯的状态,代码写出来,很简单,如下:

/*** 灯开关*/
public class Switcher {/*** 灯状态* false:熄灯* true:开灯*/private boolean state = false;/*** 使开灯*/public void switchOn() {state = true;System.out.println("开灯");}/*** 使熄灯*/public void switchOff() {state = false;System.out.println("熄灯");}
}

作为程序员的严谨,需要考虑到灯在开启的时候,再调用开启方法的情况和灯在熄灭的时候,再调用熄灭方法的情况,如下:

/*** 灯开关-Plus*/
public class SwitcherPlus {/*** 灯状态* false:熄灯* true:开灯*/private boolean state = false;public void switchOn() {// 如果是熄灯if (!state) {state = true;System.out.println("开灯");} else {System.out.println("灯已经是开灯状态,无需重复开灯");}}public void switchOff() {// 如果是开灯if (state) {state = false;System.out.println("熄灯");} else {System.out.println("灯已经是熄灭状态,无需重复熄灯");}}
}

代码变得复杂起来了,以上仅是一个对象,两种状态的情况,用if-else还能应付。如果是多个状态,例如交通信号灯,有红黄绿三个状态,绿灯变红灯,红灯变黄灯,黄灯变绿灯,代码如下:

/*** 交通信号灯*/
public class TrafficLight {/*** 信号灯状态,默认红* 红灯转绿灯,绿灯转黄灯,黄灯转红灯*/private String state = "红";/*** 切换到绿灯*/public void switchToGreen() {if ("绿".equals(state)) {System.out.println("已是绿灯,无需切换。。。");} else if ("红".equals(state)) {System.out.println("成功切换到绿灯~~~");} else if ("黄".equals(state)) {System.out.println("黄灯不能切换到绿灯!!!");}}/*** 切换到黄灯*/public void switchToYellow() {if ("绿".equals(state)) {System.out.println("成功切换到黄灯~~~");} else if ("红".equals(state)) {System.out.println("红灯不能切换到黄灯!!!");} else if ("黄".equals(state)) {System.out.println("已是黄灯,无需切换。。。");}}/*** 切换到红灯*/public void switchToRed() {if ("绿".equals(state)) {System.out.println("绿灯不能切换到红灯!!!");} else if ("红".equals(state)) {System.out.println("已是红灯,无需切换。。。");} else if ("黄".equals(state)) {System.out.println("成功切换到红灯~~~");}}
}

多层的if-else,代码显得臃肿,难以维护,后续涉及修改也会频繁改动这个类。

状态模式

使用状态模式,将方法、状态抽出来,如下:

(状态接口,State)

/*** 状态*/
public interface State {/*** 切换到绿灯*/void switchToGreen(TrafficLight trafficLight);/*** 切换到黄灯*/void switchToYellow(TrafficLight trafficLight);/*** 切换到红灯*/void switchToRed(TrafficLight trafficLight);
}

(红灯实现类,Red,注意切换成功后修改状态)

/*** 红灯*/
public class Red implements State {@Overridepublic void switchToGreen(TrafficLight trafficLight) {trafficLight.setState(new Green());System.out.println("成功切换到绿灯~~~");}@Overridepublic void switchToYellow(TrafficLight trafficLight) {System.out.println("红灯不能切换到黄灯!!!");}@Overridepublic void switchToRed(TrafficLight trafficLight) {System.out.println("已是红灯,无需切换。。。");}
}

(绿灯实现类,Green,注意切换成功后修改状态)

/*** 绿灯*/
public class Green implements State {@Overridepublic void switchToGreen(TrafficLight trafficLight) {System.out.println("已是绿灯,无需切换。。。");}@Overridepublic void switchToYellow(TrafficLight trafficLight) {trafficLight.setState(new Yellow());System.out.println("成功切换到黄灯~~~");}@Overridepublic void switchToRed(TrafficLight trafficLight) {System.out.println("绿灯不能切换到红灯!!!");}
}

(黄灯实现类,Yellow,注意切换成功后修改状态)

/*** 黄灯*/
public class Yellow implements State {@Overridepublic void switchToGreen(TrafficLight trafficLight) {System.out.println("黄灯不能切换到绿灯!!!");}@Overridepublic void switchToYellow(TrafficLight trafficLight) {System.out.println("已是黄灯,无需切换。。。");}@Overridepublic void switchToRed(TrafficLight trafficLight) {trafficLight.setState(new Red());System.out.println("成功切换到红灯~~~");}
}

(信号灯类,TrafficLight,只需调用抽象方法即可)

/*** 交通信号灯*/
public class TrafficLight {/*** 默认状态:红灯*/State state = new Red();/*** 设置灯状态*/public void setState(State state) {this.state = state;}/*** 切换到绿灯*/public void switchToGreen() {state.switchToGreen(this);}/*** 切换到黄灯*/public void switchToYellow() {state.switchToYellow(this);}/*** 切换到红灯*/public void switchToRed() {state.switchToRed(this);}
}

(客户端,Client)

public class Client {public static void main(String[] args) {TrafficLight trafficLight = new TrafficLight();trafficLight.switchToGreen();trafficLight.switchToYellow();trafficLight.switchToRed();}
}

执行如下

在这里插入图片描述

看下来,使用状态模式,减少了单个类使用大量if-else分支处理复杂逻辑的代码,使代码便于维护,后续还有其他状态,如粉灯、蓝灯,只需要增加对应的类,对应的抽象方法即可,不需要更改原来的代码。

综合来看,状态模式,将原本的代码(code)层面上的结构化,转为了类(class)层面上的结构化,这也是其他设计模式的大体思想。

使用场景

在《设计模式就该这样学》(P349)这本书中,提到状态模式适用于以下场景:

(1)行为随状态改变而改变的场景;

(2)一个操作中含有庞大的多分支结构,并且这些分支取决于对象的状态;

总结

本文介绍了行为型设计模式中的状态模式,参考《设计模式就该这样学》、《秒懂设计模式》两书,交通信号灯场景是《秒懂设计模式》中的举例。


http://www.hkcw.cn/article/wZPAgYxYgD.shtml

相关文章

proteus新建工程

1 点击新建工程 2 输入项目名,选择工程文件夹 3 下一步 4 不创建pcb 5 直接下一步 6 点击完成 7 创建完毕

【计算机CPU架构】ARM架构简介

引言:后x86时代的计算革命 2023年全球ARM芯片出货量突破300亿片,这个数字背后是智能手机、物联网设备、数据中心到超级计算机的全面渗透。当Apple M系列芯片以颠覆性效能震撼PC市场,当AWS Graviton3以40%性价比优势冲击云服务,一场…

Python实现P-PSO优化算法优化循环神经网络LSTM分类模型项目实战

说明:这是一个机器学习实战项目(附带数据代码文档),如需数据代码文档可以直接到文章最后关注获取。 1.项目背景 随着深度学习技术的迅猛发展,循环神经网络(RNN)及其变体LSTM(Long S…

牛客周赛94

随手写一下题解吧,最后一题确实有点烧脑了,一开始没想到,看完题解确实茅塞顿开了 经典校招题 思路:n级台阶,每次只能走1或2格,问你最少得步数,那肯定就是每次都走两个,如果是奇数就…

华为OD机试真题——硬件产品销售方案(2025A卷:100分)Java/python/JavaScript/C++/C语言/GO六种最佳实现

2025 A卷 100分 题型 本文涵盖详细的问题分析、解题思路、代码实现、代码详解、测试用例以及综合分析; 并提供Java、python、JavaScript、C++、C语言、GO六种语言的最佳实现方式! 2025华为OD真题目录+全流程解析/备考攻略/经验分享 华为OD机试真题《硬件产品销售方案》: 目录…

流媒体基础解析:视频清晰度的关键因素

在视频处理的过程中,编码解码及码率是影响视频清晰度的关键因素。今天,我们将深入探讨这些概念,并解析它们如何共同作用于视频质量。 编码解码概述 编码,简单来说,就是压缩。视频编码的目的是将原始视频数据压缩成较…

TDengine 集群运行监控

简介 为了确保集群稳定运行,TDengine 集成了多种监控指标收集机制,并通过 taosKeeper 进行汇总。taosKeeper 负责接收这些数据,并将其写入一个独立的 TDengine 实例中,该实例可以与被监控的 TDengine 集群保持独立。TDengine 中的…

SoftThinking:让模型学会模糊思考,同时提升准确性和推理速度!!

摘要:人类的认知通常涉及通过抽象、灵活的概念进行思考,而不是严格依赖离散的语言符号。然而,当前的推理模型受到人类语言边界的限制,只能处理代表语义空间中固定点的离散符号嵌入。这种离散性限制了推理模型的表达能力和上限潜力…

【LUT技术专题】图像自适应3DLUT

3DLUT开山之作: Learning Image-adaptive 3D Lookup Tables for High Performance Photo Enhancement in Real-time(2020 TPAMI ) 专题介绍一、研究背景二、图像自适应3DLUT方法2.1 前置知识2.2 整体流程2.3 损失函数的设计 三、实验结果四、局限五、总结…

【计算机网络】 ARP协议和DNS协议

文章目录 【计算机网络】ARP协议和DNS协议(知识点详细)一、ARP协议(地址解析协议)1. **协议功能**2. **ARP报文结构**3. **工作流程**(1)**正向ARP(已知IP,求MAC)**&…

普中STM32F103ZET6开发攻略(一)

各位看官老爷们,点击关注不迷路哟。你的点赞、收藏,一键三连,是我持续更新的动力哟!!! 目录 普中STM32F103ZET6开发攻略 1. GPIO端口实验——点亮LED灯 1.1 实验目的 1.2 实验原理 1.3 实验环境和器材…

Azure DevOps 管道部署系列之二IIS

本博客旨在提供如何使用 Azure DevOps YAML 管道部署到虚拟机上的 IIS 的实用指南。 开始之前,您需要做好以下准备: 您拥有要部署的服务器的访问权限以及 PowerShell 的管理员访问权限。您拥有要部署的远程服务器的互联网访问权限。您拥有在服务器上安装 .NET Core 托管包的…

Linux命令之ausearch命令

一、命令简介 ausearch 是 Linux 审计系统 (auditd) 中的一个实用工具,用于搜索审计日志中的事件。它是审计框架的重要组成部分,可以帮助系统管理员分析系统活动和安全事件。 二、使用示例 1、安装ausearch命令 Ubuntu系统安装ausearch命令,安装后启动服务。 root@testser…

2025山东CCPC题解

文章目录 L - StellaD - Distributed SystemI - Square PuzzleE - Greatest Common DivisorG - Assembly Line L - Stella 题目来源:L - Stella 解题思路 签到题,因为给出的字母不是按顺序,可以存起来赋其值,然后在比较。 代码…

复数三角不等式简介及 MATLAB 演示

复数三角不等式简介及 MATLAB 演示 1. 复数三角不等式简介 复数三角不等式(Complex Triangle Inequality)是复数的一种重要性质,它类似于普通的三角不等式,但适用于复数空间。具体来说,复数三角不等式可以描述复数之…

学术合作交流

想找志同道合的科研小伙伴!研究方向包括:计算机视觉(CV)、人工智能(AI)、目标检测、行人重识别、行人搜索、虹膜识别等。欢迎具备扎实基础的本科、硕士及博士生加入,共同致力于高质量 SCI 期刊和…

2025-05-31 Python深度学习10——模型训练流程

文章目录 1 数据准备1.1 下载与预处理1.2 数据加载 2 模型构建2.1 自定义 CNN 模型2.2 GPU加速 3 训练配置3.1 损失函数3.2 优化器3.3 训练参数 4 训练循环4.1 训练模式 (model.train())4.2 评估模式 (model.eval()) 5 模型验证 本文环境: Pycharm 2025.1Python 3.1…

十五、STM32的TIM(六)(PWM驱动舵机)

介绍:本章节主要讲解如何在 STM32C8T6 上使用 PWM 驱动舵机。通过按键输入控制,输出以 PWM 信号调整舵机转动角度,从而实现对舵机的精准控制。 目录 一、接线图 二、相关参数的计算 三、相关代码的编写 四、程序现象 一、接线图 二、相关…

C语言指针完全指南:从入门到精通(上)

目录 一、内存和指针 1.1 指针的使用场景 二、指针变量和地址 2.1 取地址符(&) 2.2指针变量和解引用操作符(*) 2.2.1 指针变量 2.3 指针变量的大小 三、指针变量类型的意义 3.2 指针-整数 ​编辑 四、指针计算 五、const修饰指针 5.1 const修饰变量 1.2 const修饰…

Kafka数据怎么保障不丢失

在分布式消息系统中,数据不丢失是核心可靠性需求之一。Apache Kafka 通过生产者配置、副本机制、持久化策略、消费者偏移量管理等多层机制保障数据可靠性。以下从不同维度解析 Kafka 数据不丢失的核心策略,并附示意图辅助理解。 一、生产者端&#xff1a…