(十一)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.hqwc.cn/news/423122.html

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

相关文章

为什么电脑降价了?

周末&#xff0c;非常意外地用不到3000元买到了一款2023年度发布的华为笔记本I5,16G,500G&#xff0c;基本是主流配置&#xff0c;我非常意外&#xff0c;看了又看&#xff0c;不是什么Hwawii&#xff0c;或者Huuawe。然后也不是二手。为什么呢&#xff1f;因为在ALU和FPU之外&…

Java和Redis实现一个简单的热搜功能

1. 前言 我们有一个简单的需求&#xff1a; 搜索栏展示当前登陆的个人用户的搜索历史记录&#xff0c;删除个人历史记录。用户在搜索栏输入某字符&#xff0c;则将该字符记录下来 以zset格式存储的redis中&#xff0c;记录该字符被搜索的个数以及当前的时间戳 &#xff08;用…

Qt Linux安装qt5.9全过程

1 准备好安装包 qt安装包下载官网:https://download.qt.io/archive/qt 2 将安装包放到Linux环境下 我这里使用WinSCP将windows下的文件传输到Linux 3 ./qt-opensource-linux-x64-5.9.0.run 3-0 运行时目录的所有权错误wrong ownership on runtime directory 解决:切换roo…

K8S的helm

helm的作用 在没有helm之前&#xff0c;deploymen service ingress &#xff0c;helm的作用就是通过打包的方式&#xff0c;把deployment&#xff0c;service&#xff0c;ingress 这些打包在一块&#xff0c;一键式的部署服务&#xff0c;类似yum 官方提供的一个类似于安装仓库…

大数据开发之Scala

第 1 章&#xff1a;scala入门 1.1 概述 scala将面向对象和函数式编程结合成一种简洁的高级语言 特点 1、scala和java一样属于jvm语言&#xff0c;使用时都需要先编译为class字节码文件&#xff0c;并且scala能够直接调用java的类库 2、scala支持两种编程范式面向对象和函数式…

Maven工程继承和聚合关系

1. Maven工程继承关系 1.1 继承概念 Maven 继承是指在 Maven 的项目中&#xff0c;让一个项目从另一个项目中继承配置信息的机制。继承可以让我们在多个项目中共享同一配置信息&#xff0c;简化项目的管理和维护工作。 1.2 继承作用 在父工程中统一管理项目中的依赖信息。 …

初识 JVM

什么是JVM JVM 全称是 J ava V irtual M achine&#xff0c;中文译名 Java虚拟机 。 JVM 本质上是一个运行在计算机上的程序&#xff0c;他的职责是运行 Java字节码文件 。 JVM的功能 Java语言如果不做任何优化&#xff0c;性能不如C、C等语言。 Java需要实时解释&…

什么是网络安全?网络安全概况

网络安全涉及保护我们的计算机网络、设备和数据免受未经授权的访问或破坏。 这个领域包括多种技术、过程和控制措施&#xff0c;旨在保护网络、设备和数据免受攻击、损害或未授权访问。网络安全涉及多个方面&#xff0c;包括但不限于信息安全、应用程序安全、操作系统安全等 …

仓储管理系统——软件工程报告(详细设计)④

详细设计 一、系统功能模块的划分 根据系统的功能性需求&#xff0c;本文将部队仓库管理系统分为以下六大模块&#xff1a;系统管理模 块、基础数据模块、出入库管理模块、库存管理模块、仓库信息管理模块、作业管理模 块&#xff0c;每个模块内部又分为很多小功能模块&#…

ADC的工作原理总结

ADC和DAC是联系连续和离散的重要桥梁&#xff0c;是信号采集和处理的重要环节。 这里我们先认识下ADC&#xff0c;聊一聊ADC的工作原理。 信号为何要相互转换&#xff1f; 模拟信号和数字信号的特点 自然界中大多数都是连续的模拟信号&#xff0c;模拟信号容易受到干扰&#…

华为AC+FIT AP组网配置

AC配置 vlan batch 100 to 101dhcp enableip pool apgateway-list 192.168.100.254 network 192.168.100.0 mask 255.255.255.0 interface Vlanif100ip address 192.168.100.254 255.255.255.0dhcp select globalinterface GigabitEthernet0/0/1port link-type trunkport trun…