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

c++注意点(15)----状态模式

1. 核心定义

状态模式(State Pattern)

当一个对象的内部状态改变时,它的行为也随之改变,看起来就好像这个对象改变了它的类。

它的目标是 把状态的行为封装到独立的类/函数里,对象会在运行过程中切换引用的状态对象而改变自身行为。

2.为什么要用状态模式(State Pattern)

状态模式的核心目标是 管理对象在不同状态下的行为,并且 避免臃肿的条件分支。

背后的问题:

在很多程序(尤其是嵌入式设备、UI逻辑、协议处理)里,都有“状态”这个概念:

  • 一个设备可能处于 初始化 / 运行 / 故障 等状态
  • 每个状态下的操作(事件响应)不同
  • 如果我们直接用 switch-case 或 if-else 来判断状态,那么所有状态的逻辑会混在一起
    • 维护困难
    • 状态变多时 switch 会变得非常庞大
    • 扩展新状态需要改原有代码

状态模式就是为了解决这个可维护性和扩展性问题:

  • 把状态对应的行为封装成独立模块(类/结构/函数)
  • 当状态变化时,只需要修改当前引用的状态对象,不需要在大量的分支中找逻辑

3.状态模式的优点

  • 遵循开闭原则

不修改已有状态类,就能增加新状态(只是多一个实现类/函数)。

  • 清晰分离状态逻辑

每个状态的代码放在独立文件/类里,不会让 switch 把所有逻辑混在一起。

  • 运行时灵活切换状态

可以根据条件在运行中替换当前状态对象,立刻获得另一套行为。

  • 便于单元测试

每个状态可以单独测试,而不用在庞大的分支里模拟环境。

  • 可与多态结合(在 C++/Java 里)

用多态让调用方无需关心当前状态类型,直接调用统一接口。

4.状态模式和状态机的关系与区别

状态模式 ≠ 状态机,但它们关系很密切。
状态模式是一种“面向对象的设计方法”,状态机是一种“系统建模与逻辑执行方式”。

对比项状态模式状态机
定义把对象的状态和对应行为封装成独立类/对象使用图/表表示系统的状态及状态之间的迁移
目的避免复杂分支结构,使代码更易维护和扩展精确描述和控制状态变化逻辑
实现形式面向对象语言通常用多态;C 可用函数指针既可用多态,也可用 switch、表驱动等
关注点封装行为,减少依赖状态、事件、迁移过程控制
场景OOP 业务逻辑设计嵌入式设备控制、协议解析、工作流程

联系

  • 一个状态机可以用“状态模式”来实现
  • 状态模式是实现状态机的一种优雅方法
  • 像 QP 框架就是在状态模式的基础上做了扩展:不仅封装状态行为,而且支持层次化状态机(HSM)、时间事件、事件队列等。

5. 和 switch-case 的区别

虽然 switch 也能实现状态控制,但差别很大:

  • 优点:简单、上手快
  • 缺点:
    • 所有状态逻辑集中在一个函数中,代码会越来越庞大
    • 新增状态需要修改这个 switch 结构 → 破坏开闭原则
    • 状态切换和行为执行往往耦合在一起,维护不方便
    • 不适合多人协作,每个状态都得修改同一个文件

用状态模式实现

c版本

#include <stdio.h>/* 状态接口函数指针定义 */
typedef struct State {void (*handle)(struct State **ctx); // 事件处理函数
} State;/* 前向声明状态对象 */
void Init_handle(State **ctx);
void Run_handle(State **ctx);
void Error_handle(State **ctx);/* 状态对象定义 */
State InitState  = { Init_handle  };
State RunState   = { Run_handle   };
State ErrorState = { Error_handle };/* 状态机上下文(持有当前状态指针) */
typedef struct {State *current;
} Context;/* 状态切换方法 */
void changeState(Context *ctx, State *newState) {ctx->current = newState;
}/* 状态具体处理逻辑 */
void Init_handle(State **ctx) {printf("[INIT] 初始化完成,切到运行模式\n");*ctx = &RunState;
}void Run_handle(State **ctx) {printf("[RUN] 设备正在运行,出现故障!\n");*ctx = &ErrorState;
}void Error_handle(State **ctx) {printf("[ERROR] 错误处理完成,返回初始化\n");*ctx = &InitState;
}/* 测试入口 */
int main(void) {Context ctx = { &InitState };for (int i = 0; i < 6; i++) {ctx.current->handle(&ctx.current); // 按一次按钮}return 0;
}

c++版本

#include <iostream>
using namespace std;class Context; // 前向声明/* 抽象状态接口 */
class State {
public:virtual ~State() {}virtual void handle(Context* ctx) = 0;
};/* 上下文类,持有当前状态 */
class Context {
public:Context(State* s) : current(s) {}void setState(State* s) { current = s; }void request() { current->handle(this); }
private:State* current;
};/* 具体状态类 */
class InitState : public State {
public:void handle(Context* ctx) override;
};
class RunState : public State {
public:void handle(Context* ctx) override;
};
class ErrorState : public State {
public:void handle(Context* ctx) override;
};/* 状态方法实现 */
void InitState::handle(Context* ctx) {cout << "[INIT] 初始化完成,切到运行模式\n";static RunState run;ctx->setState(&run);
}
void RunState::handle(Context* ctx) {cout << "[RUN] 设备正在运行,出现故障!\n";static ErrorState err;ctx->setState(&err);
}
void ErrorState::handle(Context* ctx) {cout << "[ERROR] 错误处理完成,返回初始化\n";static InitState init;ctx->setState(&init);
}/* 测试入口 */
int main() {static InitState init; // 初始状态Context ctx(&init);for (int i = 0; i < 6; i++) {ctx.request();}return 0;
}
  • 优点:
    • 每个状态只关心自己的逻辑,代码分散管理
    • 扩展新状态只要加一个类/结构,不用改其他状态代码
    • 更容易阅读和维护
  • 缺点:
    • 相比单个函数,要定义更多对象(初期代码量稍大)
http://www.dtcms.com/a/515585.html

相关文章:

  • Delmia 软件 Teach 模块 interpolationMode 插补模式应用说明
  • Android Studio新手开发第二十八天
  • 系统与网络安全------弹性交换网络(4)
  • 功能网站首页模板微信小说分销平台
  • 网站建设管理规定php网站怎么建设
  • 【软考备考】物联网架构:感知层、网络层、平台层、应用层详解
  • LeetCode每日一题——二进制求和
  • 【LeetCode】长度最小的子数组
  • 从什么网站建网站好百度seo优化哪家好
  • 深度学习——基于 PyTorch 的蔬菜图像分类
  • 【设计模式】适配器模式(Adapter)
  • docker安装中间件
  • 系统架构设计师备考第48天——机器人边缘计算
  • 门头沟高端网站建设阿里云服务器win系统建站教程
  • ui设计培训机构哪个比较好cpu优化软件
  • 计算机运算中的上溢、下溢是什么?
  • 别再滥用 new/delete
  • 自己做网站的视频做网站不实名认证可以吗
  • Vertical Semiconductor融资1100万美元
  • 坐标系旋转(四元数 + 欧拉角 + 轴角表示 +旋转矩阵)
  • 发刊词:开启你的高效决策之旅(专栏目录)
  • D触发器学习
  • 汶上云速网站建设wordpress多域名支持
  • C++(23):contains检查字符串是否包含子字符串
  • 23.UE-游戏逆向-寻找骨骼坐标
  • Python 图片转 PDF 详解:单张、多张及多图片格式转换
  • 深圳展示型网站建设佛山seo优化代理
  • AI研究-110 DeepSeek-OCR 原理剖析|上下文光学压缩、Gundam 动态分辨率与并发预期 附代码
  • Easyx图形库应用(mcu+lua vs plc+st)
  • 【计算机网络笔记】第一章 计算机网络导论