C++实现设计模式---状态模式 (State)

状态模式 (State)

状态模式 是一种行为型设计模式,它允许对象在运行时根据内部状态的改变来动态改变其行为。通过将状态相关的行为封装到独立的类中,状态模式使得状态的切换更加清晰和灵活。


意图

  • 将对象的行为和状态分离,随着状态的改变动态调整对象的行为。
  • 避免使用大量的 if-elseswitch-case 语句处理状态逻辑。

使用场景

  1. 对象的行为依赖于状态
    • 例如订单的状态(未支付、已支付、已发货)。
  2. 需要动态切换状态
    • 例如游戏角色的动作(站立、行走、奔跑)。
  3. 需要扩展状态逻辑
    • 新增状态时不影响现有逻辑。

参与者角色

  1. 上下文类 (Context)
    • 保存当前状态的引用,提供接口供外部访问,并委托状态对象执行行为。
  2. 状态接口 (State)
    • 定义状态的公共接口。
  3. 具体状态类 (ConcreteState)
    • 实现状态接口并定义该状态下的具体行为。

代码示例

以下代码展示了一个机器人(Robot)的状态模式实现。机器人可以处于“待机状态 (Idle)”、“工作状态 (Working)”和“充电状态 (Charging)”之间切换。

#include <iostream>
#include <memory>
#include <string>// ------------------------------
// 状态接口:定义机器人状态的公共接口
class RobotContext; // 前置声明上下文类class RobotState {
public:virtual ~RobotState() = default; // 虚析构函数,确保多态销毁// 状态行为接口virtual void startWork(RobotContext& context) = 0;     // 开始工作virtual void chargeBattery(RobotContext& context) = 0; // 开始充电virtual std::string getStateName() const = 0;          // 获取状态名称
};// ------------------------------
// 上下文类:机器人
class RobotContext {
private:std::unique_ptr<RobotState> state; // 当前机器人状态,使用 unique_ptr 管理状态对象public:explicit RobotContext(std::unique_ptr<RobotState> initialState) : state(std::move(initialState)) {}// 设置新的状态void setState(std::unique_ptr<RobotState> newState) {state = std::move(newState);}// 委托开始工作行为给当前状态void startWork() {state->startWork(*this);}// 委托充电行为给当前状态void chargeBattery() {state->chargeBattery(*this);}// 获取当前状态名称std::string getStateName() const {return state->getStateName();}
};// ------------------------------
// 具体状态类:工作状态
class WorkingState : public RobotState {
public:void startWork(RobotContext& context) override {std::cout << "机器人已经在工作中,无法重复开始工作。
";}void chargeBattery(RobotContext& context) override {std::cout << "机器人停止工作,切换到充电状态。
";context.setState(std::make_unique<class ChargingState>()); // 切换到“充电状态”}std::string getStateName() const override {return "工作状态";}
};// ------------------------------
// 具体状态类:充电状态
class ChargingState : public RobotState {
public:void startWork(RobotContext& context) override {std::cout << "机器人充电完成,切换到工作状态。
";context.setState(std::make_unique<class WorkingState>()); // 切换到“工作状态”}void chargeBattery(RobotContext& context) override {std::cout << "机器人已经在充电中,无法重复充电。
";}std::string getStateName() const override {return "充电状态";}
};// ------------------------------
// 具体状态类:待机状态
class IdleState : public RobotState {
public:void startWork(RobotContext& context) override {std::cout << "机器人开始工作,切换到工作状态。
";context.setState(std::make_unique<class WorkingState>()); // 切换到“工作状态”}void chargeBattery(RobotContext& context) override {std::cout << "机器人开始充电,切换到充电状态。
";context.setState(std::make_unique<class ChargingState>()); // 切换到“充电状态”}std::string getStateName() const override {return "待机状态";}
};// ------------------------------
// 客户端代码
int main() {// 初始化机器人为“待机状态”RobotContext robot(std::make_unique<IdleState>());// 获取当前状态并输出std::cout << "当前机器人状态: " << robot.getStateName() << "
";// 机器人开始工作robot.startWork();std::cout << "当前机器人状态: " << robot.getStateName() << "
";// 机器人充电robot.chargeBattery();std::cout << "当前机器人状态: " << robot.getStateName() << "
";// 再次开始工作robot.startWork();std::cout << "当前机器人状态: " << robot.getStateName() << "
";return 0;
}

代码解析

1. 状态接口 (RobotState)
  • 定义公共接口
    • 包括 startWorkchargeBatterygetStateName 三个接口。
    • 每个具体状态类都必须实现这些接口,定义具体的行为。
2. 上下文类 (RobotContext)
  • 负责管理当前状态
    • RobotContext 保存当前状态的智能指针(std::unique_ptr),并负责管理状态对象的生命周期。
  • 行为委托
    • 调用 startWorkchargeBattery 时,行为委托给当前状态对象。
  • 状态切换
    • 通过 setState 方法切换状态,使用 std::make_unique 创建新的状态对象。
3. 具体状态类
  • IdleState (待机状态)
    • 允许切换到“工作状态”或“充电状态”。
  • WorkingState (工作状态)
    • 如果重复调用 startWork,提示“已在工作中”。
    • 支持切换到“充电状态”。
  • ChargingState (充电状态)
    • 如果重复调用 chargeBattery,提示“已在充电中”。
    • 支持切换到“工作状态”。
4. 状态切换逻辑
  • 每个状态类都可以通过 context.setState(std::make_unique<NewState>()); 切换到其他状态。
  • 切换状态时使用 std::unique_ptr 管理状态对象,确保内存安全。

运行结果

运行程序后,输出如下:

当前机器人状态: 待机状态
机器人开始工作,切换到工作状态。
当前机器人状态: 工作状态
机器人停止工作,切换到充电状态。
当前机器人状态: 充电状态
机器人充电完成,切换到工作状态。
当前机器人状态: 工作状态

优缺点

优点
  1. 封装状态逻辑
    • 每个状态的行为封装在独立的类中,方便维护和扩展。
  2. 动态切换状态
    • 通过 setState 动态切换状态,逻辑清晰。
  3. 消除条件语句
    • 使用多态机制避免了大量的 if-elseswitch-case 语句。
缺点
  1. 类数量增加
    • 每种状态都需要单独定义一个类,可能导致类数量较多。
  2. 上下文和状态耦合
    • 状态类依赖上下文类的操作。

适用场景

  1. 对象的行为依赖于状态
    • 如订单状态、文件操作等。
  2. 需要动态切换状态
    • 系统需要根据当前状态动态改变行为。

总结

状态模式通过将状态的行为封装到独立的类中,实现了对象的动态行为调整,是有限状态机的优雅实现方式。它特别适用于需要频繁切换状态且每种状态具有独立逻辑的场景。

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

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

相关文章

继续以“实用”指导Pythonic编码(re通配表达式)(2024年终总结②)

弃现成工具手剥任务&#x1f9d0;&#xff0c;我哈哈滴就像笨笨的傻大个儿&#x1f60b;。 (笔记模板由python脚本于2025年01月12日 23:29:33创建&#xff0c;本篇笔记适合熟悉正则表达式的coder翻阅) 【学习的细节是欢悦的历程】 Python官网&#xff1a;https://www.python.or…

相机和激光雷达的外参标定 - 无标定板版本

1. 实现的效果 通过本软件实现求解相机和LiDAR的外参&#xff0c;即2个传感器之间的三维平移[x, y, z]和三维旋转[roll, pitch, yaw]。完成标定后&#xff0c;可将点云投影到图像&#xff0c;效果图如下&#xff1a; 本软件的优势&#xff1a;&#xff08;1&#xff09;无需特…

WPF系列九:图形控件EllipseGeometry

简介 EllipseGeometry用于绘制一个椭圆的形状。它通常与其他图形元素结合使用&#xff0c;比如 Path 或者作为剪切区域来定义其他元素的外形。 定义椭圆&#xff1a;EllipseGeometry 用来定义一个椭圆或者圆的几何形状。参与绘制&#xff1a;可以被用作 Path 元素的数据&…

qt设置qwidget背景色无效

最近在做一个界面&#xff0c;有三个子窗体&#xff0c;于是就把各个子窗体分别做成了三个UI&#xff0c;再将3个UI&#xff0c;放到1个UI&#xff0c;再将那一个UI在其他窗体上进行提升。 最后就发现怎么设置qwidget的背景都没有效果。 在Qt中&#xff0c;如果是给Qwidget的…

【Rust学习笔记】Rust 的所有权介绍

博主未授权任何人或组织机构转载博主任何原创文章&#xff0c;感谢各位对原创的支持&#xff01; 博主链接 博客内容主要围绕&#xff1a; 5G/6G协议讲解 高级C语言讲解 Rust语言讲解 文章目录 Rust中的所有权介绍1.1 一个简单的例子1.2 一个稍微复杂的例…

CentOS7下Hadoop集群分布式安装详细图文教程

1、集群规划 主机 角色 DSS20 NameNode DataNode ResourceManager NodeManager DSS21 SecondaryNameNode NameNode NodeManager DSS22 DataNode NodeManager 1.1、环境准备 1.1.1 关闭防火墙 #查看防火墙状态 firewall-cmd --state #停止…

在 Vue 项目中使用地区级联选

在 Vue 项目中使用地区级联选择的完整流程&#xff1a; 1.安装依赖包&#xff0c;这个包提供了中国省市区的完整数据。 npm install element-china-area-data --save 2.导入数据 import { regionData } from element-china-area-data 这个包提供了几种不同的数据格式&#…

基于改进粒子群优化的无人机最优能耗路径规划

目录 1. Introduction2. Preliminaries2.1. Particle Swarm Optimization Algorithm2.2. Deep Deterministic Policy Gradient2.3. Calculation of the Total Output Power of the Quadcopter Battery 3.OptimalEnergyConsumptionPathPlanningBasedonPSO-DDPG3.1.ProblemModell…

Redis为 List/Set/Hash 的元素设置单独的过期时间

一.业务简介 我们知道&#xff0c;Redis 里面暂时没有接口给 List、Set 或者 Hash 的 field 单独设置过期时间&#xff0c;只能给整个列表、集合或者 Hash 设置过期时间。 这样&#xff0c;当 List/Set/Hash 过期时&#xff0c;里面的所有 field 元素就全部过期了。但这样并不…

【51单片机】03 蜂鸣器-播放音乐

蜂鸣器-播放音乐 一、原理介绍1.硬件电路 二、练习1.让蜂鸣器发声2.尝试演奏小星星 一、原理介绍 蜂鸣器分为有源蜂鸣器、无源蜂鸣器两种。 有源蜂鸣器&#xff1a;施加合适的电压之后就会发出特定频率的声音 无源蜂鸣器&#xff1a;需要提供特定频率的声音信号&#xff0c;才能…

30_Redis哨兵模式

在Redis主从复制模式中,因为系统不具备自动恢复的功能,所以当主服务器(master)宕机后,需要手动把一台从服务器(slave)切换为主服务器。在这个过程中,不仅需要人为干预,而且还会造成一段时间内服务器处于不可用状态,同时数据安全性也得不到保障,因此主从模式的可用性…

汽车基础软件AutoSAR自学攻略(四)-AutoSAR CP分层架构(3) (万字长文-配21张彩图)

汽车基础软件AutoSAR自学攻略(四)-AutoSAR CP分层架构(3) (万字长文-配21张彩图) 前面的两篇博文简述了AutoSAR CP分层架构的概念&#xff0c;下面我们来具体到每一层的具体内容进行讲解&#xff0c;每一层的每一个功能块力求用一个总览图&#xff0c;外加一个例子的图给大家进…

51单片机——定时器中断(重点)

STC89C5X含有3个定时器&#xff1a;定时器0、定时器1、定时器2 注意&#xff1a;51系列单片机一定有基本的2个定时器&#xff08;定时器0和定时器1&#xff09;&#xff0c;但不全有3个中断&#xff0c;需要查看芯片手册&#xff0c;通常我们使用的是基本的2个定时器&#xff…

LeetCode热题100-合并两个有序链表【JavaScript讲解】

题目&#xff1a; 题解&#xff1a; 我们目前已经知道两条链表都是有序链表&#xff0c;我们就可以通过迭代的方法实现上述问题。当list1和list2都不是空链表时&#xff0c;判断list1和list2哪个头节点的值更小&#xff0c;将较小的值添加到结果里&#xff0c;被添加到结果里的…

Artec Leo 3D扫描仪与Ray助力野生水生动物法医鉴定【沪敖3D】

挑战&#xff1a;捕获大型水生哺乳动物&#xff08;如鲸鱼&#xff09;的数据&#xff0c;搭建全彩3D模型&#xff0c;用于水生野生动物的法医鉴定、研究和保护工作。 解决方案&#xff1a;Artec Eva、Artec Space Spider、Artec Leo、Artec Ray、Artec Studio、CT scans 效果&…

HBuilderX打包ios保姆式教程

1、登录苹果开发者后台并登录已认证开发者账号ID Sign In - Apple 2、创建标识符&#xff08;App ID&#xff09;、证书&#xff0c;描述文件 3、首先创建标识符&#xff0c;用于新建App应用 3-1、App的话直接选择第一个App IDs&#xff0c;点击右上角继续 3-2、选择App&#x…

Android DataBinding 结合 ViewModel的使用

Android DataBinding 结合 ViewModel的使用 一、build.gradle引入对应的依赖 在build.gradle&#xff08;app模块&#xff09;里引入依赖&#xff0c;然后Sync Now一下&#xff1a; android {​viewBinding {enabled true}dataBinding {enabled true}} 完整的build.gradle代…

动植物基因表达调控

1&#xff0c; on and off状态 以及表达的量 2&#xff0c; 基因调控的生物学影响&#xff1f; 超过400多种细胞类型&#xff0c;数目上37万亿 不是所有的基因都表达 为什么多核真核细胞需要基因调控&#xff1f; 单个细胞往多个细胞逐渐进化的过程&#xff0c;形成复杂的…

2024年度漏洞态势分析报告,需要访问自取即可!(PDF版本)

2024年度漏洞态势分析报告&#xff0c;需要访问自取即可!(PDF版本),大家有什么好的也可以发一下看看

【数据结构】树的定义

在计算机科学中&#xff0c;树&#xff08;Tree&#xff09;是一种重要的基础数据结构&#xff0c;广泛应用于许多领域&#xff0c;如文件系统的目录结构、数据库的索引、编译器的语法树、人工智能的决策树等。理解树的基本概念和术语&#xff0c;对于学习计算机科学及其相关技…