重拾设计模式--状态模式

文章目录

  • 状态模式(State Pattern)概述
  • 状态模式UML图
  • 作用:
  • 状态模式的结构
    • 环境(Context)类:
    • 抽象状态(State)类:
    • 具体状态(Concrete State)类:
  • C++ 代码示例1
  • C++示例代码2
  • 应用场景
    • 游戏开发领域
    • 图形用户界面(GUI)系统
    • 工作流系统和业务流程管理
    • 网络协议和通信系统

状态模式(State Pattern)概述

定义:
状态模式是一种行为型设计模式,它允许对象在其内部状态改变时改变它的行为。就好像对象看起来修改了它的类一样,通过将不同状态对应的行为封装到不同的状态类中,让一个对象在不同的状态下可以表现出不同的行为,而这些行为的切换是由对象的状态变化来驱动的。

状态模式UML图

在这里插入图片描述

作用:

提高代码的可维护性和可扩展性:当一个对象有多种状态,且每种状态下行为差异较大时,如果使用大量的条件判断语句(如if-else或者switch语句)来处理不同状态下的行为,代码会变得复杂且难以维护。而状态模式把不同状态的行为分散到各个对应的状态类中,后续添加新状态或者修改某个状态下的行为就比较方便,只需对相应的状态类进行操作,不会影响到其他部分的代码。
符合开闭原则:对扩展开放,对修改关闭。例如在一个游戏角色有多种状态(站立、行走、攻击等)的场景中,若要新增一种 “跳跃” 状态以及对应的行为,只需要新增一个 “跳跃” 状态类实现相关行为逻辑,而不用去大规模修改原有的代码结构,原有的状态类和使用状态的对象代码都可以保持相对稳定。
增强代码的可读性:不同状态下的行为逻辑清晰地封装在各自的状态类中,阅读代码时可以更直观地了解每个状态对应的具体操作,相比于把所有状态相关行为混杂在一个类里的写法,结构更加清晰明了。

状态模式的结构

环境(Context)类:

它定义了客户端感兴趣的接口,并且维护一个具体状态类的实例,这个实例代表了当前对象所处的状态。环境类的行为会受到其内部状态对象的影响,它会将请求委托给当前状态对象来处理。

抽象状态(State)类:

它定义了一个接口,这个接口包含了那些在不同具体状态下对象可能执行的方法,所有的具体状态类都要实现这个抽象状态类所定义的接口,来提供各自状态下的具体行为逻辑。

具体状态(Concrete State)类:

实现了抽象状态类中定义的接口,针对具体的某一种状态,提供了该状态下相应行为的具体实现。每个具体状态类实现的行为会根据具体业务需求而不同,当环境类的状态切换到某个具体状态时,环境类发出的请求就会由对应的这个具体状态类来处理。

C++ 代码示例1

以下以一个简单的电梯控制系统为例来展示状态模式的代码实现。电梯有几种不同的状态,比如静止、上升、下降等,每种状态下对于外部的请求(如按楼层按钮等)会有不同的响应行为。

#include <iostream>// 抽象状态类
class ElevatorState
{
public:virtual void open() = 0;virtual void close() = 0;virtual void run() = 0;virtual void stop() = 0;
};// 具体状态类:静止状态
class StoppedState : public ElevatorState 
{
public:void open() override{std::cout << "电梯门打开,当前处于静止状态。" << std::endl;}void close() override {std::cout << "电梯门关闭,当前处于静止状态,准备运行。" << std::endl;}void run() override{std::cout << "电梯从静止状态开始运行。" << std::endl;}void stop() override {std::cout << "电梯已经处于静止状态,无需再次停止。" << std::endl;}
};// 具体状态类:上升状态
class RisingState : public ElevatorState 
{
public:void open() override{std::cout << "电梯正在上升,不能开门。" << std::endl;}void close() override {std::cout << "电梯正在上升,门已关闭。" << std::endl;}void run() override{std::cout << "电梯继续上升。" << std::endl;}void stop() override{std::cout << "电梯上升过程中停止。" << std::endl;// 假设停止后切换到静止状态,可以在这里做相应状态切换逻辑,比如通知环境类切换状态}
};// 具体状态类:下降状态
class FallingState : public ElevatorState 
{
public:void open() override {std::cout << "电梯正在下降,不能开门。" << std::endl;}void close() override{std::cout << "电梯正在下降,门已关闭。" << std::endl;}void run() override {std::cout << "电梯继续下降。" << std::endl;}void stop() override{std::cout << "电梯下降过程中停止。" << std::endl;// 同样,停止后可考虑切换状态逻辑}
};// 环境类:电梯
class Elevator
{
private:ElevatorState* currentState;
public:Elevator(){currentState = new StoppedState();}void setCurrentState(ElevatorState* state) {currentState = state;}void open(){currentState->open();}void close(){currentState->close();}void run() {currentState->run();}void stop() {currentState->stop();}
};int main()
{Elevator elevator;elevator.open();elevator.close();elevator.run();elevator.stop();RisingState risingState;elevator.setCurrentState(&risingState);elevator.open();elevator.close();elevator.run();elevator.stop();return 0;
}

C++示例代码2

#include<iostream>
#include<list>
#include<string>
using namespace std;
class Andy;//男主
class State//状态
{
public:string m_satedes;//描述当前的状态
public:virtual void Fbegin(){};//前期状态virtual void Fmid(){};//中期状态virtual void Fend(){};//末期状态virtual void CurrentState(Andy*p_andy){};//调用当前状态,统一的接口,然后各个状态子类去调用自己的函数
};
class Andy
{
private:State *m_state;  //目前状态int m_years;      //时间
public:Andy(State *state): m_state(state), m_years(0) {}~Andy() { delete m_state; }int GetYears() { return m_years; }void SetYears(int years) { m_years = years; }void SetState(State *state) { delete m_state; m_state = state; }void GetState() { m_state->CurrentState(this); }
};//服刑末期
class State_End:public State
{
public:State_End(){m_satedes = "挖洞逃出来了";}void FEnd(Andy *p_andy){cout<<"第"<<p_andy->GetYears()<<"年"<<m_satedes<<endl;}void CurrentState(Andy *p_andy){FEnd(p_andy);}
};//服刑中期
class State_Mid:public State
{
public:State_Mid(){m_satedes = "服刑中期,每天帮监狱长做假账,顺便开始夜里挖洞";}void FMid(Andy *p_andy){if(p_andy->GetYears()<28){cout<<"第"<<p_andy->GetYears()<<"年"<<m_satedes<<endl;}else{p_andy->SetState(new State_End());p_andy->GetState();}}void CurrentState(Andy *p_andy){FMid(p_andy);}
};//服刑前期
class State_begin:public State
{
public:State_begin(){m_satedes = "男主Andy刚进监狱,处处受人欺负";}void Fbegin(Andy *p_andy){if(p_andy->GetYears()<5){cout<<"第"<<p_andy->GetYears()<<"年"<<m_satedes<<endl;}else{p_andy->SetState(new State_Mid());p_andy->GetState();}}void CurrentState(Andy *p_andy){Fbegin(p_andy);}
};int main()
{Andy *p = new Andy(new (State_begin));for(int i = 1; i < 40; ++i){p->SetYears(i);p->GetState();}delete p;return 0;
}

应用场景

游戏开发领域

角色状态管理:游戏中的角色通常有多种状态,如站立、行走、奔跑、跳跃、攻击、受伤、死亡等。使用状态模式可以为每个状态创建一个单独的类,在这些类中实现角色在该状态下的行为,如移动速度、动画播放、可执行的操作等。例如,当角色处于攻击状态时,其移动速度可能会降低,并且会播放攻击动画,同时能够触发攻击相关的逻辑,如伤害计算。
游戏场景状态切换:游戏场景也可以有不同的状态,像游戏的主菜单场景、游戏进行中的场景、暂停场景、游戏结束场景等。每个场景状态都有自己的一套显示内容、交互逻辑和更新机制。通过状态模式,可以方便地在不同场景状态之间切换,并且清晰地管理每个状态下的资源加载、渲染和事件处理。

图形用户界面(GUI)系统

窗口状态管理:一个窗口可能有多种状态,如最小化、最大化、正常、隐藏等。在不同状态下,窗口的显示方式、对用户操作的响应等都不同。利用状态模式,可以将每个状态对应的行为封装到相应的状态类中。例如,当窗口处于最小化状态时,它可能只在任务栏显示一个图标,并且点击图标时的操作(如恢复窗口大小)与窗口处于正常状态时的操作(如拖动边框改变大小)是不同的。
按钮状态控制:按钮有正常、鼠标悬停、按下等状态。在不同状态下,按钮的外观(如颜色、样式)和行为(如触发的事件)不同。状态模式可以让开发者轻松地定义每个状态下按钮的渲染逻辑和事件响应逻辑,使得按钮的状态管理更加清晰和易于维护。

工作流系统和业务流程管理

订单处理流程:在电商系统中,订单有多种状态,如已创建、已付款、已发货、已签收、已退款等。每个状态下的订单处理逻辑不同,例如在 “已付款” 状态下,系统会通知仓库准备发货;在 “已发货” 状态下,系统会提供物流信息查询等服务。通过状态模式,可以把订单在不同状态下的处理逻辑封装在对应的状态类中,方便业务流程的扩展和维护。
审批流程:企业中的审批流程也存在多种状态,如提交审批、部门主管审批中、高层领导审批中、审批通过、审批拒绝等。对于每个状态,都有相应的操作和流转规则,比如在 “部门主管审批中” 状态下,部门主管可以查看申请内容并进行审批操作,审批通过后状态会切换到 “高层领导审批中”。使用状态模式可以清晰地实现这种复杂审批流程的状态管理和操作逻辑。

网络协议和通信系统

TCP 连接状态管理:在 TCP 协议中,连接有多种状态,如 LISTEN(监听)、SYN - SENT(同步已发送)、SYN - RECEIVED(同步收到)、ESTABLISHED(已建立)、FIN - WAIT - 1(终止等待 1)等。在不同状态下,网络设备(如服务器和客户端)的行为和数据处理方式不同。状态模式可以用于实现 TCP 连接状态的管理,将每个状态对应的数据包处理、连接维护等操作封装在相应的状态类中,使得网络通信的状态处理更加清晰和可靠。
设备通信状态:在物联网系统中,设备之间的通信可能会出现多种状态,如连接正常、连接中断、数据传输中、等待响应等。对于每种状态,可以使用状态模式来定义设备在该状态下的通信行为,如重新连接策略、数据缓存和发送方式等,以确保设备之间的通信稳定和高效。

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

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

相关文章

python使用pip进行库的下载

前言 现如今有太多的python编译软件&#xff0c;其库的下载也是五花八门&#xff0c;但在作者看来&#xff0c;无论是哪种方法都是万变不离其宗&#xff0c;即pip下载。 pip是python的包管理工具&#xff0c;无论你是用的什么python软件&#xff0c;都可以用pip进行库的下载。 …

【IMU:视觉惯性SLAM系统】

视觉惯性SLAM系统简介 相机&#xff08;单目/双目/RGBD)与IMU结合起来就是视觉惯性&#xff0c;通常以单目/双目IMU为主。 IMU里面有个小芯片可以测量角速度与加速度&#xff0c;可分为6轴(6个自由度)和9轴&#xff08;9个自由度&#xff09;IMU&#xff0c;具体的关于IMU的介…

Halcon例程代码解读:安全环检测(附源码|图像下载链接)

安全环检测核心思路与代码详解 项目目标 本项目的目标是检测图像中的安全环位置和方向。通过形状匹配技术&#xff0c;从一张模型图像中提取安全环的特征&#xff0c;并在后续图像中识别多个实例&#xff0c;完成检测和方向标定。 实现思路 安全环检测分为以下核心步骤&…

【蓝桥杯】43688-《Excel地址问题》

Excel地址问题 题目描述 Excel 单元格的地址表示很有趣&#xff0c;它可以使用字母来表示列号。比如&#xff0c; A 表示第 1 列&#xff0c; B 表示第 2 列&#xff0c; … Z 表示第 26 列&#xff0c; AA 表示第 27 列&#xff0c; AB 表示第 28 列&#xff0c; … BA 表示…

【C++读写.xlsx文件】OpenXLSX开源库在 Ubuntu 18.04 的编译、交叉编译与使用教程

&#x1f601;博客主页&#x1f601;&#xff1a;&#x1f680;https://blog.csdn.net/wkd_007&#x1f680; &#x1f911;博客内容&#x1f911;&#xff1a;&#x1f36d;嵌入式开发、Linux、C语言、C、数据结构、音视频&#x1f36d; ⏰发布时间⏰&#xff1a; 2024-12-17 …

大数据、人工智能、云计算、物联网、区块链序言【大数据导论】

这里是阿川的博客&#xff0c;祝您变得更强 ✨ 个人主页&#xff1a;在线OJ的阿川 &#x1f496;文章专栏&#xff1a;大数据入门到进阶 &#x1f30f;代码仓库&#xff1a; 写在开头 现在您看到的是我的结论或想法&#xff0c;但在这背后凝结了大量的思考、经验和讨论 这是目…

ffmpeg翻页转场动效的安装及使用

文章目录 前言一、背景二、选型分析2.1 ffmpeg自带的xfade滤镜2.2 ffmpeg使用GL Transition库2.3 xfade-easing项目三、安装3.1、安装依赖([参考](https://trac.ffmpeg.org/wiki/CompilationGuide/macOS#InstallingdependencieswithHomebrew))3.2、获取ffmpeg源码3.3、融合xf…

什么是3DEXPERIENCE SOLIDWORKS,它有哪些角色和功能?

将业界领先的 SOLIDWORKS 3D CAD 解决方案连接到基于单一云端产品开发环境 3DEXPERIENCE 平台。您的团队、数据和流程全部连接到一个平台进行高效的协作工作&#xff0c;从而能快速的做出更好的决策。 目 录&#xff1a; ★ 1 什么是3DEXPERIENCE SOLIDWORKS ★ 2 3DEXPERIE…

如何正确计算显示器带宽需求

1. 对显示器的基本认识 一个显示器的参数主要有这些&#xff1a; 分辨率&#xff1a;显示器屏幕上像素点的总数&#xff0c;通常用横向像素和纵向像素的数量来表示&#xff0c;比如19201080&#xff08;即1080p&#xff09;。 刷新率&#xff1a;显示器每秒钟画面更新的次数&…

leetcode212. 单词搜索 II

给定一个 m x n 二维字符网格 board 和一个单词&#xff08;字符串&#xff09;列表 words&#xff0c; 返回所有二维网格上的单词 。 单词必须按照字母顺序&#xff0c;通过 相邻的单元格 内的字母构成&#xff0c;其中“相邻”单元格是那些水平相邻或垂直相邻的单元格。同一…

CTFHUB 历年真题 afr-1

发现传参为 ?phello&#xff0c;尝试 ?pflag 发现都是 no 尝试假设它是个PHP文件&#xff0c;利用php伪协议 ?pphp://filter/readconvert.base64-encode/resourceflag 得到 base64 编码再解码发现了本题的 flag n1book{afr_1_solved}

重拾设计模式--备忘录模式

文章目录 备忘录模式&#xff08;Memento Pattern&#xff09;概述定义&#xff1a; 作用&#xff1a;实现状态的保存与恢复支持撤销 / 恢复操作 备忘录模式UML图备忘录模式的结构原发器&#xff08;Originator&#xff09;&#xff1a;备忘录&#xff08;Memento&#xff09;&…

5G -- 5G网络架构

5G组网场景 从4G到5G的网络演进&#xff1a; 1、UE -> 4G基站 -> 4G核心网 * 部署初中期&#xff0c;利用存量网络&#xff0c;引入5G基站&#xff0c;4G与5G基站并存 2、UE -> (4G基站、5G基站) -> 4G核心网 * 部署中后期&#xff0c;引入5G核心网&am…

前端开放性技术面试—面试题

1. 上线出现问题如何解决&#xff1f; 步骤&#xff1a; 立即响应&#xff1a;迅速确认问题的存在和影响范围。回滚&#xff1a;如果问题严重影响用户&#xff0c;考虑立即回滚到上一个稳定版本。日志分析&#xff1a;查看服务器日志、应用日志和前端日志&#xff0c;定位问题…

详细ECharts图例3添加鼠标单击事件的柱状图

<!DOCTYPE html><html><head><meta charset"UTF-8"><script src"js/echarts.js"></script> <!-- 确保路径正确 --><title>添加鼠标单击事件的柱状图</title></head><body><div id&q…

R 语言 | 绘图的文字格式(绘制上标、下标、斜体、文字标注等)

1. 上下标 # 注意y轴标签文字 library(ggplot2) ggplot(mtcars, aes(mpg, cyl))geom_point()ylab(label bquote(O[3]~(ug / m^3)))2. 希腊字母&#xff0c;如alpha ggplot(mtcars, aes(mpg, cyl))geom_point()ylab(label bquote(O[3]~(ug / m^3)))ggtitle(expression(alpha))…

精通Redis

目录 1.NoSQL 非关系型数据库 2.Redis 3.Redis的java客户端 4.Jedis 4.1Jedis快速入门 4.2Jedis连接池及使用 5.SpringDataRedis和RedisTemplate 6.SpringDataRedis快速入门 7.RedisSerializer 1.NoSQL 非关系型数据库 基础篇-02.初始Redis-认识NoSQL_哔哩哔哩_bilib…

VR线上展厅的色彩管理如何影响用户情绪?

VR线上展厅的色彩管理对用户情绪的影响是多方面的&#xff0c;以下是专业从事VR线上展厅制作的圆桌3D云展厅平台为大家介绍的一些关键点&#xff1a; 情感共鸣&#xff1a;色彩能够激发特定的情感反应。例如&#xff0c;暖色调&#xff08;如红色、橙色&#xff09;通常与活力和…

上传文件(vue3)

使用el-upload 先上传到文件服务器&#xff0c;生成url 然后点击确定按钮&#xff1a; 保存数据 <template><el-dialog top"48px" width"500" title"新增协议" :modelValue"visible" close"handleClose()">…

GM_T 0039《密码模块安全检测要求》题目

单项选择题 根据GM/T 0039《密码模块安全检测要求》,送检单位的密码模块应包括()密码主管角色。 A.一个 B.两个 C.至少一个 D.至少两个 正确答案:C 多项选择题 根据GM/T 0039《密码模块安全检测要求》,关于非入侵式安全,以下属于安全三级密码模块要求的是()。 …