(十一)Head first design patterns状态模式(c++)

状态模式

如何去描述状态机?

假设你需要实例化一台电梯,并模仿出电梯的四个状态:开启、关闭、运行、停止。也许你会这么写

class ILift{
public:virtual void open(){}virtual void close(){}virtual void run(){}virtual void stop(){}
};
class Lift : public ILift{
public:void open(){ std::cout << "电梯门关闭..." << std::endl; }void close(){ std::cout << "电梯门开启..." << std::endl; }void run(){ std::cout << "电梯上下跑起来..." << std::endl; }void stop(){ std::cout << "电梯停止了..." << std::endl; }
};
int main(){ILift* lift = new Lift();lift->open();lift->close();lift->run();lift->stop();
}

这样写未免太草率了。因为电梯在门开启的时候一般是不能运行的,在运行的时候一般也不会门开启,而在停止工作状态一般不会再去执行关门这个动作。所以需要设置一些状态去限制这台电梯的行为。于是在类Lift中存储电梯目前的状态,在执行每个动作的时候用swith分支来判断当前动作是否有效,以及更新当前状态。于是有了下面的代码

class ILift{
public:virtual void setState(int state){};virtual void open(){}virtual void close(){}virtual void run(){}virtual void stop(){}
};
class Lift : public ILift{
public:Lift(int state):state(state){}void setState(int state){ this->state = state; }void close(){switch(state){case OPENING_STATE:closeWithoutLogic();setState(CLOSING_STATE);break;case CLOSING_STATE:break;case RUNNING_STATE:break;case STOPPING_STATE:break;}}void open(){switch(state){case OPENING_STATE:break;case CLOSING_STATE:openWithoutLogic();setState(OPENING_STATE);break;case RUNNING_STATE:break;case STOPPING_STATE:openWithoutLogic();setState(OPENING_STATE);}}void run(){switch(state){case OPENING_STATE:break;case CLOSING_STATE:runWithoutLogic();setState(RUNNING_STATE);break;case RUNNING_STATE:break;case STOPPING_STATE:runWithoutLogic();setState(RUNNING_STATE);}}void stop(){switch(state){case OPENING_STATE:break;case CLOSING_STATE:stopWithoutLogic();setState(STOPPING_STATE);break;case RUNNING_STATE:stopWithoutLogic();setState(STOPPING_STATE);break;case STOPPING_STATE:break;}}void closeWithoutLogic(){ std::cout << "电梯门关闭..." << std::endl; }void openWithoutLogic() { std::cout << "电梯门开启..." << std::endl; }void runWithoutLogic()  { std::cout << "电梯上下跑起来..." << std::endl; }void stopWithoutLogic() { std::cout << "电梯停止了..." << std::endl; }
private:int state;
};
int main(){ILift* lift = new Lift(STATE(OPENING_STATE));lift->close(); // 关闭lift->open();  // 开启lift->run();   // 无动作lift->stop();  // 无动作lift->close(); // 关闭
}

这个类的实现代码特别长,内部包含了太多的switch语句。而且当需要增加状态时,比如说电梯停电状态和电梯维修状态,就需要去更改里面的switch语句。这样写违背了开闭原则以及单一性原则。为了在增加状态的时候尽量少的修改原有代码,可以将swtich中的每个状态抽离出来单独包装成类。

创建context类,在context类中存有LiftState对象用来记录当前的状态。此时context目前拥有四种状态对象,用指针维护。每种状态的逻辑由各自类在内部实现。当电梯发生动作,即context调用函数时,函数内部会调用当前state对应的方法,于是这部分逻辑转交由state内部实现。具体代码如下:

#include<iostream>
#include<string>using namespace std;class ContextBase;
class LiftState{
public:void setContext(ContextBase* context){ this->mContext = context; }virtual void open(){}virtual void close(){}virtual void run(){}virtual void stop(){}ContextBase* getContext(){ return mContext; }
public:ContextBase* mContext;
};
class ContextBase{
public:ContextBase(){}virtual LiftState* getLiftState(){}virtual LiftState* getOpenningState(){}virtual LiftState* getClosingState(){}virtual LiftState* getRunningState(){}virtual LiftState* getStoppingState(){}virtual void setLiftState(LiftState* liftState){}virtual void open(){}virtual void close(){}virtual void run(){}virtual void stop(){}
public:LiftState* liftState;
};
class OpenningState : public LiftState{void open(){std::cout << "lift open..." << std::endl;}void close(){mContext->setLiftState(mContext->getClosingState());mContext->getLiftState()->close();}void run(){}void stop(){}
};
class ClosingState : public LiftState{void open(){mContext->setLiftState(mContext->getOpenningState());mContext->getLiftState()->open();}void close(){std::cout << "lift close..." << std::endl;}void run(){mContext->setLiftState(mContext->getRunningState());mContext->getLiftState()->run();}void stop(){mContext->setLiftState(mContext->getStoppingState());mContext->getLiftState()->stop();}
};
class RunningState : public LiftState{void open(){}void close(){}void run(){std::cout << "lift running..." << std::endl;}void stop(){mContext->setLiftState(mContext->getStoppingState());mContext->getLiftState()->stop();}
};
class StoppingState : public LiftState{void open(){mContext->setLiftState(mContext->getOpenningState());mContext->getLiftState()->open();}void close(){}void run(){mContext->setLiftState(mContext->getRunningState());mContext->getLiftState()->run();}void stop(){std::cout << "lift stopping..." << std::endl;}
};class Context : public ContextBase{
public:Context(){}LiftState* getLiftState(){return liftState;}LiftState* getOpenningState(){return openningState;}LiftState* getClosingState(){return closingState;}LiftState* getRunningState(){return runningState;}LiftState* getStoppingState(){return stoppingState;}void setLiftState(LiftState* liftState){this->liftState = liftState;this->liftState->setContext(this);}void open(){ liftState->open(); }void close(){ liftState->close(); }void run(){ liftState->run(); }void stop(){ liftState->stop(); }
public:LiftState* openningState = new OpenningState();LiftState* closingState  = new ClosingState();LiftState* runningState  = new RunningState();LiftState* stoppingState = new StoppingState();
};int main(){Context* context = new Context;context->setLiftState(new ClosingState());context->open();context->close();context->run();context->stop();
}

状态模式的优势:

当由新的状态加入时,只需要扩展子类,而不需要过多地更改原有代码。遵守了开闭原则。

当动作和状态更新等逻辑交由状态类内部实现,实现了单一性设计原则。

参考

Java设计模式——状态模式(STATE PATTERN)_java中state pattern-CSDN博客​​​​​​​

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

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

相关文章

基于SpringBoot Vue二手闲置物品交易系统

大家好✌&#xff01;我是Dwzun。很高兴你能来阅读我&#xff0c;我会陆续更新Java后端、前端、数据库、项目案例等相关知识点总结&#xff0c;还为大家分享优质的实战项目&#xff0c;本人在Java项目开发领域有多年的经验&#xff0c;陆续会更新更多优质的Java实战项目&#x…

4小时精通MyBatisPlus框架

目录 1.介绍 2.快速入门 2.1.环境准备 2.2.快速开始 2.2.1引入依赖 2.2.2.定义Mapper ​编辑 2.2.3.测试 2.3.常见注解 ​编辑 2.3.1.TableName 2.3.2.TableId 2.3.3.TableField 2.4.常见配置 3.核心功能 3.1.条件构造器 3.1.1.QueryWrapper 3.1.2.UpdateWra…

Flowable 加签和减签

一&#xff1a;示例 Deployment deploy repositoryService.createDeployment().name("会签流程").addClasspathResource("processes/CounterSignProcess.bpmn").deploy();ProcessInstance processInstance runtimeService.startProcessInstanceByKey(&qu…

【操作系统】同步和互斥详细讲解(算法+源码)

博主介绍&#xff1a;✌全网粉丝喜爱、前后端领域优质创作者、本质互联网精神、坚持优质作品共享、掘金/腾讯云/阿里云等平台优质作者、擅长前后端项目开发和毕业项目实战✌有需要可以联系作者我哦&#xff01; &#x1f345;附上相关C语言版源码讲解&#x1f345; &#x1f44…

记录一次从有道云笔记迁移到语雀笔记

推荐阅读 智能化校园&#xff1a;深入探讨云端管理系统设计与实现&#xff08;一&#xff09; 智能化校园&#xff1a;深入探讨云端管理系统设计与实现&#xff08;二&#xff09; 1、安装git&#xff0c;python3等准备工作 文章中标注python3&#xff0c;为避免与python2 冲…

【Java-框架-SpringSecurity】单点登录(认证和授权)- 随笔

项目文件&#xff1b; 【1】 【2】 【3】 【4】 【5】 【6】 【7】 【8】

【小白学机器学习3】关于最简单的线性回归,和用最小二次法评估线性回归效果, 最速下降法求函数的最小值

目录 1 什么是回归分析 1.1 什么是线性回归 1.2非线性回归 2 数据和判断方法 2.1 原始数据 2.2 判断方法&#xff1a;最小二乘法 3 关于线性回归的实测 3.1 用直线模拟 3.2 怎么判断哪个线性模拟拟合更好呢&#xff1f; 3.2.1 判断标准 3.2.2 最小二乘法 3.2.3 高维…

【征服redis16】收官-redis缓存一致性问题解决方案

今天我们来写redis最后一篇&#xff1a;redis作为缓存时如何与数据库实现数据一致的问题。 最近看redis看得有点麻了&#xff0c;这篇就简单描述吧 目录 1.什么是缓存与数据库一致性问题 1.1 缓存一致性的概念 1.2 缓存不一致的场景 2.缓存不一致的解决思路 1.什么是缓存…

HarmonyOS 通过Web组件嵌套网络应用

我们今天来说说 在程序中嵌套一个网址地址 HarmonyOS中是通过一个简单的WEB组件来实现 网络应用就是相当于网址地址 通过链接将应用嵌入到手机当中 WEB组件需要两个参数 一个是 src 地址 要嵌套的网址 另一个是 控制器 我们可以先编写代码如下 import webview from "o…

力扣hot100 环形链表 快慢指针 计步器

Problem: 141. 环形链表 文章目录 思路&#x1f496; 快慢指针法&#x1f496; 计步器法 思路 &#x1f468;‍&#x1f3eb; 参考题解 &#x1f496; 快慢指针法 时间复杂度: O ( n ) O(n) O(n) 空间复杂度: O ( 1 ) O(1) O(1) /*** Definition for singly-linked list…

【QT+QGIS跨平台编译】之五:【curl+Qt跨平台编译】(一套代码、一套框架,跨平台编译)

文章目录 一、curl介绍二、curl下载三、文件分析四、pro文件五、编译实践 一、curl介绍 curl&#xff08;CommandLine Uniform Resource Locator&#xff09;主要功能就是用不同的协议连接和沟通不同的服务器&#xff0c;相当封装了的socket。 libcurl支持http, https, ftp, g…

大模型实战营Day5笔记

大模型部署背景 大模型部署是指将训练好的模型在特定的软硬件环境中启动的过程&#xff0c;使模型能够接收输入并返回预测结果。大模型的内存开销巨大&#xff0c;7B模型仅权重需要14G内存。另外大模型是自回归生成&#xff0c;需要缓存Attention的 k/v。 LMDeploy 简…

超简单的OCR模块:cnocr

前言 毫无疑问的是&#xff0c;关于人工智能方向&#xff0c;python真的十分方便和有效。 这里呢&#xff0c;我将介绍python众多OCR模块中一个比较出色的模块&#xff1a;cnocr 模块介绍 cnocr是一个基于PyTorch的开源OCR库&#xff0c;它提供了一系列功能强大的中文OCR模型和…

小型园区组网实例

目录 拓扑需求IP规划路由配置交换机配置NAT配置ACL配置DHCP配置配置过程&#xff1a;配置结果&#xff1a; OSPF配置链路聚合配置配置过程&#xff1a; 网络测试 拓扑 需求 企业网络信息服务平台需实现功能&#xff1a;企业网站服务器、FTP服务器、DNS服务器。企业ip分配地址段…

阿里巴巴开源联邦学习框架FederatedScope

5月5日&#xff0c;阿里巴巴达摩院发布新型联邦学习框架FederatedScope&#xff0c;声称可以在不共享训练数据的情况下开发机器学习算法&#xff0c;从而保护隐私。&#xff0c;其源代码现已在Apache 2.0许可下发布在GitHub上。 介绍 该平台被描述为一个全面的联邦学习框架&a…

html 3D 倒计时爆炸特效

下面是代码&#xff1a; <!DOCTYPE html> <html><head><meta charset"UTF-8"><title>HTML5 Canvas 3D 倒计时爆炸特效DEMO演示</title><link rel"stylesheet" href"css/style.css" media"screen&q…

Ubuntu用gparted重新分配空间

ubuntu系统使用过程中安装系统时预先留的空间不够使用怎么办&#xff1f; 这么办&#xff01; 首先 使用df -h 查看当前空间使用情况 已经分配的空间重新规划 &#xff1f; 先将已分配的空间中的多余空间分离出来&#xff1b; 假设我想将挂载点/home下的一部分空间分给挂载…

BL120PM PLC网关,实现PLC协议转Modbus协议

随着物联网技术的迅猛发展&#xff0c;人们深刻认识到在智能化生产和生活中&#xff0c;实时、可靠、安全的数据传输至关重要。在此背景下&#xff0c;高性能的物联网数据传输解决方案——协议转换网关应运而生&#xff0c;广泛应用于工业自动化和数字化工厂应用环境中。 钡铼…

在linux部署Prometheus+Grafana+Exporter监控系统性能

Prometheus、Grafana和Report组件是什么&#xff1f; Prometheus、Grafana和Exporter是常用于系统监控和指标收集的组合。 Prometheus是一种开源的系统监控和警报工具。它可以收集各种指标数据&#xff0c;并提供强大的查询语言和灵活的警报规则&#xff0c;用于实时监控系统…

Prometheus配置Grafana监控大屏(Docker)

拉取镜像 docker pull grafana/grafana挂载目录 mkdir /data/prometheus/grafana -p chmod 777 /data/prometheus/grafana临时启动 docker run -d -p 3000:3000 --name grafana grafana/grafana从容器拷贝配置文件至对应目录 docker exec -it grafana cat /etc/grafana/gra…