命令模式(Command Pattern)詳解

文章目錄

    • 1. 什么是命令模式?
    • 2. 為什么需要命令模式?
    • 3. 命令模式的核心概念
    • 4. 命令模式的結構
    • 5. 命令模式的基本實現
      • 5.1 簡單的燈光控制示例
      • 5.2 家電控制示例
    • 6. 帶有撤銷功能的命令模式
      • 6.1 修改命令接口
      • 6.2 實現可撤銷的燈光命令
      • 6.3 實現可撤銷的風扇命令
      • 6.4 修改調用者,支持撤銷功能
      • 6.5 客戶端代碼演示
    • 7. 宏命令實現
      • 7.1 實現宏命令
      • 7.2 客戶端代碼演示
    • 8. 命令隊列實現
      • 8.1 命令隊列類
      • 8.2 客戶端代碼演示
    • 9. 命令日志與恢復
      • 9.1 可序列化的命令接口
      • 9.2 命令日志管理器
    • 10. 命令模式在Java中的實際應用
      • 10.1 Swing中的Action
      • 10.2 Runnable接口
      • 10.3 任務調度系統
      • 10.4 Java 8 Lambda表達式
    • 11. 命令模式與其他設計模式的結合
      • 11.1 命令模式與組合模式
      • 11.2 命令模式與備忘錄模式
      • 11.3 命令模式與策略模式
    • 12. 命令模式的優缺點
      • 12.1 優點
      • 12.2 缺點
    • 13. 命令模式的適用場景
    • 14. 命令模式的常見問題與解決方案
      • 14.1 如何處理大量的命令類?
      • 14.2 如何處理命令執行失敗的情況?
      • 14.3 如何實現更高效的撤銷/重做功能?
    • 15. 總結
      • 15.1 核心要點
      • 15.2 設計建議

1. 什么是命令模式?

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

簡單來說,命令模式就是將"請求"轉化為一個對象,這個對象可以被存儲、傳遞、調用,而且可以在不同的時間點被請求調用,即使發送請求的對象已經不存在。

2. 為什么需要命令模式?

在以下情況下,命令模式特別有用:

  1. 需要參數化操作:當你需要根據運行時確定的請求參數來執行操作時
  2. 需要將操作放入隊列:當操作需要排隊執行,或者在不同時間執行時
  3. 需要支持撤銷/重做功能:當系統需要支持操作的撤銷和重做功能時
  4. 需要支持事務:當操作需要作為一個事務執行,要么全部完成,要么全部不做
  5. 需要將發送者與接收者解耦:當請求發送者不需要知道請求如何被處理以及由誰處理時

3. 命令模式的核心概念

命令模式涉及以下幾個核心角色:

  1. 命令(Command)

    • 聲明執行操作的接口
    • 通常只有一個執行方法(如execute()
  2. 具體命令(Concrete Command)

    • 實現命令接口
    • 通常持有接收者的引用
    • 調用接收者的相關操作來完成命令的執行
  3. 接收者(Receiver)

    • 知道如何實施與命令相關的操作
    • 任何類都可以作為接收者
  4. 調用者(Invoker)

    • 要求命令對象執行請求
    • 不知道命令是如何執行的,也不知道具體的接收者是誰
  5. 客戶端(Client)

    • 創建具體的命令對象并設置它的接收者
    • 將命令對象交給調用者

4. 命令模式的結構

命令模式的UML類圖如下:

+----------------+       +----------------+
|    Invoker     |------>|    Command     |
+----------------+       +----------------+| execute()      |+----------------+↑|+----------------+|ConcreteCommand |+----------------+| execute()      |+----------------+||v+----------------+|    Receiver    |+----------------+| action()       |+----------------+

5. 命令模式的基本實現

5.1 簡單的燈光控制示例

下面是一個簡單的燈光控制示例,展示了命令模式的基本實現。

首先,定義命令接口:

// 命令接口
public interface Command {void execute();
}

然后,定義接收者類(燈):

// 接收者類
public class Light {private String location;public Light(String location) {this.location = location;}public void turnOn() {System.out.println(location + " 燈已打開");}public void turnOff() {System.out.println(location + " 燈已關閉");}
}

接著,定義具體命令類:

// 打開燈的命令
public class LightOnCommand implements Command {private Light light;public LightOnCommand(Light light) {this.light = light;}@Overridepublic void execute() {light.turnOn();}
}// 關閉燈的命令
public class LightOffCommand implements Command {private Light light;public LightOffCommand(Light light) {this.light = light;}@Overridepublic void execute() {light.turnOff();}
}

然后,定義調用者類(遠程控制器):

// 調用者類
public class RemoteControl {private Command command;public void setCommand(Command command) {this.command = command;}public void pressButton() {command.execute();}
}

最后,客戶端代碼:

public class CommandPatternDemo {public static void main(String[] args) {// 創建接收者Light livingRoomLight = new Light("客廳");Light kitchenLight = new Light("廚房");// 創建具體命令Command livingRoomLightOn = new LightOnCommand(livingRoomLight);Command livingRoomLightOff = new LightOffCommand(livingRoomLight);Command kitchenLightOn = new LightOnCommand(kitchenLight);Command kitchenLightOff = new LightOffCommand(kitchenLight);// 創建調用者RemoteControl remote = new RemoteControl();// 使用遠程控制器打開客廳燈remote.setCommand(livingRoomLightOn);remote.pressButton();// 使用遠程控制器關閉客廳燈remote.setCommand(livingRoomLightOff);remote.pressButton();// 使用遠程控制器打開廚房燈remote.setCommand(kitchenLightOn);remote.pressButton();// 使用遠程控制器關閉廚房燈remote.setCommand(kitchenLightOff);remote.pressButton();}
}

輸出結果:

客廳 燈已打開
客廳 燈已關閉
廚房 燈已打開
廚房 燈已關閉

5.2 家電控制示例

我們可以擴展上面的例子,添加更多種類的家電控制:

// 音響系統接收者
public class StereoSystem {private String location;public StereoSystem(String location) {this.location = location;}public void on() {System.out.println(location + " 音響已打開");}public void off() {System.out.println(location + " 音響已關閉");}public void setCD() {System.out.println(location + " 音響已設置為CD播放模式");}public void setVolume(int volume) {System.out.println(location + " 音響音量已設置為 " + volume);}
}// 電風扇接收者
public class Fan {private String location;public Fan(String location) {this.location = location;}public void on() {System.out.println(location + " 電風扇已打開");}public void off() {System.out.println(location + " 電風扇已關閉");}public void setHigh() {System.out.println(location + " 電風扇已設置為高速");}public void setMedium() {System.out.println(location + " 電風扇已設置為中速");}public void setLow() {System.out.println(location + " 電風扇已設置為低速");}
}

然后,為這些家電創建對應的命令:

// 打開音響的命令
public class StereoOnWithCDCommand implements Command {private StereoSystem stereo;public StereoOnWithCDCommand(StereoSystem stereo) {this.stereo = stereo;}@Overridepublic void execute() {stereo.on();stereo.setCD();stereo.setVolume(11);}
}// 關閉音響的命令
public class StereoOffCommand implements Command {private StereoSystem stereo;public StereoOffCommand(StereoSystem stereo) {this.stereo = stereo;}@Overridepublic void execute() {stereo.off();}
}// 打開風扇并設置高速的命令
public class FanHighCommand implements Command {private Fan fan;public FanHighCommand(Fan fan) {this.fan = fan;}@Overridepublic void execute() {fan.on();fan.setHigh();}
}// 關閉風扇的命令
public class FanOffCommand implements Command {private Fan fan;public FanOffCommand(Fan fan) {this.fan = fan;}@Overridepublic void execute() {fan.off();}
}

修改調用者類,支持多個按鈕:

// 多按鈕遙控器
public class MultiButtonRemote {private Command[] onCommands;private Command[] offCommands;public MultiButtonRemote(int slotCount) {onCommands = new Command[slotCount];offCommands = new Command[slotCount];// 初始化所有命令為空命令對象,避免空指針異常Command noCommand = new NoCommand(); // NoCommand是一個空實現for (int i = 0; i < slotCount; i++) {onCommands[i] = noCommand;offCommands[i] = noCommand;}}public void setCommand(int slot, Command onCommand, Command offCommand) {onCommands[slot] = onCommand;offCommands[slot] = offCommand;}public void pressOnButton(int slot) {onCommands[slot].execute();}public void pressOffButton(int slot) {offCommands[slot].execute();}
}// 空命令 - 用于初始化,避免空指針異常
public class NoCommand implements Command {@Overridepublic void execute() {// 什么也不做}
}

客戶端代碼:

public class HomeAutomationDemo {public static void main(String[] args) {// 創建接收者Light livingRoomLight = new Light("客廳");Light kitchenLight = new Light("廚房");StereoSystem stereo = new StereoSystem("客廳");Fan ceilingFan = new Fan("臥室");// 創建具體命令Command livingRoomLightOn = new LightOnCommand(livingRoomLight);Command livingRoomLightOff = new LightOffCommand(livingRoomLight);Command kitchenLightOn = new LightOnCommand(kitchenLight);Command kitchenLightOff = new LightOffCommand(kitchenLight);Command stereoOnWithCD = new StereoOnWithCDCommand(stereo);Command stereoOff = new StereoOffCommand(stereo);Command fanHigh = new FanHighCommand(ceilingFan);Command fanOff = new FanOffCommand(ceilingFan);// 創建多按鈕遙控器MultiButtonRemote remote = new MultiButtonRemote(4);// 設置每個插槽對應的命令remote.setCommand(0, livingRoomLightOn, livingRoomLightOff);remote.setCommand(1, kitchenLightOn, kitchenLightOff);remote.setCommand(2, stereoOnWithCD, stereoOff);remote.setCommand(3, fanHigh, fanOff);// 測試按鈕System.out.println("------ 按下第1個按鈕的開按鈕 --

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

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

相關文章

《Vue3學習手記8》

vue3中的一些API shallowRef ( ) 和shallowReactive ( ) shallowRef (淺層響應式) 1.作用:創建一個響應式數據&#xff0c;但只對頂層屬性進行響應式處理。 2.用法: const originalref(...) const original2shallowRef(original) 3.特點:只跟蹤引用值的變化&#xff0c;不關心…

雙列集合——map集合和三種遍歷方式

雙列集合的特點 鍵和值一一對應&#xff0c;每個鍵只能對應自己的值 一個鍵和值整體稱為鍵值對或鍵值對對象&#xff0c;java中叫做entry對象。 map常見的api map接口中定義了雙列集合所有的共性方法&#xff0c;下面三個實現類就沒有什么額外新的方法要學習了。 map接口…

Linux安裝部署Postgresql數據庫

聯網安裝方案 Linux能在線安裝依賴組件的前提下&#xff0c;可以快速安裝部署PG數據庫&#xff0c;安裝過程使用root管理員帳號&#xff1a; 首先&#xff0c;使用如下命令自動下載Postgresql組件&#xff1a; # 在openEuler、Fedora或CentOS 8上&#xff0c;你可能會使用&a…

供應鏈算法整理(二)--- 智能補貨

供應鏈業務的目標價值是&#xff1a;優化貨品的供給、銷售提供支撐&#xff0c;以降低成本&#xff0c;提高時效、收益&#xff0c;最終提升用戶體驗。基于目標價值&#xff0c;整體的算法模塊分為&#xff1a;智能選品、智能預測、品倉鋪貨、智能補貨、智能調撥、倉網路由、快…

vscode 個性化

vscode 個性化 設置 吸頂效果 使用前使用后 設置方法 VS Code 的粘性滾動預覽 - 類似于 Excel 的凍結首行 插件 代碼片段分享 - CodeSnap 使用方式 CtrlShiftP輸入CodeSnap 喚起插件選擇代碼 行內報錯提示 - Error Lens 使用前使用后 VSCode Error Lens插件介紹&…

Rockermq的部署與使用(0-1)

?RocketMQ? 是阿里巴巴開源的一款 ?分布式消息中間件&#xff0c;具有高吞吐、低延遲、高可用等特點&#xff0c;廣泛應用于多個領域&#xff0c;包括異步通信解耦、企業解決方案、金融支付、電信、電子商務、快遞物流、廣告營銷、社交、即時通信、移動應用、手游、視頻、物…

軟件測試報告機構如何保障軟件質量并維護其安全性?

軟件測試報告機構在軟件開發流程里起著十分關鍵的作用&#xff0c;它可以保障軟件的質量&#xff0c;它還能夠維護軟件的安全性。下面&#xff0c;我們就來深入了解一下這類機構。 機構作用 軟件測試報告機構是軟件質量的“把關者”&#xff0c;能對軟件進行全面評估&#xf…

4個純CSS自定義的簡單而優雅的滾動條樣式

今天發現 uni-app 項目的滾動條不顯示&#xff0c;查了下原來是設置了 ::-webkit-scrollbar {display: none; } 那么怎么用 css 設置滾動條樣式呢&#xff1f; 定義滾動條整體樣式? ::-webkit-scrollbar 定義滾動條滑塊樣式 ::-webkit-scrollbar-thumb 定義滾動條軌道樣式?…

ES6入門---第二單元 模塊五:模塊化

js不支持模塊化 注意&#xff1a; 需要放到服務器環境 1、如何定義模塊&#xff1f; export 東西 例&#xff1a;1.js文件中 console.log(1模塊加載了);//顯示是否加載了 export const a 12; export const b 5; export let c 101; const a12; const b5; const c101;ex…

14.Excel:排序和篩選

一 位置 兩個位置。 二 排序&#xff1a;如何使用 1.常規使用 補充&#xff1a;不彈出排序提醒排序。 選中要排序列中的任意一個單元格&#xff0c;然后排序。 2.根據要求進行排序 1.根據姓名筆畫進行降序排序 要勾選上數據包含標題&#xff0c;默認是勾選了。 2.根據運營部、…

嵌入式系統基礎知識

目錄 一、馮諾依曼結構與哈佛結構 &#xff08;一&#xff09;馮諾依曼結構 &#xff08;二&#xff09;哈佛架構 二、ARM存儲模式 &#xff08;一&#xff09;大端模式 &#xff08;二&#xff09;小端模式 &#xff08;三&#xff09;混合模式 三、CISC 與 RISC &am…

CSS 預處理器 Sass

目錄 Sass 一、Sass 是什么&#xff1f; 二、核心功能詳解 1. 變量&#xff08;Variables&#xff09; 2. 嵌套&#xff08;Nesting&#xff09; 3. 混合宏&#xff08;Mixins&#xff09; 4. 繼承&#xff08;Inheritance&#xff09; 5. 運算&#xff08;Operations&…

信息收集新利器:SSearch Chrome 插件來了

SSearch 下載地址 SSearch &#x1f623;用途 每次谷歌語法搜索時還得自己寫&#xff0c;我想省事一點&#xff0c;弄了一個插件&#xff0c;先加了幾個常用的語法&#xff0c;點擊后會跳轉到對應搜索頁面&#xff0c;也可以直接在搜索框微調 后續也會加些其他語法 &#…

Docker搭建SFTP

在這個教程中&#xff0c;我們將通過一個簡單的例子來展示如何使用 Docker 和 atmoz/sftp 鏡像設置一個基本的 SFTP 服務。這個服務將允許用戶通過 SFTP 安全地訪問和管理文件。我們將配置一個名為 ops 的用戶&#xff0c;其密碼為 123456&#xff0c;并限定用戶只能訪問特定的…

正態分布習題集 · 答案與解析篇

正態分布習題集 答案與解析篇 與題目篇編號一致,如有其他解題思路,歡迎在評論區交流。 1. 基礎定義與性質 1.1 密度函數 X ~ N ( μ , σ 2 ) X \sim N(\mu,\sigma^2) X~N(μ,σ2) 的 PDF: [ f(x) = \frac{1}{\sigma\sqrt{2\pi}} \exp\left(-\frac{(x-\mu)2}{2\sigma2}\…

Java學習手冊:SQL 優化技巧

一、SQL 查詢優化 選擇合適的索引列 &#xff1a;索引可以顯著提高查詢速度&#xff0c;但需要選擇合適的列來創建索引。通常&#xff0c;對于頻繁作為查詢條件的列、連接操作的列以及排序或分組操作的列&#xff0c;應該考慮創建索引。例如&#xff0c;在一個訂單表中&#xf…

(02)Redis 的訂閱發布Pub/Sub

我們為了自己實現一個MQ功能&#xff0c;就要深入底層挖掘現有開源產品的實現過程。 Redis 發布訂閱底層結構解析 Redis 不存儲消息&#xff0c;僅作為“實時中轉”&#xff1b;只有訂閱者在線時才能收到消息&#xff1b;消息是廣播給所有訂閱此頻道的客戶端。 1. 核心數據結…

使用Docker一鍵安裝SigLens:簡單快捷的日志分析解決方案

在當今復雜的IT環境中,高效的日志管理和分析變得越來越重要。SigLens作為一款強大的開源日志分析工具,為開發者和運維人員提供了直觀、高效的日志處理體驗。本文將介紹如何使用Docker快速安裝SigLens,讓您在幾分鐘內就能開始進行日志分析。 為什么選擇Docker安裝SigLens? Do…

C#與西門子PLC通信:S7NetPlus和HslCommunication使用指南

西門子S7協議是用來和PLC進行通訊的一個協議&#xff0c;默認端口是102&#xff0c;數據會保存在一個個DB塊中&#xff0c;比較經典的用法是一個DB塊專門用來讀取&#xff0c;一個用來寫入。 DB&#xff08;數據塊&#xff09; {塊號}.DBX/DBD/DBW{字節地址}.{位偏移} 1、數據…

【中間件】brpc_基礎_remote_task_queue

文章目錄 remote task queue1 簡介2 核心功能2.1 任務提交與分發2.2 無鎖或低鎖設計2.3 與 bthread 深度集成2.4 流量控制與背壓 3 關鍵實現機制3.1 數據結構3.2 任務提交接口3.3 任務竊取&#xff08;Work Stealing&#xff09;3.4 同步與喚醒 4 性能優化5 典型應用場景6 代碼…