【設計模式】命令模式 (動作(Action)模式或事務(Transaction)模式)宏命令

命令模式(Command Pattern)詳解


一、命令模式簡介

命令模式(Command Pattern) 是一種 行為型設計模式(對象行為型模式),它將一個請求封裝為一個對象,從而使你可以用不同的請求對客戶進行參數化,并支持請求的排隊、記錄日志、撤銷等操作。

別名動作(Action)模式或事務(Transaction)模式

簡單來說:

“把一次方法調用包裝成一個對象,這樣你就可以像處理普通對象一樣來處理這些請求。”

將請求發送者和接收者完全解耦
發送者與接收者之間沒有直接引用關系
發送請求的對象只需要知道如何發送請求,而不必知道如何完成請求

在這里插入圖片描述
相同的開關可以通過不同的電線來控制不同的電器
開關 <- -> 請求發送者
電燈<- -> 請求的最終接收者和處理者
開關和電燈之間并不存在直接耦合關系,它們通過電線連接在一起,使用不同的電線可以連接不同的請求接收者
在這里插入圖片描述

命令模式包含以下4個角色
Command(抽象命令類)
ConcreteCommand(具體命令類)
Invoker(調用者)
Receiver(接收者)

在這里插入圖片描述
命令模式的本質是對請求進行封裝。

一個請求對應于一個命令,將發出命令的責任和執行命令的責任分開。

命令模式允許請求的一方和接收的一方獨立開來,使得請求的一方不必知道接收請求的一方的接口,更不必知道請求如何被接收、操作是否被執行、何時被執行,以及是怎么被執行的。


二、解決的問題類型

命令模式主要用于解決以下問題:

  • 解耦請求發送者和接收者:發送者不需要知道具體執行邏輯,只需要知道如何發送“命令”。
  • 支持撤銷/重做功能:通過保存命令歷史,可以輕松實現撤銷或重做操作。
  • 支持事務回滾、日志記錄、隊列任務等功能:命令可以被記錄、排隊、延遲執行。(在不同的時間指定請求、將請求排隊和執行請求)
  • 系統需要將一組操作組合在一起形成宏命令

三、使用場景

場景示例
支持撤銷操作文本編輯器中的“撤銷”、“重做”按鈕
解耦調用方與執行方遙控器控制多個家電設備
實現宏命令執行一組命令的組合操作
任務隊列將多個命令加入隊列異步執行
日志與恢復記錄命令執行日志,系統崩潰后可恢復

四、核心角色

角色描述
Command(命令接口)定義執行命令的方法,如 execute()
ConcreteCommand(具體命令)實現 Command 接口,綁定具體的接收者(Receiver)并調用其方法
Invoker(調用者)持有命令對象,負責調用命令的 execute() 方法
Receiver(接收者)實際執行命令的對象,包含業務邏輯
Client(客戶端)創建命令對象并設置接收者,將命令交給調用者執行

五、代碼案例(Java)

我們以“智能遙控器控制家電”為例來演示命令模式的使用。

1. 定義命令接口

// 命令接口
interface Command {void execute();void undo(); // 可選:用于撤銷操作
}

2. 創建接收者類(實際執行動作的對象)

// 燈的接收者
class Light {public void on() {System.out.println("The light is ON");}public void off() {System.out.println("The light is OFF");}
}// 風扇的接收者
class Fan {public void start() {System.out.println("The fan is STARTING");}public void stop() {System.out.println("The fan is STOPPING");}
}

3. 創建具體命令類

// 開燈命令
class LightOnCommand implements Command {private Light light;public LightOnCommand(Light light) {this.light = light;}@Overridepublic void execute() {light.on();}@Overridepublic void undo() {light.off();}
}// 關風扇命令
class FanOffCommand implements Command {private Fan fan;public FanOffCommand(Fan fan) {this.fan = fan;}@Overridepublic void execute() {fan.stop();}@Overridepublic void undo() {fan.start();}
}

4. 創建調用者(比如遙控器)

// 遙控器
class RemoteControl {private Command command;public void setCommand(Command command) {this.command = command;}public void pressButton() {command.execute();}public void pressUndo() {command.undo();}
}

5. 客戶端測試代碼

public class Client {public static void main(String[] args) {// 創建接收者Light light = new Light();Fan fan = new Fan();// 創建具體命令Command lightOn = new LightOnCommand(light);Command fanOff = new FanOffCommand(fan);// 創建調用者RemoteControl remote = new RemoteControl();// 設置命令并執行remote.setCommand(lightOn);remote.pressButton();   // 輸出:The light is ONremote.pressUndo();     // 輸出:The light is OFFSystem.out.println("----------");remote.setCommand(fanOff);remote.pressButton();   // 輸出:The fan is STOPPINGremote.pressUndo();     // 輸出:The fan is STARTING}
}
典型代碼(C++)

典型的抽象命令類代碼

abstract class Command
{public abstract void Execute();
}

典型的調用者(請求發送者)類代碼

class Invoker
{private Command command;//構造注入public Invoker(Command command){this.command=command;}	public Command Command{get { return command; }//設值注入set { command = value; } 
}	//業務方法,用于調用命令類的方法public void Call(){command.Execute();}
}

典型的具體命令類代碼

class ConcreteCommand : Command
{private Receiver receiver; //維持一個對請求接收者對象的引用public override void Execute(){receiver.Action();//調用請求接收者的業務處理方法Action()}
}

典型的請求接收者類代碼

class Receiver
{public void Action(){//具體操作}
}
其他案例(C++)
  1. 為了用戶使用方便,某系統提供了一系列功能鍵,用戶可以自定義功能鍵的功能,例如功能鍵FunctionButton可以用于退出系統(由SystemExitClass類來實現),也可以用于顯示幫助文檔(由DisplayHelpClass類來實現)。
    用戶可以通過修改配置文件來改變功能鍵的用途,現使用命令模式來設計該系統,使得功能鍵類與功能類之間解耦,可為同一個功能鍵設置不同的功能。

在這里插入圖片描述

  1. 電視機遙控器
    電視機是請求的接收者,遙控器是請求的發送者,遙控器上有一些按鈕,不同的按鈕對應電視機的不同操作。抽象命令角色由一個命令接口來扮演,有三個具體的命令類實現了抽象命令接口,這三個具體命令類分別代表三種操作:打開電視機、關閉電視機和切換頻道。顯然,電視機遙控器就是一個典型的命令模式應用實例。
    在這里插入圖片描述

六、優缺點分析

優點描述
? 解耦調用者與接收者調用者無需了解具體執行細節,只需調用命令即可
? 支持撤銷/重做、宏命令、日志記錄等高級功能通過命令對象可以輕松實現這些功能,可以比較容易地設計一個命令隊列或宏命令(組合命令)為請求的撤銷(Undo)和恢復(Redo)操作提供了一種設計和實現方案
? 擴展性好新增命令只需添加新的 ConcreteCommand 類,符合開閉原則
缺點描述
? 增加類的數量每個命令都需要一個類,可能造成類爆炸
? 理解成本高對于新手來說,結構略復雜,需要一定學習成本
? 性能開銷如果頻繁創建命令對象,可能帶來額外內存消耗

七、與其他模式對比(補充)

模式名稱目標
策略模式封裝算法,讓算法可替換,強調“行為切換”
觀察者模式當對象狀態改變時通知所有監聽者
命令模式將請求封裝成對象,便于傳遞、存儲、撤銷等操作

八、最終小結

命令模式是一種非常靈活且強大的行為型設計模式,它適用于:

  • 需要解耦請求發送者和接收者的場景;
  • 需要支持撤銷、重做、日志記錄等高級功能;
  • 需要構建任務隊列、宏命令、批處理機制等系統功能。

📌 一句話總結:

命令模式就像“遙控器”,你按下按鈕,背后誰在干活你不知道,但你知道事情能辦成。


? 推薦使用方式:

  • 在需要撤銷/重做的系統中優先考慮命令模式;
  • 結合“命令歷史”實現多級撤銷;
  • 使用“宏命令”批量執行多個命令;
  • 用 JSON 序列化保存命令狀態,實現持久化。

九、擴展

實現命令隊列

動機

  1. 當一個請求發送者發送一個請求時,有不止一個請求接收者產生響應,這些請求接收者將逐個執行業務方法,完成對請求的處理。
  2. 增加一個CommandQueue類,由該類負責存儲多個命令對象,而不同的命令對象可以對應不同的請求接收者。
  3. 批處理。

實現

using System.Collections.Generic;
namespace CommandSample
{class CommandQueue{//定義一個List來存儲命令隊列private List<Command> commands = new List<Command>();public void AddCommand(Command command){commands.Add(command);}public void RemoveCommand(Command command){commands.Remove(command);}//循環調用每一個命令對象的Execute()方法public void Execute() {foreach (object command in commands) {((Command)command).Execute();}}}
}

記錄請求日志

動機
將請求的歷史記錄保存下來,通常以日志文件(Log File)的形式永久存儲在計算機中

  1. 為系統提供一種恢復機制
  2. 可以用于實現批處理
  3. 防止因為斷電或者系統重啟等原因造成請求丟失,而且可以避免重新發送全部請求時造成某些命令的重復執行

實現
將發送請求的命令對象通過序列化寫到日志文件中
命令類必須使用屬性[Serializable]標記為可序列化
在這里插入圖片描述

實現撤銷操作

實例
可以通過對命令類進行修改使得系統支持撤銷(Undo)操作和恢復(Redo)操作。
設計一個簡易計算器,該計算器可以實現簡單的數學運算,還可以對運算實施撤銷操作。

在這里插入圖片描述

宏命令

動機

  1. 宏命令(Macro Command)又稱為組合命令(Composite Command),它是組合模式和命令模式聯用的產物
  2. 宏命令是一個具體命令類,它擁有一個集合,在該集合中包含了對其他命令對象的引用
  3. 當調用宏命令的Execute()方法時,將遞歸調用它所包含的每個成員命令的Execute()方法。一個宏命令的成員可以是簡單命令,還可以繼續是宏命令
  4. 執行一個宏命令將觸發多個具體命令的執行,從而實現對命令的批處理

在這里插入圖片描述

部分內容由AI大模型生成,注意識別!

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

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

相關文章

HTML5智能排班日歷:動態排班一目了然

這個日歷將具備以下功能: 顯示一個標準的月度日歷視圖。可以自由切換上一個月和下一個月。在日歷的每一天自動顯示當天值班的人員。您可以很方便地在文件中修改值班人員列表和排班的起始日期。包括:動態生成日歷網格處理月份切換根據排班規則計算并顯示每天的值班人員<!DO…

深度剖析C++生態系統:一門老牌語言如何在開源浪潮中煥發新生?

&#x1f4dd;個人主頁&#x1f339;&#xff1a;慌ZHANG-CSDN博客 &#x1f339;&#x1f339;期待您的關注 &#x1f339;&#x1f339; 一、前言&#xff1a;C的“長壽秘訣”是什么&#xff1f; C 誕生已超過 40 年。它經歷了桌面應用、互聯網爆發、移動時代&#xff0c;再…

60個功能OfficeBox 萬彩辦公大師:PDF 格式轉換 OCR識別免費無廣告

各位辦公小能手們&#xff01;今天給大家介紹個超厲害的免費辦公工具套裝——OfficeBox萬彩辦公大師&#xff0c;是廣州萬彩科技整出來的。軟件下載地址安裝包 它里面有60多個沒廣告的綠色組件&#xff0c;簡直像個百寶箱&#xff01;涵蓋了PDF處理、格式轉換、OCR識別、屏幕錄…

擁抱主權AI:OpenCSG驅動智能體運營,共筑新加坡智能高地

2025年7月11日&#xff0c;由Linux基金會AI & Data、TikTok及LF Edge聯合主辦的 【LF AI & Data Day Singapore 2025】 在新加坡TikTok總部盛大啟幕。本次大會以“Agent for SWE”為核心議題&#xff0c;匯聚全球頂尖AI開發者、企業領袖及開源社區先鋒。作為國家主權AI…

單片機學習筆記.根據芯片數據手冊寫驅動程序(這里使用的是普中開發版,以DS1302為例)

硬件原理圖部分&#xff1a; VCC2:是主電源 VCC1&#xff1a;是備用電源&#xff0c;此處沒有使用VCC1 查芯片數據手冊的網站&#xff1a; ALLDATASHEETCN.COM - 電子元件和半導體及其他半導體的數據表搜索網站。https://www.alldatasheetcn.com/ 1.由原理圖可知對應引腳&…

Capture One24下載與保姆級安裝教程!

軟件下載 軟件名稱&#xff1a;Capture One24 軟件語言&#xff1a;簡體中文 軟件大小&#xff1a;1.06G 系統要求&#xff1a;Windows7或更高&#xff0c;32/64位操作系統 硬件要求&#xff1a;CPU2.5GHz&#xff0c;RAM4G或更高 下載通道丨下載&#xff1a;https://too…

微信小程序(數據庫)

const dbwx.cloud.database()//連接數據庫db.collection("test").doc("b69f67c0626fac9000e123fc1ff07a42&#xff08;為要查詢數據的id&#xff09;").get({success:res>{console.log(res)}})或getData(){db.collection("test").doc("&…

Apache CXF 漏洞曝光:存在拒絕服務與數據泄露雙重風險

Apache軟件基金會近日披露了一個影響多個Apache CXF版本的安全漏洞&#xff08;CVE-2025-48795&#xff09;。Apache CXF是開發者廣泛使用的開源Web服務框架&#xff0c;用于構建基于SOAP和REST的應用程序。漏洞雙重威脅該漏洞具有雙重危害性&#xff1a;一方面可能通過內存耗盡…

Android 應用自動更新:從理論到實戰的硬核指南

目錄 1. 自動更新的核心邏輯:為什么它對用戶體驗至關重要? 自動更新的本質 為什么它如此重要? 2. 版本檢測:如何優雅地發現“新大陸”? 設計版本檢測的邏輯 實現版本檢測的 API 請求 用戶體驗優化 3. 下載新版本:穩妥地獲取安裝包 下載的兩種方式 注意事項 用戶…

每日面試題05:ArrayList和LinkedList的底層原理

ArrayList與LinkedList深度解析&#xff1a;從底層原理到實戰選擇在Java的List接口實現中&#xff0c;ArrayList和LinkedList是最常用的兩種選擇。面試中“它們的區別”幾乎是必問題&#xff0c;但僅僅停留在“數組vs鏈表”的層面顯然不夠。本文將從??底層數據結構、內存布局…

python的慈善捐贈平臺管理信息系統

前端開發框架:vue.js 數據庫 mysql 版本不限 后端語言框架支持&#xff1a; 1 java(SSM/springboot)-idea/eclipse 2.NodejsVue.js -vscode 3.python(flask/django)–pycharm/vscode 4.php(thinkphp/laravel)-hbuilderx 數據庫工具&#xff1a;Navicat/SQLyog等都可以 摘要 本文…

三十二、【核心功能改造】數據驅動:重構儀表盤與關鍵指標可視化

三十二、【核心功能改造】數據驅動:重構儀表盤與關鍵指標可視化 前言準備工作第一部分:后端實現 - 統計 API1. 創建 `DashboardStatsView`2. 注冊統計 API 路由3. 后端初步測試第二部分:前端實現 - 重構儀表盤頁面1. 創建 `api/dashboard.ts` API 服務2. 重構 `HomeView.vue…

神經網絡與深度學習Python入門

一、神經網絡基礎 1. 神經元模型 在神經網絡中&#xff0c;最基本的單元是神經元&#xff08;Neuron&#xff09;&#xff0c;也稱為節點或單元。它模擬了生物神經系統中的神經元行為。一個典型的神經元模型包含多個輸入&#xff08;x1,x2,…,xnx_1, x_2, \ldots, x_nx1?,x2?…

Android System WebView:Android生態的核心組件

在Android生態系統中&#xff0c;Android System WebView&#xff08;簡稱WebView&#xff09;扮演著至關重要的角色。它是Chrome瀏覽器的內核&#xff0c;為Android設備提供了強大的網頁瀏覽和Web內容展示功能。無論是日常瀏覽網頁、使用基于Web的應用程序&#xff0c;還是進行…

Element Plus和Ant Design Vue深度對比分析與選型指南

在 Vue3生態中&#xff0c;Element Plus和Ant Design Vue&#xff08;以下簡稱 AntD Vue&#xff09;是兩款最主流的 UI 組件庫。它們分別脫胎于 Element UI&#xff08;Vue 2 版本&#xff09;和 Ant Design&#xff08;React 生態&#xff09;&#xff0c;經過多年迭代已成為…

AJAX 開發中的注意點

關鍵詞&#xff1a;AJAX、異步請求、前端開發、跨域、錯誤處理、安全、性能優化 ? 引言 在現代 Web 應用中&#xff0c;AJAX 是實現前后端數據交互的重要手段。然而&#xff0c;在實際開發過程中&#xff0c;如果不注意一些常見問題&#xff0c;可能會導致應用出現安全性漏洞…

類之間的縱向關系——繼承

繼承定義&#xff1a;被繼承的類叫做基類&#xff08;父類&#xff09;&#xff0c;繼承的類叫派生類&#xff08;子類&#xff09;&#xff0c;在派生類類名后面加&#xff1a; 繼承方式 基類class CFather{}; class CSon:public CFather{};父類(基類)與子類(派生類)之間的關系…

bytetrack漏檢補齊

bytetrack漏檢補齊1.人流慢速運動&#xff0c;跟蹤效果比較好&#xff0c;偶爾有漏檢&#xff0c;跟蹤可以自動補齊。2.快速運動&#xff0c;頻繁遮擋&#xff0c;效果可能不好*如果漏檢&#xff0c;倒著跟蹤&#xff0c;把丟失的檢測框拷貝出來&#xff0c;保留進行跟蹤。有時…

安裝Keycloak并啟動服務(macOS)

前提&#xff1a;電腦已經安裝Java 17 1、下載Keycloak 2、下載完后解壓縮&#xff0c;使用文本編輯器修改配置文件&#xff08;keycloak/conf/keycloak.conf&#xff09; # Basic settings for running in production. Change accordingly before deploying the server. # …

汽車動力轉向器落錘沖擊試驗臺

落錘沖擊試驗臺主要用于扣件減振量的測試&#xff0c;采用電動錨鏈提錘結構&#xff0c;控制精度高&#xff0c;定位準確。采用伺服電機減速機驅動&#xff0c;避免提錘加速和到位減速時的沖擊&#xff0c;具有多重安全保護功能&#xff0c;防止二次沖擊裝置。主機框架采用上下…