設計模式--命令模式的簡單例子

引入:以一個對數組的增刪改查為例。通過命令模式可以對數組進行增刪改查以及撤銷回滾。

一、基本概念

命令模式有多種分法,在本文中主要分為CommandMgr、Command、Receiver.

CommandMgr主要用于控制命令執行等操作、Command為具體的命令、Receiver為命令具體要操作的對象。

總而言之,增刪改查就是具體的Command、Receiver就是數組、CommandMgr負責控制命令的執行與回滾等。

二、程序設計

以下代碼可從github下載:GitHub - laizilianglaiziliang/LearnCommandProject

1.Receiver
//"Receiver_Array.h"
#pragma once
#include<vector>
#include<optional>
#include<iostream>
template <class T>
class Receiver_Array
{
private:std::vector<T>* myArry;
public:~Receiver_Array(){}Receiver_Array() {myArry = new std::vector<T>();}Receiver_Array(std::vector<T>* _myArry){if (_myArry){myArry = new std::vector<T>(*_myArry);}else{myArry = new std::vector<T>();}}bool add(const int pos, const T& val){if (errorCheck(pos)){return false;}myArry->insert(pos + myArry->begin(), val);return true;}bool del(const int pos){if (errorCheck(pos)){return false;}myArry->erase(pos + myArry->begin());return true;}bool modify(const int pos, const T& val){if (errorCheck(pos)){return false;}myArry->erase(pos + myArry->begin());return true;}std::optional<T> seek(const int pos){if (errorCheck(pos)){return std::nullopt;}return (*myArry)[pos];}bool errorCheck(const int pos){if (pos >= myArry->size()){printf("  Operation Failed.Array Bounds Errors.  ");return true;}return false;}void display(){for (int i = 0; i < myArry->size(); ++i){std::cout << (*myArry)[i] << "  ";}std::cout << std::endl;}
};

在本例子中Receiver_Array類是一個模板類,可支持不同類型的數組。同時實現了對數組進行增刪改查,為不同的命令類提供了基礎的功能。

2.Command
//Command.h
#pragma once
#include "Receiver_Array.h"
#include<optional>
#include <memory>
class Command
{
public:		int m_iPos;bool m_bCanRevert;
public:Command(int _pos) : m_iPos(_pos), m_bCanRevert(true){}virtual ~Command(){}virtual bool  execute() = 0;virtual void* executeOther(){return nullptr;}virtual bool  undo() = 0;virtual bool  redo() = 0;
};
template <class T>
class AddCommand:public Command
{
private:std::shared_ptr<Receiver_Array<T>> m_Receiver_Array;T m_Val;
public:AddCommand() {}AddCommand(std::shared_ptr<Receiver_Array<T>> _receiver_Array, int _pos,const T& _val) :Command( _pos), m_Receiver_Array(_receiver_Array), m_Val(_val){		}virtual ~AddCommand() {//if (m_Receiver_Array)//{//	m_Receiver_Array->destory();//	m_Receiver_Array = nullptr;//}}bool execute() override{try{if (this->m_Receiver_Array->add(this->m_iPos, m_Val)){printf("  Add Success.");return true;}printf("  Add Fail.");return false;}catch(...){printf("  Add Fail.");return false;}return true; }virtual bool undo() override{try{if (this->m_Receiver_Array->del(this->m_iPos)){printf("  Undo Success.");return true;}}catch (...){}printf("  Undo Fail.");return false;}virtual bool redo() override{if (execute()){printf("  Redo Success.");return true;}printf("  Redo Fail.");return false;}
};
template <class T>
class DelCommand :public Command
{
private:std::shared_ptr<Receiver_Array<T>>  m_Receiver_Array;T m_Val;
public:DelCommand() {}DelCommand(std::shared_ptr<Receiver_Array<T>>  _receiver_Array, int _pos) :Command(_pos), m_Receiver_Array(_receiver_Array){}virtual ~DelCommand(){//if (m_Receiver_Array)//{//	m_Receiver_Array->destory();//	m_Receiver_Array = nullptr;//}}bool execute() override{try{std::optional<T> val = m_Receiver_Array->seek(m_iPos);if (val!=std::nullopt && this->m_Receiver_Array->del(this->m_iPos)){printf("  Del Success.");m_Val = val.value();return true;}printf("  Del Fail.");return false;}catch (...){printf("  Del Fail.");return false;}return true;}virtual bool undo() override{try{if (this->m_Receiver_Array->add(this->m_iPos, m_Val)){printf("  Undo Success.");return true;}}catch (...){}printf("  Undo Fail.");return false;}virtual bool redo() override{if (execute()){printf("  Redo Success.");return true;}printf("  Redo Fail.");return false;}
};
template <class T>
class ModifyCommand :public Command
{
private:std::shared_ptr<Receiver_Array<T>>  m_Receiver_Array;T m_Val;
public:ModifyCommand() {}ModifyCommand(std::shared_ptr<Receiver_Array<T>>  _receiver_Array, int _pos,const T& _val) :Command(_pos), m_Receiver_Array(_receiver_Array), m_Val(_val){}virtual ~ModifyCommand(){//if (m_Receiver_Array)//{//	m_Receiver_Array->destory();//	m_Receiver_Array = nullptr;//}}bool execute() override{try{std::optional<T> val = this->m_Receiver_Array->seek(m_iPos);//判斷m_iPos是合法的if (val != std::nullopt && this->m_Receiver_Array->modify(this->m_iPos, m_Val)){printf("  Modify Success.");m_Val = val.has_value();//用于undo redoreturn true;}			printf("  Modify Fail.");return false;}catch (...){printf("  Modify Fail.");return false;}return true;}virtual bool undo() override{try{if (execute()){printf("  Undo Success.");return true;}}catch (...){}printf("  Undo Fail.");return false;}virtual bool redo() override{if (execute()){printf("  Redo Success.");return true;}printf("  Redo Fail.");return false;}
};
template <class T>
class SeekCommand :public Command
{
private:std::shared_ptr<Receiver_Array<T>>  m_Receiver_Array;
public:SeekCommand():m_bCanRevert(false) {}SeekCommand(std::shared_ptr<Receiver_Array<T>>  _receiver_Array, int _pos) :Command(_pos), m_Receiver_Array(_receiver_Array){m_bCanRevert = false;//, m_bCanRevert(false)}virtual ~SeekCommand(){//if (m_Receiver_Array)//{//	m_Receiver_Array->destory();//	m_Receiver_Array = nullptr;//}}bool execute() override{return false;}virtual void* executeOther() override{try{std::optional<T> val = m_Receiver_Array->seek(m_iPos);if (val == std::nullopt){printf("  Seek Fail.");return nullptr;}printf("  Seek Success.");T* ret = new T();*ret = val.value();return ret;}catch (...){}printf("  Seek Fail.");return nullptr;}virtual bool undo() override{printf("  Undo Fail.");return false;}virtual bool redo() override{printf("  Redo Fail.");return false;}
};

1)Command類是命令基類。本來也想將Command設計成模板類,但是后面想想感覺不太好,因為Command設計成模板類會影響到CommandMgr也變成模板類。如果Command類是模板類,要注意其屬性如果在派生類中要用的話要用this指針去訪問,否則會出現找不到標識符的問題。

可參考:

C++模板類中,派生類使用基類中數據或方法報“找不到標識符”_c++頭文件引用其他類提示找不到符號-CSDN博客

2)Command類中有個m_bCanRevert屬性用于判斷該命令是否可以被撤銷回滾,因為并不是所有的命令都支持撤銷回滾,比如例子中的SeekCommand。

3)Command類中有個executeOther,因為SeekCommand執行后需要返回一個值,是特殊的命令,因此executeOther用于執行特殊的命令

4)其他的Command派生類依賴于Receiver_Array類,可能會出現多個類依賴于同一個Receiver_Array類對象的情況,因此把Receiver_Array類成員變量設置為智能指針方便內存的釋放

5)其他的主要就是實現每個Command類的execute、undo、redo方法,這個直接看邏輯就能理解。

3.CommandMgr
//CommandMgr.h
#pragma once
#include <stack>
#include <memory>
class Command;
class CommandMgr
{
private:std::stack<std::shared_ptr<Command>> m_stkUndo;//undo棧std::stack<std::shared_ptr<Command>> m_stkRedo;//redo棧
public:CommandMgr();~CommandMgr();void execute(std::shared_ptr<Command> command) noexcept;void* executeOther(std::shared_ptr<Command> command)noexcept;void undo() noexcept;void redo() noexcept;
};
//CommandMgr.cpp
#include "CommandMgr.h"
#include "Command.h"
CommandMgr::CommandMgr()
{
}
CommandMgr::~CommandMgr()
{while (!m_stkRedo.empty()){m_stkRedo.pop();}while (!m_stkUndo.empty()){		m_stkUndo.pop();}
}
void CommandMgr::execute(std::shared_ptr<Command> command) noexcept
{if (command->execute()){printf("  Command Execute Success\n\n");if (command->m_bCanRevert){m_stkUndo.push(command);}}else{printf("  Command Execute Fail\n\n");}
}void* CommandMgr::executeOther(std::shared_ptr<Command> command) noexcept
{void* val = command->executeOther();if (val){printf("  Command Execute Success\n\n");if (command->m_bCanRevert){m_stkUndo.push(command);}return val;}else{printf("  Command Execute Fail\n\n");}return nullptr;
}void CommandMgr::undo() noexcept
{if (m_stkUndo.empty()){return;}std::shared_ptr<Command> command = m_stkUndo.top();if (command && command->m_bCanRevert && command->undo()){		m_stkUndo.pop();m_stkRedo.push(command);printf("  Command Undo Success\n\n");}else{printf("  Command Undo Fail\n\n");}
}void CommandMgr::redo() noexcept
{if (m_stkRedo.empty()){return;}std::shared_ptr<Command> command = m_stkRedo.top();if (command && command->m_bCanRevert && command->redo()){m_stkUndo.push(command);printf("  Command Redo Success\n\n");}else{printf("  Command Redo Fail\n\n");}
}

1)CommandMgr主要用于管理命令,用來操作具體的命令的調用控制、undo、redo控制。

2)因為Command類型對象的內存不太好管理,因此也使用了智能指針。

3)里面的undo、redo主要通過棧來實現。當命令execute過后便會添加到undo棧,接下來的undo、redo主要就是對undo棧和redo棧進行互相倒騰。

4.main函數

當做完上面的工作就能對數組進行方便的增刪改查了,還可以撤銷回退哦。

// LearnCommandProject.cpp : 此文件包含 "main" 函數。程序執行將在此處開始并結束。#include <iostream>
#include <vector>
#include "Command.h"
#include "Receiver_Array.h"
#include "CommandMgr.h"
#include <memory>
int main()
{std::vector<int> vec{ 1,2,3 };std::shared_ptr<Receiver_Array<int>> receiver_Array(new Receiver_Array<int>(&vec));std::shared_ptr<AddCommand<int>> addCommand(new AddCommand<int>(receiver_Array, 3, 4));CommandMgr commandMgr;commandMgr.execute(addCommand);commandMgr.undo();commandMgr.redo();receiver_Array->display();std::shared_ptr<SeekCommand<int>> seekCommand(new SeekCommand<int>(receiver_Array, 1));int* val= (int*)(commandMgr.executeOther(seekCommand));receiver_Array->display();delete val;val = nullptr;std::shared_ptr<DelCommand<int>> delCommand(new DelCommand(receiver_Array, 1));commandMgr.execute(delCommand);commandMgr.undo();commandMgr.redo();receiver_Array->display();std::shared_ptr<ModifyCommand<int>> modifyCommand(new ModifyCommand(receiver_Array, 2, 2));commandMgr.execute(modifyCommand);commandMgr.undo();commandMgr.redo();receiver_Array->display();printf("ok");
}

.上面的代碼可能還有設計不好的地方,歡迎批評指正。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/212631.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/212631.shtml
英文地址,請注明出處:http://en.pswp.cn/news/212631.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

逸迅科技丁紅陽:三種能力幫助企業打造GBI “護城河”

大數據產業創新服務媒體 ——聚焦數據 改變商業 近日&#xff0c;由上海市經濟和信息化委員會、上海市科學技術委員會指導&#xff0c;數據猿與上海大數據聯盟聯合主辦的“2023企業數智化轉型升級發展論壇”在上海舉行。本次論壇以“釋放數字價值驅動智能升級”為主題&#xf…

piakachu越權漏洞

水平越權 首先打開這一關&#xff0c;在右側有一些提示&#xff0c;我們可以看到 然后我們隨便輸入一組信息即可&#xff0c;可以在url中看到這樣的字段 當我們嘗試在url中直接更換另一個用戶名時可以發現&#xff0c;直接切換到了另一個用戶的身份 垂直越權 這里可以看到右邊…

QML和C++交互中,實現C++中connect到qml的信號,再從qml發射信號傳遞數據給C++的一種方式

1.需求&#xff1a; 假設我們有一個需求&#xff0c;要求在用戶點擊列表中的項目時&#xff0c;不僅在控制臺上輸出項目的名稱&#xff0c;還要在C端進行一些處理。我們希望在C端能夠接收到用戶點擊的項目名稱&#xff0c;并進行相應的處理。 2.分析&#xff1a; 在這種情況…

Android 10.0 系統framework修改低電量關機值為2%

1.前言 在10.0的系統產品開發中,在系統關于低電量關機的值,每個平臺都不同,根據實際開發底層硬件的要求看實際情況來調整這個值, 所以需要分析相關的電量變化執行的代碼流程,來實現這個功能 2.系統framework修改低電量關機值為2%的核心類 frameworks\base\services\cor…

一文學會使用 PyInstaller 將 Python 腳本打包為 .exe 可執行文件

文章目錄 前言PyInstaller特點跨平臺支持自動依賴項處理單文件發布支持圖形用戶界面&#xff08;GUI&#xff09;和命令行界面&#xff08;CLI&#xff09;應用支持多種打包選項 基本用法常用參數其它參數 版本 & 環境實現步驟安裝 PyInstaller創建 Python 腳本使用 PyInst…

Strange-Towers-of-Hanoi

title: Strange Towers of Hanoi date: 2023-12-11 03:20:05 tags: 遞推 categories: 算法進階指南 題目大意 解出 n n n 個盒子 4 4 4 座塔的漢諾塔問題最少需要多少次&#xff1f; 思路 首先考慮 n n n 個盒子 3 3 3 座塔的經典漢諾塔問題&#xff0c;設 d [ n ] d[n] …

第三十章 控制到 XML 模式的映射 - Array of Classname

文章目錄 第三十章 控制到 XML 模式的映射 - Array of ClassnameArray of Classname 第三十章 控制到 XML 模式的映射 - Array of Classname Array of Classname 本部分顯示了從啟用 XML 的類生成的XML 架構的一部分&#xff0c;此時該類包含定義為類名數組的屬性。例如&…

【SpringBoot教程】SpringBoot 創建定時任務(配合數據庫動態執行)

作者簡介&#xff1a;大家好&#xff0c;我是擼代碼的羊駝&#xff0c;前阿里巴巴架構師&#xff0c;現某互聯網公司CTO 聯系v&#xff1a;sulny_ann&#xff08;17362204968&#xff09;&#xff0c;加我進群&#xff0c;大家一起學習&#xff0c;一起進步&#xff0c;一起對抗…

transformer模型結構|李宏毅機器學習21年

來源&#xff1a;https://www.bilibili.com/video/BV1Bb4y1L7FT?p4&vd_sourcef66cebc7ed6819c67fca9b4fa3785d39 文章目錄 概述seq2seqtransformerEncoderDecoderAutoregressive&#xff08;AT&#xff09;self-attention與masked-self attentionmodel如何決定輸出的長度…

【親測有效】支持橫豎屏 微信小程序video禁止進度條拖動,微信小程序遮罩進度條,

背景&#xff1a;部分課程禁止客戶拖動視頻進度條直至播放結束 紅色是遮罩區域遮罩區域 實際遮罩效果&#xff08;有一個很淺的陰影區域&#xff09; 實現代碼 .wxml文件 <video enable-progress-gesture"false" ><cover-view class"cover">…

基于深度學習的yolov7植物病蟲害識別及防治系統

歡迎大家點贊、收藏、關注、評論啦 &#xff0c;由于篇幅有限&#xff0c;只展示了部分核心代碼。 文章目錄 一項目簡介簡介YOLOv7 系統特性工作流程 二、功能三、系統四. 總結 一項目簡介 # YOLOv7植物病蟲害識別及防治系統介紹 簡介 該系統基于深度學習技術&#xff0c;采…

Seata配置

參考教程 seata 分布式事務的環境搭建與使用 Seata 1.4.0 nacos配置和使用&#xff0c;超詳細 Seata 1.4.2 的安裝 Nacos的配置和使用 官網下載地址 本文以v1.4.1為例 1.數據庫及表的創建 創建seata數據庫&#xff0c;創建以下表&#xff08;右鍵連接-》新建數據庫seata-》…

kubeadm搭建1.20.7版本k8s

資源 服務器名稱ip地址服務master1&#xff08;2C/4G&#xff0c;cpu核心數要求大于2&#xff09;192.168.100.10docker、kubeadm、kubelet、kubectl、flannelnode01&#xff08;2C/2G&#xff09;192.168.100.30docker、kubeadm、kubelet、kubectl、flannelnode02&#xff08…

windows系統proteus中Ardunio Mega 2560和虛擬機上Ubuntu系統CuteCom進行串口通信

在文章利用proteus實現串口助手和arduino Mega 2560的串口通信-CSDN博客 中&#xff0c;實現了windows系統的proteus中Ardunio Mega 2560和SSCOM通過虛擬串口進行通信。虛擬串口的連接示意圖如下圖所示。 在文章windows系統和虛擬機上ubuntu系統通過虛擬串口進行通信-CSDN博客…

3DMAX關于顯示驅動問題的解決方法大全

3DMAX與顯卡驅動有關的問題主要有以下幾種情況&#xff1a; 1.3DMAX啟動彈出這樣的界面&#xff1a; 2.主工具欄按鈕不顯示&#xff0c;或者鼠標移上去才顯示&#xff08;刷新問題&#xff09;。 3&#xff0e;視口菜單不顯示或顯示不全。 問題分析&#xff1a; 首先&#x…

安全基礎從0開始

文章目錄 常見名詞小實戰 網站搭建小實戰抓包模擬器狀態碼返回值網站搭建WEB應用安全漏洞 數據包&封包&信息收集**參考點** 常見名詞 前后端&#xff0c;POC/EXP&#xff0c;Payload/Shellcode&#xff0c;后門/Webshell&#xff0c;木馬/病毒&#xff0c; 反彈&…

ReactNative0.73發布,架構升級與更好的調試體驗

這次更新包含了多種提升開發體驗的改進&#xff0c;包括&#xff1a; 更流暢的調試體驗: 通過 Hermes 引擎調試支持、控制臺日志歷史記錄和實驗性調試器&#xff0c;讓調試過程更加高效順暢。穩定的符號鏈接支持: 簡化您的開發工作流程&#xff0c;輕松將文件或目錄鏈接到其他…

react表單-受控

react - 表單組件 受控組件 表單項中的值&#xff08;value/checked&#xff09;受到類組件state中數據來控制&#xff0c;同時還需要綁定一個onChange事件來完成對state中數據的修改 import React, { Component } from react;class AppInput extends Component {// 設置受控組…

基于ssm應急資源管理系統論文

摘 要 現代經濟快節奏發展以及不斷完善升級的信息化技術&#xff0c;讓傳統數據信息的管理升級為軟件存儲&#xff0c;歸納&#xff0c;集中處理數據信息的管理方式。本應急資源管理系統就是在這樣的大環境下誕生&#xff0c;其可以幫助管理者在短時間內處理完畢龐大的數據信息…

排序算法之七:歸并排序(遞歸)

基本思想 基本思想&#xff1a; 歸并排序&#xff08;MERGE-SORT&#xff09;是建立在歸并操作上的一種有效的排序算法,該算法是采用分治法&#xff08;Divide and Conquer&#xff09;的一個非常典型的應用。將已有序的子序列合并&#xff0c;得到完全有序的序列&#xff1…