設計模式:命令模式 Command

目錄

  • 前言
  • 問題
  • 解決方案
  • 結構
  • 代碼


前言

命令是一種行為設計模式,它可將請求轉換為一個包含與請求相關的所有信息的獨立對象。該轉換讓你能根據不同的請求將方法參數化、延遲請求執行或將其放入隊列中,且能實現可撤銷操作。


問題

假如你正在開發一款新的文字編輯器, 當前的任務是創建一個包含多個按鈕的工具欄, 并讓每個按鈕對應編輯器的不同操作。 你創建了一個非常簡潔的 按鈕 類, 它不僅可用于生成工具欄上的按鈕,還可用于生成各種對話框的通用按鈕。
在這里插入圖片描述
盡管所有按鈕看上去都很相似, 但它們可以完成不同的操作(打開、保存、打印和應用等)。你會在哪里放置這些按鈕的點擊處理代碼呢? 最簡單的解決方案是在使用按鈕的每個地方都創建大量的子類。 這些子類中包含按鈕點擊后必須執行的代碼。
在這里插入圖片描述
你很快就意識到這種方式有嚴重缺陷。 首先, 你創建了大量的子類, 當每次修改基類 按鈕 時, 你都有可能需要修改所有子類的代碼。 簡單來說, GUI 代碼以一種拙劣的方式依賴于業務邏輯中的不穩定代碼。
在這里插入圖片描述
還有一個部分最難辦。復制/粘貼文字等操作可能會在多個地方被調用。例如用戶可以點擊工具欄上小小的“復制”按鈕,或者通過上下文菜單復制一些內容, 又或者直接使用鍵盤上的 Ctrl+C 。

我們的程序最初只有工具欄, 因此可以使用按鈕子類來實現各種不同操作。 換句話來說, 復制按鈕 CopyButton 子類包含復制文字的代碼是可行的。 在實現了上下文菜單、 快捷方式和其他功能后, 你要么需要將操作代碼復制進許多個類中,要么需要讓菜單依賴于按鈕,而后者是更糟糕的選擇。

解決方案

優秀的軟件設計通常會將關注點進行分離, 而這往往會導致軟件的分層。最常見的例子:一層負責用戶圖像界面;另一層負責業務邏輯。 GUI 層負責在屏幕上渲染美觀的圖形, 捕獲所有輸入并顯示用戶和程序工作的結果。 當需要完成一些重要內容時(比如計算月球軌道或撰寫年度報告,GUI 層則會將工作委派給業務邏輯底層。

這在代碼中看上去就像這樣: 一個 GUI 對象傳遞一些參數來調用一個業務邏輯對象。 這個過程通常被描述為一個對象發送請求給另一個對象。
在這里插入圖片描述
命令模式建議 GUI 對象不直接提交這些請求。 你應該將請求的所有細節(例如調用的對象、 方法名稱和參數列表)抽取出來組成命令類,該類中僅包含一個用于觸發請求的方法。

命令對象負責連接不同的 GUI 和業務邏輯對象。 此后, GUI對象無需了解業務邏輯對象是否獲得了請求, 也無需了解其對請求進行處理的方式。 GUI 對象觸發命令即可, 命令對象會自行處理所有細節工作。
在這里插入圖片描述
下一步是讓所有命令實現相同的接口。 該接口通常只有一個沒有任何參數的執行方法, 讓你能在不和具體命令類耦合的情況下使用同一請求發送者執行不同命令。 此外還有額外的好處, 現在你能在運行時切換連接至發送者的命令對象, 以此改變發送者的行為。

你可能會注意到遺漏的一塊拼圖——請求的參數。 GUI 對象可以給業務層對象提供一些參數。 但執行命令方法沒有任何參數,所以我們如何將請求的詳情發送給接收者呢?答案是:使用數據對命令進行預先配置,或者讓其能夠自行獲取數據。
在這里插入圖片描述
讓我們回到文本編輯器。 應用命令模式后, 我們不再需要任何按鈕子類來實現點擊行為。 我們只需在 按鈕 Button 基類中添加一個成員變量來存儲對于命令對象的引用, 并在點擊后執行該命令即可。

你需要為每個可能的操作實現一系列命令類, 并且根據按鈕所需行為將命令和按鈕連接起來。

其他菜單、 快捷方式或整個對話框等 GUI 元素都可以通過相同方式來實現。當用戶與 GUI 元素交互時,與其連接的命令將會被執行。 現在你很可能已經猜到了, 與相同操作相關的元素將會被連接到相同的命令,從而避免了重復代碼。

最后,命令成為了減少 GUI 和業務邏輯層之間耦合的中間層。而這僅僅是命令模式所提供的一小部分好處!

結構

在這里插入圖片描述

代碼

#include <iostream>
#include <string>
#include <list>
#include <memory>
using namespace std;class Receiver{
public:void operation1(const string& params){cout<<"開始用"<<params<<"執行操作1"<<endl;}void operation2(const string& params){cout<<"開始用"<<params<<"執行操作2"<<endl;}
};class Command{
public:virtual void execute()=0;
};
class ConcreteCommand1:public Command{
public:ConcreteCommand1(shared_ptr<Receiver> receiver, const string& parameter):m_receiver(receiver),m_params(parameter){}void execute() override{m_receiver->operation1(m_params);}
private:shared_ptr<Receiver> m_receiver;string m_params;
};
class ConcreteCommand2:public Command{
public:ConcreteCommand2(shared_ptr<Receiver> receiver, const string& parameter):m_receiver(receiver),m_params(parameter){}void execute() override{m_receiver->operation2(m_params);}
private:shared_ptr<Receiver> m_receiver;string m_params;
};class Invoker{
public:void setCommand(shared_ptr<Command> command){m_commmandList.push_back(command);}void executeCommand(){for(auto& command:m_commmandList){command->execute();}}
private:list<shared_ptr<Command>> m_commmandList;
};int main(){auto receiver=make_shared<Receiver>();auto command1=make_shared<ConcreteCommand1>(receiver,"按鈕1");auto command2=make_shared<ConcreteCommand2>(receiver,"按鈕2");auto invoker=make_shared<Invoker>();invoker->setCommand(command1);invoker->executeCommand();cout<<"------------------"<<endl;invoker->setCommand(command2);invoker->executeCommand();cout<<"------------------"<<endl;return 0;
}

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

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

相關文章

4-verilog簡單狀態機

verilog簡單狀態機 1. always (posedge clk or negedge rst_n) beginif (!rst_n)cnt_1ms < 20b0;else if (cnt_1ms_en)cnt_1ms < cnt_1ms 1b1;elsecnt_1ms < 20d0; endalways (posedge clk or negedge rst_n) beginif(!rst_n)cur_state < s1_power_init;else i…

ICCV2025 | 對抗樣本智能安全方向論文匯總 | 持續更新中~

匯總結果來源&#xff1a;ICCV 2025 Accepted Papers 若文中出現的 論文鏈接 和 GitHub鏈接 點不開&#xff0c;則說明還未公布&#xff0c;在公布后筆者會及時添加. 若筆者未及時添加&#xff0c;歡迎讀者告知. 文章根據題目關鍵詞搜索&#xff0c;可能會有遺漏. 若筆者出現…

SPI通信中CS片選的兩種實現方案:硬件片選與軟件片選

一. 簡介本文簡單熟悉一下SPI通信中的片選信號&#xff08;CS&#xff09;的兩種實現方案&#xff1a;硬件片選和軟件片選&#xff0c;以及兩種方案的區別&#xff0c;如何選擇。在SPI&#xff08;Serial Peripheral Interface&#xff09;通信中&#xff0c;片選信號&#xff…

IBM 報告稱除美國外,全球數據泄露成本下降

IBM 發布的一份針對 113,620 起數據泄露事件的年度全球分析報告發現&#xff0c;平均數據泄露成本同比下降了 9%&#xff0c;這主要歸功于更快的發現和遏制速度。 該報告與波耐蒙研究所 (Ponemon Institute) 合作完成&#xff0c;發現全球平均數據泄露成本從 2024 年的 488 萬美…

Docker Compose 部署 Dify + Ollama 全棧指南:從裸奔到安全可觀測的 AI 應用實戰

&#x1f4cc; 摘要 本文以中國開發者視角出發&#xff0c;手把手教你用 Docker Compose 在本地或輕量云主機上部署 Dify Ollama 組合棧&#xff0c;實現“安全、可觀測、可擴展”的私有化 AI 應用平臺。全文約 8 000 字&#xff0c;包含&#xff1a; 架構圖、流程圖、甘特圖…

「源力覺醒 創作者計劃」_全方面實測文心ERNIE-4.5-VL-28B-A3B開源大模型

「源力覺醒 創作者計劃」_全方面實測文心ERNIE-4.5-VL-28B-A3B開源大模型1. 文心大模型4.5-28B概述2. 部署ERNIE-4.5-VL-28B-A3B文心大模型2.1. 創建GPU云主機2.2. ERNIE-4.5-VL-28B-A3B部署2.3. 創建大模型API交互接口3. 文心大模型4.5-28B多方面性能評測3.1. 語言理解方面3.2…

數據庫學習------數據庫事務的特性

在數據庫操作中&#xff0c;事務是保證數據一致性和完整性的核心機制。無論是簡單的單表更新&#xff0c;還是復雜的多表關聯操作&#xff0c;事務都扮演著至關重要的角色。那么什么是數據庫事務&#xff1f;數據庫事務是一個不可分割的操作序列&#xff0c;它包含一個或多個數…

18-C語言:第19天筆記

C語言&#xff1a;第19天筆記 內容提要 構造類型 結構體共用體/聯合體構造類型 數據類型 基本類型/基礎類型/簡單類型 整型 短整型&#xff1a;short – 2字節基本整型&#xff1a;int – 4字節長整型&#xff1a;long – 32位系統4字節/ 64位系統8字節長長整型&…

centos下安裝anaconda

下載 anaconda 安裝包 wget https://repo.anaconda.com/archive/Anaconda3-2022.05-Linux-x86_64.sh 2. 授權 chmod x Anaconda3-2022.05-Linux-x86_64.sh 3. 安裝 ./Anaconda3-2022.05-Linux-x86_64.sh 此時顯示Anaconda的信息&#xff0c;并且會出現More&#xff0c;繼續…

MySQL(172)如何進行MySQL的全局變量設置?

MySQL的全局變量是影響整個服務器設置和行為的參數。可以在服務器啟動時通過配置文件設置這些變量&#xff0c;也可以在服務器運行時通過SQL命令動態調整。以下是關于如何設置和管理MySQL全局變量的詳細說明和示例代碼。 一、通過配置文件設置全局變量 在MySQL服務器啟動時&…

【最后203篇系列】030 強化學習探索

前言 我發現在csdn寫完一篇文章越來越難了&#xff0c;有n篇寫了一半沒往下寫。原來我覺得補完203篇&#xff0c;湊到一千篇是個很簡單的事&#xff0c;沒想到還挺難的。 我回想了一下&#xff0c;過去一年大模型領域繼續發生這很劇烈的變化&#xff0c;這是一種新的模式 &…

fastGEO v1.7.0 大更新,支持PCA、差異分析、火山圖、熱圖、差異箱線圖、去批次等分析

前言 之前一篇文章【fastGEO V1.6.1 這個版本強的可怕&#xff0c;GEO數據自動下載、探針注釋、Shiny App】介紹了fastGEO用于GEO數據下載和探針注釋的核心功能。 雖然是付費50獲取安裝包&#xff08;剛開始是20&#xff09;&#xff0c;但也深受歡迎&#xff0c;說明這個R包…

LLM 典型模型技術特性及項目落地全流程實踐

在大語言模型(LLM)技術快速迭代的當下,開發者面臨的核心挑戰已從 “是否使用” 轉變為 “如何正確選型并高效落地”。本文將系統剖析當前主流 LLM 的技術特性,結合實際項目架構,提供從模型選型、接口集成到性能優化的全流程技術方案,并附關鍵代碼實現,為工業級 LLM 應用…

機器學習消融實驗:方法論演進、跨領域應用與前沿趨勢

一、定義與起源 消融實驗&#xff08;Ablation Study&#xff09;是一種系統性移除或修改模型關鍵組件以評估其對整體性能貢獻的實驗方法論。其術語源于神經科學和實驗心理學&#xff08;20世紀60-70年代&#xff09;&#xff0c;指通過切除動物腦區研究行為變化的實驗范式。2…

北京-4年功能測試2年空窗-報培訓班學測開-今天來聊聊我的痛苦

最近狀態很不對勁&#xff0c;因為我很少花時間好好思考&#xff0c;只是處于執行狀態&#xff0c;甚至也不太寫筆記了&#xff0c;我原以為這樣會更高效&#xff0c;現在想想&#xff0c;開始不愿花時間深思才是斷弦的開始吧而且從結課后我有了隱瞞&#xff0c;我不想過多透露…

深度解析 | AI 幻覺的形成和應對路徑

寫這一篇的緣由一是因為我也在摸索如何降低 AI 幻覺提升 AI 工具使用效率&#xff0c;二是因為前兩周在MIT學習時老師講的一節課&#xff0c;剛好也解釋了這個問題&#xff0c;所以一并做個總結&#xff0c;分享給大家。 近幾年&#xff0c;大型語言模型&#xff08;LLM&#…

Java把word轉HTML格式

Java把word轉HTML格式&#xff0c;兩種方式方式一&#xff1a;maven引入依賴,pom.xml<dependency><groupId>e-iceblue</groupId><artifactId>spire.office.free</artifactId><version>5.3.1</version> </dependency>然后代碼讀…

#C語言——學習攻略:探索字符函數和字符串函數(一)--字符分類函數,字符轉換函數,strlen,strcpy,strcat函數的使用和模擬實現

&#x1f31f;菜鳥主頁&#xff1a;晨非辰的主頁 &#x1f440;學習專欄&#xff1a;《C語言學習》 &#x1f4aa;學習階段&#xff1a;C語言方向初學者 ?名言欣賞&#xff1a;"編程的本質是理解問題&#xff0c;然后把它分解成可執行的步驟。" 目錄 1. 字符分類函…

(吃飯)質數時間

題目描述如果把一年之中的某個時間寫作 a 月 b 日 c 時 d 分 e 秒的形式&#xff0c;當這五個數都為質數時&#xff0c;我們把這樣的時間叫做質數時間&#xff0c;現已知起始時刻是 2022 年的 a 月 b 日 c 時 d 分 e 秒&#xff0c;終止時刻是 2022 年的 u 月 v 日 w 時 x 分 y…

【RK3568 RTC 驅動開發詳解】

RK3568 RTC 驅動開發詳解一、Linux RTC 子系統架構?二、設備樹配置?三、驅動四、時間相關命令實時時鐘&#xff08;RTC&#xff09;是嵌入式系統中不可或缺的硬件模塊&#xff0c;負責在系統斷電后繼續計時&#xff0c;為設備提供穩定的時間基準。本文將以瑞芯微 RK3568 平臺…