【深入浅出设计模式--状态模式】

深入浅出设计模式--状态模式

一、背景

状态模式是一种行为设计模式,让你能在一个对象的内部状态变化时改变其行为,使其看上去就像改变了自身所属的类一样。其与有限状态机的概念紧密相关,如下所示:

二、问题

在实际设计编码UI界面的工作中,有很多人应该都遇到过类似这样的场景:当鼠标移动或者点击某个标签、按钮等组件时,对应组件上会根据鼠标的状态进行不同的响应,比如颜色大小的变化。如果状态有很多种,那我们就会在代码中添加许多条件判断(if-else、switch),有时候可能一条语句中的条件多达十来个,出现bug的时候调试起来相当恶心。基于这个问题,下面使用状态模式逐步解决。

三、解决方案

  1. 首先在上下文类Context中定义改变状态的接口changeState,并聚合了指向当前状态的IState对象指针,changeState的参数即为new生成的具体状态类NormorlState等,调用paintTags函数时会调用当前状态类的doPaint函数进行该状态下的绘制操作。
  2. 接口状态类IState中提供了doPaint纯虚函数,每个具体状态类会继承并重写doPaint,在doPaint中可以调用setHoverState等函数对Context类对象的成员变量进行修改,同步状态与操作。
  3. 为了对每个状态类对象进行复用,采用单例模式提供GetInstance函数供Context调用。
    类图如下:
  4. 上面的类结构中,因为每个具体状态类都是单例模式,提供除了名字不同之外相同的代码块,因此会有许多重复代码,因此想到在接口状态类IStateBase和具体状态类之间插入一个单例模板类IStateTemplate专门提供静态GetInstance函数,然后每个具体状态类对其继承和模板特化,这样在具体状态类中只需要实现doPaint函数即可。
  5. 各类达到高度凝练与抽象,每一层只专注某一功能的效果。后续如果有新加入一种状态,只需要特化IStateTemplate,然后重写doPaint函数即可,其他状态的代码无需修改,减少大量条件判断的同时也降低了出错的概率。
    改进后的类图如下:
  6. 该模式下各类之间交互的时序图如下:
  7. Context类关键代码截图:
  8. State相关类关键代码截图:

四、 适用场景总结

  • 如果对象需要根据自身当前状态(成员变量值)进行不同行为,同时状态的数量非常多且与状态相关的代码会频繁变更的话,可使用状态模式。
  • 当相似状态和基于条件的状态机转换中存在许多重复代码时,可使用状态模式。
  • 如果状态机只有很少的几个状态,或者很少发生改变,那么应用该模式可能会显得小题大作。

五、后记

以上所有内容均为原创,代码已上传至gayhub:
https://github.com/gangster-puppy/Design-Pattern.git

相关推荐
用户624293196622 小时前
告别 Electron 臃肿与 Wireshark 老化界面:用 Rust + Tauri 2.0 构建多总线网络与现场总线深度分析仪 Omni-Probe
设计模式
是2的10次方啊3 小时前
设计模式与生活㉒:暖气热不热,得一间一间摸过去
设计模式
ShineWinsu3 小时前
对于Qt:QTreeWidget常见属性以及QTreeWidgetItem类的解析
开发语言·c++·qt·gui·客户端·多叉树·qtreewidget
落羽的落羽4 小时前
【C++】C++17的主要特性
linux·服务器·开发语言·c++·算法·机器学习
bigbread8 小时前
迭代器模式-在区域健康档案导出中的实战应用
设计模式
汉克老师9 小时前
《从C++小白到算法高手:GESP 1—8级成长地图》第一讲:认识GESP——从编程新手到算法探索者
c++·gesp·信息学竞赛·小学生学c++
装不满的克莱因瓶10 小时前
设计模式之策略模式核心概念和应用场景
java·后端·设计模式·架构·系统架构·策略模式
晴天的雨.99211 小时前
【C++】继承篇
java·开发语言·c++
青少儿编程课堂11 小时前
蓝桥杯青少组图形化 + 全国青少年信息素养大赛 + 电子学会图形化考级:校园大富翁经营闯关解析
c++·python·算法·bfs·信息学竞赛
another heaven11 小时前
【C/C++ 第一次跨越(上):用 C++11/14 停止制造新的旧代码】
c语言·c++·制造