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

设计模式:状态模式 State

目录

  • 前言
  • 问题
  • 解决方案
  • 代码


前言

状态是一种行为设计模式,让你能在一个对象的内部状态变化时改变其行为,使其看上去就像改变了自身所属的类一样。


问题

状态模式与 有限状态机 的概念紧密相关。
在这里插入图片描述
其主要思想是程序在任意时刻仅可处于几种有限的状态中。在任何一个特定状态中, 程序的行为都不相同, 且可瞬间从一个状态切换到另一个状态。不过,根据当前状态,程序可能会切换到另外一种状态, 也可能会保持当前状态不变。 这些数量有限且预先定义的状态切换规则被称为转移。

你还可将该方法应用在对象上。假如你有一个 文档Document 类。 文档可能会处于 草稿 Draft 、 审阅中 Moderation 和 已发布 Published 三种状态中的一种。文档的 publish 发布 方法在不同状态下的行为略有不同:

• 处于 草稿 状态时,它会将文档转移到审阅中状态。

• 处于 审阅中 状态时, 如果当前用户是管理员, 它会公开发布文档。

• 处于 已发布 状态时,它不会进行任何操作。

在这里插入图片描述
状态机通常由众多条件运算符( if 或 switch )实现,可根据对象的当前状态选择相应的行为。“状态” 通常只是对象中的一组成员变量值。 即使你之前从未听说过有限状态机,你也很可能已经实现过状态模式。

当我们逐步在 文档 类中添加更多状态和依赖于状态的行为后, 基于条件语句的状态机就会暴露其最大的弱点。为了能根据当前状态选择完成相应行为的方法, 绝大部分方法中会包含复杂的条件语句。修改其转换逻辑可能会涉及到修改所有方法中的状态条件语句,导致代码的维护工作非常艰难。

这个问题会随着项目进行变得越发严重。 我们很难在设计阶段预测到所有可能的状态和转换。 随着时间推移, 最初仅包含有限条件语句的简洁状态机可能会变成臃肿的一团乱麻。

解决方案

状态模式建议为对象的所有可能状态新建一个类, 然后将所有状态的对应行为抽取到这些类中。

原始对象被称为上下文(context), 它并不会自行实现所有行为,而是会保存一个指向表示当前状态的状态对象的引用,且将所有与状态相关的工作委派给该对象。
在这里插入图片描述
如需将上下文转换为另外一种状态, 则需将当前活动的状态对象替换为另外一个代表新状态的对象。 采用这种方式是有前提的: 所有状态类都必须遵循同样的接口, 而且上下文必须仅通过接口与这些对象进行交互。

这个结构可能看上去与策略模式相似, 但有一个关键性的不同——在状态模式中, 特定状态知道其他所有状态的存在,且能触发从一个状态到另一个状态的转换; 策略则几乎完全不知道其他策略的存在。

代码

#include <iostream>
#include <string>
#include <memory>
using namespace std;enum User{Admin,Author
};
User global_user=Admin;class State{
public:virtual void render()=0;virtual void publish()=0;virtual ~State(){}
};
class Document{
public:void render(){m_state->render();}void publish(){m_state->publish();}void changeState(shared_ptr<State> state){m_state=state;}
private:shared_ptr<State> m_state=nullptr;
};class Published:public State{
public:void render() override{}void publish() override{}
};
class Moderation:public State{
public:void render() override{}void publish() override{}
};
class Draft:public State{
public:Draft(shared_ptr<Document> doc):m_document(doc){}void render() override{if(global_user==Admin || global_user==Author){cout<<"渲染文档"<<endl;}else{cout<<"非法用户"<<endl;}}void publish() override{if(global_user==Admin){cout<<"Admin用户在保存文档"<<endl;m_document->changeState(make_shared<Published>());}else{m_document->changeState(make_shared<Moderation>());}}
private:shared_ptr<Document> m_document=nullptr;
};int main(){auto document=make_shared<Document>();document->changeState(make_shared<Draft>(document));document->render();document->publish();return 0;
}
http://www.dtcms.com/a/303728.html

相关文章:

  • 【Redis实现基础的分布式锁及Lua脚本说明】
  • 【CAN总线】STM32 的 CAN 总线通信开发笔记(基于 HAL)
  • Spring Boot 自动配置:从 2.x 到 3.x 的进化之路
  • Python 程序设计讲义(28):字符串的用法——格式化字符串
  • 【C++】第十九节—一文万字详解 | AVL树实现
  • Go进阶:流程控制(if/for/switch)与数组切片
  • adb reboot 与 adb shell svc power reboot 的区别
  • 爬虫自动化:一文掌握 PyAutoGUI 的详细使用
  • 【RH134 问答题】第 9 章 访问网络附加存储
  • 智能制造的空间度量:机器视觉标定技术解析
  • 数据结构【红黑树】
  • 架构实战——互联网架构模板(“用户层”和“业务层”技术)
  • MySql插入中文生僻字/Emoji报错django.db.utils.DataError: (1366, “Incorrect string value
  • 14、distance_object_model_3d算子
  • Web3 网络安全漏洞的预防措施
  • 解决IDEA拉取GitLab项目报错:必须为访问令牌授予作用域[api, read user]
  • 风口还是伪命题?AI + Web3 赛道价值何在?
  • Time drifts can result in unexpected behavior such as time-outs.
  • IDEA中全局搜索快捷键Ctrl+Shift+F为何失灵?探寻原因与修复指南
  • imx6ull-驱动开发篇3——字符设备驱动开发实验
  • 【C++算法】79.BFS解决FloodFill算法_图像渲染
  • 【C#|C++】C#调用C++导出的dll之非托管的方式
  • 数据结构 排序(1)---插入排序
  • 基于mysql云数据库对比PowerBI vs QuickBI vs FineBI更换数据源的可行性
  • Kafka——Kafka控制器
  • 如何选择工业电脑?
  • 【VOS虚拟操作系统】未来之窗打包工具在前端资源优化中的应用与优势分析——仙盟创梦IDE
  • Spring AI集成Elasticsearch向量检索时filter过滤失效问题排查与解决方案
  • ICT模拟零件测试方法--晶体管测试
  • Linux救援模式之应用篇