当前位置: 首页 > news >正文

状态模式(State Pattern)

C++ 状态模式(State Pattern)

一、模式概述

状态模式(State Pattern)属于行为型设计模式

核心思想

将对象的不同状态分别封装为独立类,对象行为随内部状态改变而自动变化,对外表现如同修改了对象所属类;彻底替代传统大量if-else/switch分支判断,让状态逻辑解耦、职责清晰。

适用场景

  1. 对象行为依赖自身状态,运行时状态改变则行为随之改变;
  2. 业务中存在大量基于状态的条件判断代码,分支臃肿、难以维护;
  3. 状态数量固定、状态转换规则明确,需要扩展新状态;
  4. 典型业务:电梯状态、订单流程、网络连接、游戏角色、设备运行状态机等。

二、核心角色

状态模式由三类核心角色组成,各司其职:

角色名称职责说明
抽象状态State定义所有状态统一的行为接口,声明状态处理方法,通常为纯虚类
具体状态ConcreteStateX继承抽象状态,实现当前状态独有行为;负责触发状态跳转
上下文Context持有当前状态对象;对外提供统一调用入口;提供状态切换接口,串联整个状态流程

角色协作流程

  1. 客户端调用上下文的对外接口;
  2. 上下文将请求委托给当前具体状态对象处理;
  3. 具体状态执行自身逻辑,并根据业务规则修改上下文的状态;
  4. 下次请求会交由新状态处理,实现行为自动切换。

三、模式优缺点

优点

  1. 消除分支语句:剥离大量if-else/switch,代码结构更整洁;
  2. 符合开闭原则:新增状态只需新增具体状态类,无需修改原有代码;
  3. 状态逻辑隔离:每个状态的行为、转换逻辑内聚在对应类中,职责单一,易维护;
  4. 状态转换规范化:转换规则统一管理,流程清晰可控。

缺点

  1. 类数量膨胀:状态越多,对应的具体状态类就越多,增加代码体量;
  2. 流程分散:状态跳转逻辑分散在各个状态类中,整体状态流转流程阅读难度提升;
  3. 过度设计:简单状态(仅2~3个状态、逻辑简单)使用该模式会增加复杂度。

四、C++ 基础实现(标准写法)

1. 前置说明

  • 使用纯虚类作为抽象状态基类;
  • 采用原始指针演示基础逻辑,后文补充智能指针工程写法;
  • 类之间存在交叉引用,使用前向声明解决头文件循环依赖。

2. 完整代码示例

#include<iostream>usingnamespacestd;// 前向声明上下文类classContext;// ===================== 抽象状态类 State =====================classState{public:// 纯虚函数:状态处理行为,参数为上下文,用于状态切换virtualvoidhandle(Context*context)=0;virtual~State()=default;// 虚析构,保证多态析构安全};// ===================== 具体状态类 A =====================classConcreteStateA:publicState{public:voidhandle(Context*context)override;};// ===================== 具体状态类 B =====================classConcreteStateB:publicState{public:voidhandle(Context*context)override;};// ===================== 上下文类 Context =====================classContext{private:State*m_currentState;// 持有当前状态对象public:// 构造函数:初始化默认状态Context(State*state):m_currentState(state){}// 设置/切换状态voidsetState(State*state){m_currentState=state;}// 对外统一请求接口voidrequest(){if(m_currentState){m_currentState->handle(this);// 委托给当前状态处理}}};// 状态A 实现逻辑:执行行为,并切换到状态BvoidConcreteStateA::handle(Context*context){cout<<"当前处于【状态A】,执行状态A逻辑"<<endl;// 状态跳转:切换为状态Bcontext->setState(newConcreteStateB());}// 状态B 实现逻辑:执行行为,并切换到状态AvoidConcreteStateB::handle(Context*context){cout<<"当前处于【状态B】,执行状态B逻辑"<<endl;// 状态跳转:切换为状态Acontext->setState(newConcreteStateA());}// ===================== 客户端测试 =====================intmain(){// 初始化上下文,默认状态为AContextctx(newConcreteStateA());// 多次调用,观察状态自动切换ctx.request();ctx.request();ctx.request();return0;}

3. 运行结果

当前处于【状态A】,执行状态A逻辑 当前处于【状态B】,执行状态B逻辑 当前处于【状态A】,执行状态A逻辑

五、C++ 工程级优化(智能指针版)

原始指针容易造成内存泄漏、野指针,正式项目推荐使用std::unique_ptr管理状态对象。

优化后代码

#include<iostream>#include<memory>usingnamespacestd;classContext;// 抽象状态classState{public:virtualvoidhandle(Context*context)=0;virtual~State()=default;};// 具体状态AclassConcreteStateA:publicState{public:voidhandle(Context*context)override;};// 具体状态BclassConcreteStateB:publicState{public:voidhandle(Context*context)override;};// 上下文(使用 unique_ptr 管理状态)classContext{private:unique_ptr<State>m_currentState;public:explicitContext(unique_ptr<State>state):m_currentState(move(state)){}voidsetState(unique_ptr<State>state){m_currentState=move(state);}voidrequest(){if(m_currentState)m_currentState->handle(this);}};voidConcreteStateA::handle(Context*context){cout<<"当前处于【状态A】,执行逻辑"<<endl;context->setState(make_unique<ConcreteStateB>());}voidConcreteStateB::handle(Context*context){cout<<"当前处于【状态B】,执行逻辑"<<endl;context->setState(make_unique<ConcreteStateA>());}// 客户端intmain(){Contextctx(make_unique<ConcreteStateA>());ctx.request();ctx.request();ctx.request();return0;}

优势:智能指针自动释放内存,无需手动delete,规避内存泄漏。

六、两种状态切换方式

在实际开发中,状态切换分为两种模式:

1. 状态类内部控制跳转(常用)

  • 跳转逻辑写在ConcreteState::handle中;
  • 优点:状态自管理,内聚性强;
  • 缺点:跳转逻辑分散。

2. 上下文统一控制跳转

  • 所有状态转换规则集中写在Context中;
  • 优点:整体状态流转一目了然,便于梳理完整流程;
  • 缺点:上下文会随状态增多变得臃肿。

七、状态模式 vs 策略模式(易混区分)

两者结构相似,均封装行为、委托执行,核心区别在行为目的与切换逻辑

对比维度状态模式策略模式
核心目的处理对象状态变化,行为随状态自动改变封装多种算法/策略,按需替换算法
切换触发内部状态流转,自动切换外部客户端主动选择,手动切换
关系状态之间存在流转、依赖关系各个策略相互独立,无先后流转关系
典型场景状态机、订单、电梯、设备状态排序算法、支付方式、加密算法

八、使用注意事项

  1. 控制状态数量:状态过多会产生大量子类,若状态超过10个,可考虑改用配置表+枚举实现状态机;
  2. 循环依赖处理ContextState互相引用,必须使用前向声明
  3. 析构安全:抽象状态基类必须提供虚析构函数,防止多态析构内存泄漏;
  4. 慎用场景:简单两状态、固定逻辑,不建议强行使用,避免过度设计;
  5. 多线程场景:多线程下需对m_currentState加锁,保证状态切换线程安全。

九、总结

  1. 本质:把状态变成类,用多态替代分支判断
  2. 核心三角色:抽象状态、具体状态、上下文;
  3. C++ 开发优先使用智能指针管理状态对象,保证内存安全;
  4. 适合复杂状态机场景,简单场景按需取舍。
http://www.gsyq.cn/news/1398384.html

相关文章:

  • 别再只会转格式了!FFmpeg的-i、-f、-ss参数组合,5分钟搞定视频精准裁剪与格式转换
  • HALCON 22.11深度模型加密实操:保护你的AI训练成果与商业机密
  • [論文學習]透過 Recollection 與 Ranking 揭露 LLM 訓練資料隱私漏洞
  • OpenClaw 离线包安装,无网络环境部署方法
  • 韬定律:多层电子系统的时间缩放理论,以及3D芯体设想
  • DeepSeek V4 Pro 永久降价:AI 模型价格战背后的技术逻辑与开发者的新机遇
  • Excel列宽自适应背后的秘密:为什么你的表格打印出来总对不齐?
  • 用Python和NumPy手把手实现一个简单的马尔可夫链预测模型(附完整代码)
  • xinference
  • RT-Thread Studio + STM32CubeMX 联合开发避坑实录:搞定W25Q32 SPI Flash的SFUD与FAL配置
  • DDS通信支持UDP与TCP
  • AI Agent实战教程:用LangGraph构建Multi-Agent协作系统
  • Lovable运维平台从0到1搭建全流程:7步实现自动化、可观测性与DevOps无缝集成
  • 保姆级教程:用STM32CubeMX和HAL库配置CAN扩展帧过滤器(掩码模式)
  • LLM安全攻防:对抗攻击原理与防御实践
  • 2026年Q2智慧酒店OLT光网系统专业厂家排行:智慧酒店RCU客房控制系统、智慧酒店升级改造方案及报价、智慧酒店客房系统选择指南 - 优质品牌商家
  • 从用户分群到商品推荐:K-Means和KNN在电商数据分析里的真实应用案例
  • 高光谱数据降维实战:鲁棒局部流形表示(RLMR)算法解析与应用
  • 文档级神经机器翻译:基于全局与局部嵌入的工程实践
  • 【AI面试临阵磨枪-73】金融 AI 安全:风控、反欺诈、合规、幻觉、隐私保护
  • pandas数据清洗实战:从脏数据到分析就绪的工程化流程
  • Burp Suite Sequencer深度解析:会话Token不可预测性验证实战
  • Apache Superset认证绕过漏洞CVE-2023-27524深度解析
  • 安卓so动态调试实战:5步精准定位关键函数
  • PyTorch多GPU训练避坑指南:CUDA_VISIBLE_DEVICES和DataParallel的正确打开方式
  • YOLO26实现布料缺陷自动化检测(项目源码+数据集+模型权重+UI界面+python+深度学习+远程环境部署)
  • 吴恩达深度学习笔记:手把手教你用Python实现一个4层神经网络(附完整代码)
  • CentOS 7网络配置踩坑实录:从‘网络不可达’到完美联通的避坑指南
  • 为什么92%的企业AI项目将在2028年前失效?从Transformer到Neuromorphic AI的工具代际断层全解析
  • 别再死磕CNN了!用GCN搞定社交网络好友推荐,Python代码实战(附避坑指南)