C++设计模式---命令模式

2023-11-03


命令模式的场景

现在需要设计这样的场景:厨师类负责做菜,比如红烧鱼、锅包肉等菜,而顾客一般不能直接命令厨师做哪些菜,而是需要写一个便签,写上需要做哪些菜,然后交给厨师来做。

#include <iostream>
#include <vector>
#include <list>
using namespace std;

namespace hjl_project1
{
    class Cook
    {
    public:
        void cook_fish()
        {
            cout<<"做一盘红烧鱼"<<endl;
        }
        void cook_meat()
        {
            cout<<"做一盘锅包肉"<<endl;
        }
        //做其他菜品,略
    };
    //厨师做的每样菜品对应的抽象类
    class Command
    {
    public:
        Command(Cook*pcook)
        {
            m_pcook=pcook;
        }
        //做父类时析构函数为虚函数
        virtual ~Command()
        {
            if(m_pcook!=nullptr)
            {
                delete m_pcook;
                m_pcook=nullptr;
            }   
        }
        //通知厨师做菜
        virtual void Execute()=0;
    protected:
    		//命令对应的厨师
        Cook*m_pcook;
    };

    //做红烧鱼菜品的命令子类
    class CommandFish:public Command
    {
    public:
        CommandFish(Cook*pcook)
            :Command(pcook)
        {}
        virtual void Execute()
        {
            m_pcook->cook_fish();
        }
    };
    //做锅包肉菜品的命令子类
    class CommandMeate:public Command
    {
    public:
        CommandMeate(Cook*pcook)
            :Command(pcook)
        {}
        virtual void Execute()
        {
            m_pcook->cook_meat();
        }
    };
};
int main()
{
    using namespace hjl_project1;
    //创建做鱼的便签,交给厨师
    Command* pcmd1=new CommandFish(new Cook());
    pcmd1->Execute();
    //创建做肉的便签,交给厨师
    Command* pcmd2=new CommandMeate(new Cook());
    pcmd2->Execute();
    //释放资源 delete ...
}

但是上面这样做有一些不方便,那就是顾客每次都要创建一个便签,然后调用Execute来通知厨师。

这时候我们引入一个服务员类,这个服务员类接收所有的便签,然后替顾客通知厨师。

#include <iostream>
#include <vector>
#include <list>
using namespace std;

namespace hjl_project1
{
    class Cook
    {
    public:
        void cook_fish()
        {
            cout<<"做一盘红烧鱼"<<endl;
        }
        void cook_meat()
        {
            cout<<"做一盘锅包肉"<<endl;
        }
        //做其他菜品,略
    };

    //初识做的每样菜品对应的抽象类
    class Command
    {
    public:
        Command(Cook*pcook)
        {
            m_pcook=pcook;
        }
        //做父类时析构函数为虚函数
        virtual ~Command()
        {
            if(m_pcook!=nullptr)
            {
                delete m_pcook;
                m_pcook=nullptr;
            }   
        }
        virtual void Execute()=0;
    protected:
        Cook*m_pcook;
    };

    //做红烧鱼菜品的命令子类
    class CommandFish:public Command
    {
    public:
        CommandFish(Cook*pcook)
            :Command(pcook)
        {}
        virtual void Execute()
        {
            m_pcook->cook_fish();
        }
    };
    //做锅包肉菜品的命令子类
    class CommandMeate:public Command
    {
    public:
        CommandMeate(Cook*pcook)
            :Command(pcook)
        {}
        virtual void Execute()
        {
            m_pcook->cook_meat();
        }
    };

    //------服务员类
    class Waiter
    {
    public:
        //顾客将便签交给服务员
        void AddCommand(Command*pcommand)
        {
           m_commlist.push_back(pcommand);
        }
        //如果顾客想撤单,则将便签从列表中删除
        void DelCommand(Command*pcommand)
        {
            m_commlist.remove(pcommand);
        }
        void Notify()
        {
            //服务员将便签交到厨师手里让厨师做菜
            for(auto iter=m_commlist.begin();iter!=m_commlist.end();++iter)
            {
                (*iter)->Execute();
            }
        }
    private:
        list<Command*>m_commlist;
    };
    //实习服务员类,每次只能通知一个command
    class Traineewaiter
    {
    public:
        Traineewaiter(Command*pcommand):m_pcommand(pcommand){}
        void Notify()
        {
            m_pcommand->Execute();
        }
        ~Traineewaiter()
        {
            if(m_pcommand!=nullptr)
            {
                delete m_pcommand;
                m_pcommand=nullptr;
            }
        }
    private:
        Command* m_pcommand;
    };
};
int main()
{
    using namespace hjl_project1;
    Command* pcmd1=new CommandFish(new Cook());
    Command* pcmd2=new CommandMeate(new Cook());
    Waiter* pwaiter1=new Waiter();
    pwaiter1->AddCommand(pcmd1);
    pwaiter1->AddCommand(pcmd2);
		//服务员一次性通知厨师
    pwaiter1->Notify();
    //释放资源 delete ...
}

在这里插入图片描述


命令模式的定义

命令模式一共有四种角色:

  1. 接收者类:上面的Cook类,他执行具体的动作,比如cook_fish等
  2. 调用者类:waiter类,他只与command类存在关联关系。
  3. Command(抽象命令类):声明了Execute用来调用接收者类的具体接口。
  4. 具体命令类:继承Command,实现了Execute方法,调用接收者的具体接口,比如cook_fish。

定义:将一个请求或者命令封装为一个对象,以便这些请求可以以对象的方式通过参数进行传递,对象化的请求还可以排队执行或者根据需要将这些请求录入日志进行查看,或者对这些请求进行撤销。

从上面的定义不难看出,命令模式执行的命令具有 异步执行、延迟执行、排队执行、撤销命令这些特点,所以它适用的场景有:

  1. 绘图软件需要进行撤销操作,因为保存了命令的list,所以可以给每个具体命令类增加一个撤销接口,需要撤销时执行即可。
  2. 任务的定期调度执行。我们可以指定调用者类的执行时间。
  3. 游戏中的时光倒流系统或者回放系统的实现。将玩家的操作以具体命令类的方式记录到命令流中,就可以回放的功能。

命令模式的特点:

  1. 调用者和接收者解耦,调用者和接收者之间可以是多对多的关系。
  2. 增加新功能的时候,对接收者类的修改是不可避免的,但是可以通过增加新的具体命令类,从而不用修改调用者。
  3. 具体的命令类可能会过多,这是命令模式的缺点。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

C++设计模式---命令模式 的相关文章

随机推荐

  • 创建蓝图函数

    如果把蓝图类当作C 类的设计图 那么函数是必不可少的 即成员函数 蓝图类中添加函数 改名 myPrint 类似于宏 这里也有输入输出参数接口 只是函数自带执行数据类型 而宏完全自定义 只打印出hello即可 在事件图表中 允许输入 按A键时
  • PCIe专题学习——2.4

    之前我们讲了对PCIe的一些基础概念做了一个宏观的介绍 了解了PCIe是一种封装分层协议 packet based layered protocol 主要包括事务层 Transaction layer 数据链路层 Data link lay
  • 循环神经网络matlab程序设计,matlab程序设计<神经网络源码>

    P 108 60 111 84 693 14 1119 66 533 38 80 01 184 58 160 32 253 28 89 18 158 68 213 48 28 59 441 63 590 93 680 20 145 23 2
  • 在IntelliJ IDEA IDE中添加jar包的步骤

    在IntelliJ IDEA IDE中添加jar包的步骤如下 打开IntelliJ IDEA 打开需要添加jar包的项目 在IntelliJ IDEA右侧的项目导航器中 找到项目 右键单击项目 选择 Open Module Settings
  • Python密码库Cryptography探究学习

    一 简介 Cryptography的目标是建立一个标准Python加密库 支持 Python 2 6 2 7 Python 3 3 and PyPy 2 6 如果对密码学领域感兴趣的话 可以学习Crypto 101 作者是 Laurens
  • 一、新建第一个工程——51、STM32、MSP432

    目录 一 51单片机 二 STM32 三 MSP432E401R 一 51单片机 步骤1 如图 双击桌面Keil5图标 打开keil5 点击 Project 点击New uvision project 步骤2 如图 找到合适的存放工程的位置
  • 活动Activity——活动之间传递信息——向上一个Activity返回数据

    处理下一个页面的应答数据 详细步骤说明如下 1 上一个页面打包好请求数据 调用startActivityForResult方法执行跳转动作 2 下一个页面接收并解析请求数据 进行相应处理 3 下一个页面在返回上一个页面时 打包应答数据并调用
  • 安装mongoDB出现服务启动失败--服务没有响应控制功能--Status:Service ‘MongoDB Server (MongoDB)‘ (MongoDB) failed tostart.

    下载了4 4 20版本的MongoDB mongodb windows x86 64 4 4 20 signed msi 在安装完成后 参考 61条消息 window 下安装 mongodb 详细步骤 window安装mongodb 极客飞
  • 2022.05面试总结

    前言 今年四月份正在办公室高高兴兴的写bug 突然就被通知毕业了 传说中的天选打工人 于是开始了五月份找工作的苦逼生活 总体上来说市场比较冷淡 前后面试了20多家 只拿到了4个offer 整体涨幅在30 左右 话说回来自从2020年之后 疫
  • Verilog的结构化、数据流、行为级描述方式

    Verilog的结构化 数据流 行为级描述方式 概述 verilog通常可以使用三种不同的方式描述模块实现的逻辑功能 结构化 数据流 行为描述方式 结构化描述方式 是使用实例化低层次模块的方法 即调用其他已经定义过的低层次模块对整个电路的功
  • 为什么采用PID算法?增量式PID定位方式参数如何整定?

    PID控制能满足相当多的工业对象的控制要求 尤其适用于可建立精确模型的确定性控制系统 由于其算法简单 鲁棒性强和可靠性高适合多数控制系统中 可以结合采用自适应 模糊 滑模 神经网络等智能控制以增强控制性能和适应环境的能力 首先从理论原则出发
  • MFC 如何改变对话框的默认背景颜色

    下面介绍三种方法 实现改变对话框的默认背景颜色 1 可以在CLotteryApp InitInstance 设置更新对话框的背景颜色 调用SetDialogBkColor RGB 160 32 240 即可以改变背景颜色 注意这里绘制的颜色
  • chrome 控制台 base64加密解密

    1 视界 2 背景 因为在客户机器 要查询base64的解密信息 但是因为内网无法使用网络 只能拷贝软件本想查询插件 后来发现谷歌支持解密 3 方法 在chrome控制台上可以直接使用函数做base64加密解密 用法 加密 btoa ord
  • plt.pie()参数解释

    label 设置各部分标签 explode 设置某一块离开中心距离 autopct 设置圆里面的文本 shadow 设置是否有阴影 labeldistance 设置标签文本距圆心位置 数字表示多少倍半径 startangle 起始角度 默认
  • 性能小课堂:Jmeter录制手机app脚本

    环境准备 1 手机 2 wifi 3 Jmeter 具体步骤 1 启动Jmeter 2 测试计划 中添加 线程组 3 工作台 中添加 HTTP代理服务器 4 配置代理服务器 Global Settings下面的端口配置 9988 HTTPS
  • 抖音企业号无需API开发连接AI图像生成,打造AI智能绘图助手

    1 抖音用户使用场景 作为抖音企业号的运营人员 我们一直在寻找新的方式来增强我们与用户之间的互动 最近 我们发现了AI绘图技术可以根据用户需求和指令自动创建图片 无需人为干预 这为我们节省了人力和时间 因此 我们考虑将AI绘图模型接入到抖音
  • Waves 14 Complete对Mac和Windows系统的最低要求

    Waves 14 Complete是一款功能齐全的音频编辑软件 适用于音乐制作 音频工程和声音设计等领域 它提供了一系列强大的工具和效果 帮助用户在音频处理过程中实现专业水平的效果和混音 Waves 14 Complete包含了多个实用的插
  • Qt窗体边框阴影的绘制

    setWindowFlags Qt FramelessWindowHint Qt WindowSystemMenuHint setAttribute Qt WA TranslucentBackground setMouseTracking
  • Python与Xpath--二手房房价数据爬取

    一 写在开头 本文在 城市感知计算 代码的基础上进行了修改和调整以更符合自己的需求和习惯 在此感谢作者的分享 其次我想说的是如果有同志看见了我的文章并且想要尝试实现的话 希望能 合理 温柔 地爬取数据 给网站减少访问压力 他好我也好 最好是
  • C++设计模式---命令模式

    文章目录 命令模式的场景 命令模式的定义 命令模式的场景 现在需要设计这样的场景 厨师类负责做菜 比如红烧鱼 锅包肉等菜 而顾客一般不能直接命令厨师做哪些菜 而是需要写一个便签 写上需要做哪些菜 然后交给厨师来做 include