设计模式12:状态模式

 系列总链接:《大话设计模式》学习记录_net 大话设计-CSDN博客

参考:设计模式之状态模式 (C++ 实现)_设计模式的状态模式实现-CSDN博客

1.概述

      状态模式允许一个对象在其内部状态改变时改变其行为。对象看起来像是改变了其类。使用状态模式可以将状态的相关行为放在各个状态类中,从而实现状态切换的灵活性和可扩展性。

       用例子来说明,小明是个大学生(对象),简化其状态为:困,饿,饱;简化行为:吃饭,睡觉,打王者;默认情况下小明的行为和状态之间的关系会有偶然性,所以会存在逻辑上的if-else组合,要考虑地全面,这分支无疑会比较多,并且可以出错。如果从状态模式处理小明状态和行为的逻辑问题,可以把小明的状态抽象为状态类(State),各种具体的状态定为其的继承类(ConcreteState),小明具体如何在行为和状态间切换的场景类(Context)。这样会比较清晰,各自的状态类下和其相关的行为会比较清晰;如果想新增状态类,也比较方便。

2.结构与实现

结构:

状态模式主要由以下几个部分构成:

  1. Context (上下文):持有一个具体的状态对象,并在状态之间切换。
  2. State (状态接口):定义一个接口用于在具体状态中实现不同的行为。
  3. ConcreteState (具体状态):实现状态接口的具体类,每个状态都有自己的行为。

实现:

参照概述的中例子,实现如下:

State.h:

#ifndef STATE_H
#define STATE_H

#include <QDebug>

class People;

class State
{
public:
    State() {}
    virtual void sleep(People* xiaoming)=0;
    virtual void eat(People* xiaoming)=0;
    virtual void playWangzhe(People* xiaoming)=0;
};

//疲劳
class tiredState : public State
{
public:
    tiredState(){}
    void sleep(People* people);
    void eat(People* people);
    void playWangzhe(People* people);
};

//饥饿
class hungryState : public State
{
public:
    hungryState(){}
    void sleep(People* people);
    void eat(People* people);
    void playWangzhe(People* people);
};

//饱
class fullState : public State
{
public:
    fullState(){}
    void sleep(People* people);
    void eat(People* people);
    void playWangzhe(People* people);
};

#endif // STATE_H

State.cpp:

#include "State.h"
#include "People.h"

void tiredState::sleep(People *people)
{
    qDebug() << "tired, go to sleeping and hungry.";
    people->setState(new hungryState());
}

void tiredState::eat(People *people)
{
    qDebug() << "tired, no want to eat...";
}

void tiredState::playWangzhe(People *people)
{
    qDebug() << "tired, no want to play...";
}

void hungryState::sleep(People *people)
{
    qDebug() << "hungry, no want to sleep...";
}

void hungryState::eat(People *people)
{
    qDebug() << "hungry, go to eat and full.";
    people->setState(new fullState());
}

void hungryState::playWangzhe(People *people)
{
    qDebug() << "hungry, no want to play...";
}

void fullState::sleep(People *people)
{
    qDebug() << "full, no want to sleep...";
}

void fullState::eat(People *people)
{
    qDebug() << "full, no want to eat...";
}

void fullState::playWangzhe(People *people)
{
    qDebug() << "full, go to play wangzhe and tired.";
    people->setState(new tiredState());
}

People.h:

#ifndef PEOPLE_H
#define PEOPLE_H

#include "State.h"

class People
{
public:
    People() {state = new tiredState();}
    ~People(){delete state;}

    void setState(State* newState){
        delete state;
        state = newState;
    }
    void play();
    void sleep();
    void eat();

private:
    State* state;
};
#endif // PEOPLE_H

People.cpp:

#include "People.h"
void People::play()
{
    state->playWangzhe(this);
}

void People::sleep()
{
    state->sleep(this);
}

void People::eat()
{
    state->eat(this);
}

main.cpp:

#include <QCoreApplication>
#include "People.h"

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    People* xiaoming = new People();
    xiaoming->eat();
    xiaoming->play();
    xiaoming->sleep();
    xiaoming->eat();
    xiaoming->play();
    xiaoming->eat();

    delete xiaoming;
    return 0;
}

运行效果:

tired, no want to eat...
tired, no want to play...
tired, go to sleeping and hungry.
hungry, go to eat and full.
full, go to play wangzhe and tired.
tired, no want to eat...

3.应用

状态机,游戏开发、网络协议处理、用户界面

4.优缺点及适用环境

优点:

  1. 简化对象的实现:通过将不同的状态逻辑分离到不同的类中,可以使原本复杂的条件语句变得更加简单明了。
  2. 符合开闭原则:当需要增加新的状态时,只需添加新的状态类而无需修改现有的代码,提高了系统的可扩展性。
  3. 提高内聚性:每个状态的行为被封装在一个单独的类中,增强了模块化和内聚性。
  4. 清晰的状态转换:状态模式使得状态之间的转换更加明确和易于管理。

缺点:

  1. 可能引入过多的类:对于每一个状态都需要创建一个新的类,这可能会导致系统中有过多的小类,增加了复杂度。
  2. 状态爆炸问题:如果状态之间存在多种组合,那么将会产生大量的状态类,维护起来较为困难。
  3. 上下文与状态之间的耦合:状态对象通常依赖于上下文对象,反之亦然,这可能导致较高的耦合度。

应用环境:

  • 当一个对象在它的生命周期中需要根据不同的状态表现出不同的行为时。
  • 当状态转换的逻辑复杂,使用多个条件语句来处理会使得代码难以理解和维护时。
  • 当系统中存在大量相似但又有些许差异的状态或行为时,可以利用状态模式来减少重复代码并提高灵活性。
  • 在有限状态机(FSM)中,状态模式是一个常见的选择,用于建模具有不同状态和事件驱动转换的系统。

综上所述,状态模式适用于那些有明显状态变化并且这些状态变化会导致行为变更的情况,尤其是在你希望保持代码整洁、易于扩展的情况下。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

如何使用 Wireshark:从入门到进阶的网络分析工具

简述 Wireshark 是全球最受欢迎的网络协议分析工具&#xff0c;它帮助用户捕获和分析网络流量&#xff0c;诊断网络问题&#xff0c;排查安全漏洞&#xff0c;甚至恢复丢失的数据文件。作为一名网络工程师、安全专家、甚至是开发者&#xff0c;Wireshark 都是你必须掌握的工具…

100个问题学langchain入门(2/10)

问题 11 在 LangChain 中&#xff0c;如何将文档转化为向量以存储到 Vectorstore 中&#xff1f;具体使用了哪些技术或工具&#xff1f; 在 LangChain 中&#xff0c;将文档转化为向量以存储到 Vectorstore 中&#xff0c;主要通过以下步骤和技术完成&#xff1a; 转化流程&a…

C#winform引入DLL,DLL嵌入exe

C#winform将DLL嵌入exe 1 项目引入DLL1.1 项目-鼠标右击-点击添加引用&#xff1b;1.2 点击“浏览”&#xff1b;1.3 添加选中DLL1.4 勾选引入的DLL&#xff0c;点击“确定”1.5 添加成功后 2 DLL嵌入exe2.1 打开引入DLL属性窗口2.2 将“复制本地”项设为“false”2.3 双击打开…

828华为云征文 | 华为云Flexus云服务器X实例搭建企业内部VPN私有隧道,以实现安全远程办公

VPN虚拟专用网络适用于企业内部人员流动频繁和远程办公的情况&#xff0c;出差员工或在家办公的员工利用当地ISP就可以和企业的VPN网关建立私有的隧道连接。 通过拨入当地的ISP进入Internet再连接企业的VPN网关&#xff0c;在用户和VPN网关之间建立一个安全的“隧道”&#xff…

wxpyton+wxFormBuilder加法运算示例

wxpythonwxFormBuilder加法运算示例 在wxFormBuilder里设计一个窗体&#xff0c;生成如下代码&#xff1a;calc_From.py 放在lib文件夹下面 import gettext import wx import wx.xrc _ gettext.gettext class MyFrame1(wx.Frame):def __init__(self, parent):wx.Frame.__init…

【AI驱动的数据结构:包装类的艺术与科学】

&#x1f308;个人主页: Aileen_0v0 &#x1f525;热门专栏: 华为鸿蒙系统学习|计算机网络|数据结构与算法 ​&#x1f4ab;个人格言:“没有罗马,那就自己创造罗马~” 文章目录 包装类装箱和拆箱阿里巴巴面试题 包装类 在Java中基本数据类型不是继承来自Object&#xff0c;为了…

springBoot Maven 剔除无用的jar引用

目录 Used undeclared dependencies found Unused declared dependencies found 当项目经过一段时间的开发和维护后&#xff0c;经常会遇到项目打包速度变慢的问题。这通常与项目中包含大量的jar依赖有关&#xff0c;这些依赖之间的关系错综复杂。这种情况在项目维护过程中是…

电脑玩《刺客信条》时中,遇到找不到d3dx9_42.dll的问题是什么原因?缺失d3dx9_42.dll应该怎么解决呢?下面一起来看看吧!

电脑玩《刺客信条》时&#xff0c;找不到d3dx9_42.dll的原因及解决办法 对于许多热爱《刺客信条》这款游戏的玩家来说&#xff0c;在游戏中遇到找不到d3dx9_42.dll的问题无疑是非常令人头疼的。这一错误不仅会导致游戏无法启动&#xff0c;还可能引发运行过程中的图形错误、卡…

【CSS in Depth 2 精译_083】13.3:CSS 混合模式的用法及相关注意事项 + 13.4:本章小结

当前内容所在位置&#xff08;可进入专栏查看其他译好的章节内容&#xff09; 第四部分 视觉增强技术 ✔️【第 13 章 渐变、阴影与混合模式】 ✔️ 13.1 渐变 13.1.1 使用多个颜色节点&#xff08;上&#xff09;13.1.2 颜色插值方法&#xff08;中&#xff09;13.1.3 径向渐变…

环境变量的知识

目录 1. 环境变量的概念 2. 命令行参数 2.1 2.2 创建 code.c 文件 2.3 对比 ./code 执行和直接 code 执行 2.4 怎么可以不带 ./ 2.4.1 把我们的二进制文件拷贝到 usr/bin 路径下&#xff0c;也不用带 ./ 了 2.4.2 把我们自己的路径添加到环境变量里 3. 认识PATH 3.…

Linux Swap: 深入解析 mkswap, mkfs.swap, 和 swapon

文章目录 Linux Swap: 深入解析 mkswap, mkfs.swap, 和 swapon什么是 Swap&#xff1f;主要命令介绍1. mkswap2. mkfs.swap3. swapon 创建和管理 Swap 的步骤1. 创建 Swap 分区2. 初始化 Swap3. 激活 Swap4. 持久化配置5. 查看 Swap 状态 删除 Swap 分区或文件1. 停用 Swap2. 删…

模具生产过程中的标签使用流程图

①NFC芯片嵌入周转筐&#xff0c;通过读卡器读取CK_Label_v3的数据&#xff0c;并将这些信息上传至服务器进行存储&#xff1b; ②服务器随后与客户的WMS&#xff08;仓库管理系统&#xff09;进行交互&#xff0c;记录和同步注塑机的原始数据&#xff1b; ③当周转筐内的模具…

自己搭建专属AI:Llama大模型私有化部署

前言 AI新时代&#xff0c;提高了生产力且能帮助用户快速解答问题&#xff0c;现在用的比较多的是Openai、Claude&#xff0c;为了保证个人隐私数据&#xff0c;所以尝试本地&#xff08;Mac M3&#xff09;搭建Llama模型进行沟通。 Gpt4all 安装比较简单&#xff0c;根据 G…

【笔记】深度学习模型评估指标

推荐链接&#xff1a; &#xff08;0&#xff09;多分类器的评价指标 &#xff08;1&#xff09;泛化误差的评价方法&#xff1a;【机器学习】模型评估与选择&#xff08;留出法、交叉验证法、查全率、查准率、偏差、方差&#xff09; &#xff08;2&#xff09;机器学习&…

前端实现页面自动播放音频方法

前端实现页面视频在谷歌浏览器中自动播放音频方法 了解Chrome自动播放策略 在Chrome和其他现代浏览器中&#xff0c;为了改善用户体验&#xff0c;自动播放功能受到了限制。Chrome的自动播放策略主要针对有声音的视频&#xff0c;目的是防止页面在用户不知情的情况下自动播放声…

MinCostMaxFlow-Graph Algorithm

lab要求如下&#xff1a; 1.代码实现思路 图的构建 使用邻接表 adjacencyList 来存储图的结构&#xff0c;每个节点对应一个列表&#xff0c;列表中存储从该节点出发的所有边。 通过 addEdge 方法添加有向边及其反向边&#xff0c;同时设置正向边和反向边的相互引用。 最小费…

简单工厂模式和策略模式的异同

文章目录 简单工厂模式和策略模式的异同相同点&#xff1a;不同点&#xff1a;目的&#xff1a;结构&#xff1a; C 代码示例简单工厂模式示例&#xff08;以创建图形对象为例&#xff09;策略模式示例&#xff08;以计算价格折扣策略为例&#xff09;UML区别 简单工厂模式和策…

欢迎 PaliGemma 2 – 来自 Google 的新视觉语言模型

我们很高兴迎来 Google 全新的视觉语言模型 PaliGemma 2&#xff0c;这是 PaliGemma 的一个新版本。与其前代产品一样&#xff0c;PaliGemma 2 使用强大的SigLIP进行视觉处理&#xff0c;但在文本解码部分升级到了最新的 Gemma 2。 https://hf.co/collections/google/siglip-65…

Django基础 - 01入门简介

一、 基本概念 1.1 Django说明 Django发布于2005年&#xff0c; 网络框架&#xff0c; 用Python编写的开源的Web应用框架。采用了MVC框架模式&#xff0c;也称为MTV模式。官网&#xff1a; https://www.djangoproject.com1.2 MVC框架 Model&#xff1a; 封装和数据库相关…

华为OD --- 敏感字段加密

华为OD --- 敏感字段加密 题目独立实现思路源码实现 参考实现 题目 独立实现 思路 通过便利字符串把所有“关键字”找出来,然后将第N个关键字替换成******,最后再通过 “_” 拼接起来即可 源码实现 const rl require("readline").createInterface({ input: proce…