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

行为型设计模式——状态模式

文章目录状态模式结构实现特点状态模式场景在软件系统中有些对象也像水一样具有多种状态这些状态在某些情况下能够相互转换而且对象在同的状态下也将具有不同的行为。如果使用复杂的条件判断语句如if或switch来进行状态的判断和换操作这会导致代码的可维护性和灵活性下降特别是出现新状态的时候代码的扩展性很差客户端码也需要进行修改违反开闭原则。为了更好地对这些具有多种状态的对象进行设计我们可以使用一被称之为状态模式State Pattern的设计模式。人在幼年、童年、少年、中年、老年各个使其的形态都是不一样的工作期间上午、中午、下午、傍晚、深夜的工作状态也不一样人的心情不同时会有喜、怒、哀、乐手机在待机、通话、充电、游戏时的状态也不一样文章的发表会有草稿、审阅、发布状态⚠️状态模式和策略模式比较类似策略模式中的各个策略是独立的不关联的但是状态模式下的对象的各种状态可以是独立的也可以是相互依赖的比如上面关于文章的发布的例子普通用户的文章草稿发表之后被审阅审阅失败重新变成草稿管理用户的文章操作发布成功变成已发表状态, 发布失败重新变成草稿 状态模式就是在一个类的内部会有多种状态的变化因为状态变化从而导致其行为的改变在类的外部看上去这个类就像是自身发生了改变一样。 结构在状态模式结构图中包含如下几个角色Context环境类环境类又称为上下文类它是拥有多种状态的对象。由于环境类的状态存在多样性且在不同状态下对象的行为有所不同因此将状态独立出去形成单独的状态类。在环境类中维护一个抽象状态类State的实例这个实例定义当前状态在具体实现时它是一个State子类的对象。State抽象状态类它用于定义一个接口以封装与环境类的一个特定状态相关的行为在抽象状态类中声明了各种不同状态对应的方法而在其子类中实现类这些方法由于不同状态下对象的行为可能不同因此在不同子类中方法的实现可能存在不同相同的方法可以写在抽象状态类中。Concrete State具体状态类它是抽象状态类的子类每一个子类实现一个与环境类的一个状态相关的行为每一个具体状态类对应环境的一个具体状态不同的具体状态类其行为有所不同。在状态模式的使用过程中一个对象的状态之间还可以进行相互转换通常有两种实现状态转换的方式public:voidchangeState(){/判断属性值根据属性值进行状态转换if(value0){this-setState(newConcreteStateA());}elseif(value1){this-setState(newConcreteStateB());}}public:voidchangeState(Context*ctx){/根据环境对象中的属性值进行状态转换if(ctx-getValue()1){ctx-setState(newConcreteStateB());}elseif(ctx-getValue()2){ctx-setState(newConcreteStateC());}}实现// State.h// 抽象状态classSanji;classAbstractState{public:virtualvoidworking(Sanji*sanji)0;virtual~AbstractState(){}};// 上午状态classForenoonState:publicAbstractState{public:voidworking(Sanji*sanji)override;};// 中午状态classNoonState:publicAbstractState{public:voidworking(Sanji*sanji)override;};// 下午状态classAfternoonState:publicAbstractState{public:voidworking(Sanji*sanji)override;};// 晚上状态classEveningState:publicAbstractState{public:voidworking(Sanji*sanji)override;};#includeiostream#includeState.h#includeSanji.husingnamespacestd;voidForenoonState::working(Sanji*sanji){inttimesanji-getClock();if(time8){cout当前时间time点, 准备早餐, 布鲁克得多喝点牛奶...endl;}elseif(time8time11){cout当前时间time点, 去船头钓鱼, 储备食材...endl;}else{sanji-setState(newNoonState);sanji-working();}}voidNoonState::working(Sanji*sanji){inttimesanji-getClock();if(time13){cout当前时间time点, 去厨房做午饭, 给路飞多做点肉...endl;}else{sanji-setState(newAfternoonState);sanji-working();}}voidAfternoonState::working(Sanji*sanji){inttimesanji-getClock();if(time15){cout当前时间time点, 准备下午茶, 给罗宾和娜美制作爱心甜点...endl;}elseif(time15time18){cout当前时间time点, 和乔巴去船尾钓鱼, 储备食材...endl;}else{sanji-setState(newEveningState);sanji-working();}}voidEveningState::working(Sanji*sanji){inttimesanji-getClock();if(time19){cout当前时间time点, 去厨房做晚饭, 让索隆多喝点汤...endl;}else{cout当前时间time点, 今天过得很高兴, 累了睡觉了...endl;}}// Sanji.h#pragmaonce#includeState.hclassSanji{public:Sanji(){m_statenewForenoonState;}//工作函数在不同的时间状态下工作的内容也不同voidworking(){m_state-working(this);}//设置山治当前的状态voidsetState(AbstractState*state){if(m_state!nullptr){deletem_state;}m_statestate;}//设置当前的时间voidsetClock(inttime){m_clocktime;}//得到当前的时间intgetClock(){returnm_clock;}~Sanji(){deletem_state;}private://通过这整形的时钟变量来描述一天中当前这个时刻的时间点intm_clock0;// 时钟//通过这个状态指针来保存当前描述山治状态的对象AbstractState*m_statenullptr;};intmain(){Sanji*sanjinewSanji;// 时间点vectorintdata{7,10,12,14,16,18,22};for(constautoitem:data){sanji-setClock(item);sanji-working();}deletesanji;return0;}特点在实际开发中状态模式具有较高的使用频率在工作流和游戏开发中状态模式都得到了广泛的应用例如公文状态的转换、游戏中角色状态切换等。主要优点封装了状态的转换规则在状态模式中可以将状态的转换代码封装在环境类或者具体状态类中可以对状态转换代码进行集中管理而不是分散在一个个业务方法中。将所有与某个状态有关的行为放到一个类中只需要注入一个不同的状态对象即可使环境对象拥有不同的行为。允许状态转换逻辑与状态对象合成一体而不是提供一个巨大的条件语句块状态模式可以让我们避免使用庞大的条件语句来将业务方法和状态转换代码交织在一起。可以让多个环境对象共享一个状态对象从而减少系统中对象的个数。主要缺点状态模式的使用必然会增加系统中类和对象的个数导致系统运行开销增大。状态模式的结构与实现都较为复杂如果使用不当将导致程序结构和代码的混乱增加系统设计的难度。状态模式对“开闭原则”的支持并不太好增加新的状态类需要修改那些负责状态转换的源代码否则无法转换到新增状态修改某个状态类的行为也需修改对应类的源代码。适用环境如果对象需要根据当前自身状态进行不同的行为 同时状态的数量非常多且与状态相关的代码会频繁变更或者类对象在改变自身行为时需要使用大量的条件语句时可使用状态模式。如果对象需要根据自身当前状态进行不同行为同时状态的数量非常多且与状态相关的代码会频繁变更的话可使用状态模式。如果某个类需要根据成员变量的当前值改变自身行为从而需要使用大量的条件语句时可使用该模式。当相似状态和基于条件的状态机转换中存在许多重复代码时可使用状态模式。
http://www.gsyq.cn/news/1386491.html

相关文章:

  • 【CP-05】RTE运行时环境 - SWC的操作系统接口
  • SAP顾问实战:如何用ABAP函数MD_STOCK_REQUIREMENTS_LIST_API批量跑MD04数据(附完整代码)
  • 从‘邮票贴钱’到算法面试:回溯法解连续邮资问题的实战拆解与思路升华
  • 电赛备赛别慌!这份集成运放电路速查手册+Multisim仿真文件,帮你快速上手
  • 数据融合驱动的全地面起重机路面信息识别技术【附数据】
  • RT-Thread FinSH命令导出全解析:从MSH_CMD_EXPORT宏到bin文件里的秘密
  • 从LED闪烁到外设驱动:STM32 HAL库GPIO实战进阶,用CubeMx配置按键、蜂鸣器和继电器
  • 清华大学学位论文LaTeX排版终极指南:3步快速生成标准格式
  • Cadence SPB17.4元件管理器实战:批量更新原理图属性,别再傻傻手动改了
  • 2026年5月市面上冰箱清洗服务商哪家强厂家推荐榜,直冷/风冷/对开门冰箱清洗选择指南 - 海棠依旧大
  • 别再傻傻分不清:Mol、SDF、SMILES文件格式到底怎么选?
  • 揭秘生物年龄计算:BioAge工具包如何帮你量化衰老进程
  • Apifox环境变量+JavaScript实战:5分钟搞定Google Gemini API接口自动化测试
  • 有哪些AI论文软件是真的坚守学术严谨,而不是空洞拼凑?
  • (毕业必看)实测靠谱的AI论文软件,毕业党收藏备用
  • 从零到一:在LUNIX系统上部署Anubis并进行GNSS数据质量分析
  • 2026年5月国内专业水泥电杆底盘供应商排行:高压水泥电线杆、高强度水泥电杆、高强度水泥电线杆、低压水泥电线杆选择指南 - 优质品牌商家
  • 2026年5月行业观察:莆田可靠的LV鞋店价值评估与供应链选择 - 2026年企业推荐榜
  • 别扔!用吃灰的TP-LINK-WR703N做个无线打印服务器,保姆级刷机教程(含Breed+OpenWrt)
  • 避坑指南:在Docker容器里为OpenCV编译Nvidia GPU硬解码支持,我踩过的那些‘库版本’的坑
  • 2026年江苏区域静电检测闸机专业厂家TOP5排行:上海翼闸速通门/上海通道闸门禁/上海防静电门禁闸机/上海防静电闸机/选择指南 - 优质品牌商家
  • android主流闹钟流程/架构-------------不用改架构
  • 从理论推导到代码实现:手把手教你用Python/Numpy写出守恒形式的NS方程求解器
  • 手把手教你用C++和倍福ADS库在Ubuntu上读写PLC变量(附完整CMake配置)
  • 2026年Q2国内主流超声治疗仪品牌排行盘点:经颅磁疗仪/膝盖超声波治疗仪/超声波治疗器/超声波治疗理疗/便携超声波治疗仪/选择指南 - 优质品牌商家
  • 三、Tucker 分解:从高阶PCA到多维数据压缩的实战解析
  • Redis沙盒体验:在浏览器中零门槛掌握NoSQL核心技能
  • 【DeepSeek安全测试辅助实战指南】:20年攻防专家亲授3大高危漏洞自动识别技巧
  • ARM AArch32通用定时器寄存器架构与CNTHPS_TVAL详解
  • 别再自己画库了!手把手教你用立创EDA+AD19快速搞定原理图库(以BMI088为例)