常用設計模式系列(十七)—命令模式

常用設計模式系列(十七)—命令模式

第一節、前言

各位老鐵好!
今天我來跟大家分享對象行為型模式第二章節——《命令模式》,“命令”一詞,通俗易懂,我們在生活中經常會發出各種各樣的命令,就像你告訴你手機上的“siri”、“小愛同學”打開音樂、切歌等等命令,而你的“語音小助理”根據不同的指令完成對不同軟件的不同操作,這個過程使用的就是“命令模式”。

第二節、命令模式

命令模式概念:

命令模式(Command Pattern):
將一個請求封裝為一個對象,從而可用不同的請求對客戶進行參數化,對請求排隊或者或者記錄請求日志以及支持可撤銷的操作

命令模式的構成:

在這里插入圖片描述

個人理解

將用戶的請求即命令進行抽象,抽象為一個對象,每個客戶端調用不同的對象即發起不同的命令來完成指令,命令模式需要支持當請求較多時候的請求隊列排隊,并且記錄請求過程的日志,并且要支持可撤銷的動作。

場景舉例:

在日常生活中,我們使用開關來控制一些電器的打開或者關閉,例如常見的電燈、排風扇、門禁等等,這個開關可以安裝到不同的電器上,那這樣對應安裝的開關就能控制對應的電器,所以開關與電器沒有直接的關系,因為買來的開關可能控制燈泡,可能控制其它電器開關。但是開關與電器之間使用電線連接,開關打開時,電線通電,電器正常工作,相反則電器停止工作,相同的開關可以通過不同的線路來控制不同的電器。這個時候發送者(開關)換個接受者(電器)就可以解耦,發送的對象(開關)只需要知道如何發送請求,而不需要知道如何完成請求(完成請求是電線的職責),這個解耦后運轉的模式,稱為命令模式。

結構圖:

image

第三節、場景分析及代碼實現

場景分析

我們在使用電腦操控的時候,使用的是鼠標去點擊系統的某個按鈕,按鈕上的字展示的不同的功能,然后點擊按鈕,按鈕會根據不同的指令完成某個功能,例如某個系統有主頁按鈕,登錄按鈕、退出按鈕;

可以分析有如下幾個角色

1.功能按鈕當做調用者。
2.Command類當做抽象命令。
3.可設計三個具體命令類:主頁命令類、登錄命令類、退出命令類。
4.可以設計出一個系統類用來當做接收者,包含訪問主頁命令、登錄命令、退出命令

UML圖

image

代碼實現

1.調用者功能按鈕類FunctionButton

package com.yang.command;/*** @ClassName FunctionButton* @Description 功能按鈕類* @Author IT小白架構師之路* @Date 2021/1/25* @Version 1.0**/
public class FunctionButton {/*** 命令*/private Command command;public FunctionButton(Command command){this.command = command;}/*** 點擊動作*/public void click(){//執行命令command.execute();}
}

2.抽象命令類Command

package com.yang.command;/*** @ClassName Command* @Description 抽象命令類* @Author IT小白架構師之路* @Date 2021/1/25* @Version 1.0**/
public interface Command {/*** 執行命令*/public void execute();
}

3.訪問主頁命令IndexCommand

package com.yang.command;/*** @ClassName IndexCommand* @Description 訪問主頁命令類* @Author IT小白架構師之路* @Date 2021/1/25* @Version 1.0**/
public class IndexCommand implements Command{/*** 系統類*/private SystemMenu systemMenu;public IndexCommand(){systemMenu = new SystemMenu();}@Overridepublic void execute() {systemMenu.toIndex();}
}

4.登錄命令類LoginCommand

package com.yang.command;/*** @ClassName LoginCommand* @Description 登錄命令類* @Author IT小白架構師之路* @Date 2021/1/25* @Version 1.0**/
public class LoginCommand implements Command{/*** 系統類*/private SystemMenu systemMenu;public LoginCommand(){systemMenu = new SystemMenu();}@Overridepublic void execute() {systemMenu.toLogin();}
}

5.退出命令類LogoutCommand

package com.yang.command;/*** @ClassName LogOutCommand* @Description 退出命令類* @Author IT小白架構師之路* @Date 2021/1/25 14:51* @Version 1.0**/
public class LogOutCommand implements Command{/*** 系統類*/private SystemMenu systemMenu;public LogOutCommand(){systemMenu = new SystemMenu();}@Overridepublic void execute() {systemMenu.toLogOut();}
}

6.系統類作為調用者SystemMenu

package com.yang.command;/*** @ClassName SystemMenu* @Description 系統菜單類* @Author IT小白架構師之路* @Date 2021/1/25* @Version 1.0**/
public class SystemMenu {/*** 訪問主頁*/public void toIndex(){System.out.println("當前是主頁");}/*** 登錄動作*/public void toLogin(){System.out.println("登錄成功");}/*** 退出動作*/public void toLogOut(){System.out.println("您已退出");}
}

7.創建客戶端進行測試

package com.yang.command;/*** @ClassName Client* @Description 客戶端* @Author IT小白架構師之路* @Date 2021/1/25* @Version 1.0**/
public class Client {public static void main(String[] args) {//要發起訪問主頁命令Command command = new IndexCommand();//功能按鈕FunctionButton functionButton = new FunctionButton(command);//點擊functionButton.click();System.out.println("-------------------我是分割線-----------------------");//要發起登錄命令command = new LoginCommand();//功能按鈕functionButton = new FunctionButton(command);//點擊functionButton.click();System.out.println("-------------------我是分割線-----------------------");//要發起登出命令command = new LogOutCommand();//功能按鈕functionButton = new FunctionButton(command);//點擊functionButton.click();System.out.println("-------------------我是分割線-----------------------");}
}

8.測試結果如下

當前是主頁
-------------------我是分割線-----------------------
登錄成功
-------------------我是分割線-----------------------
您已退出
-------------------我是分割線-----------------------

使用代碼實現隊列

加隊列的目的是,當業務發送方為多個、業務接收方為多個時,可以使用隊列存儲多個命令對象,不同的命令對象可以對應不同的請求者。增加隊列后,可以將命令存放在隊列中,一次執行,類似批量執行。

1.創建命令隊列類

package com.yang.command;import java.util.ArrayList;/*** @ClassName CommandQueue* @Description 命令隊列* @Author IT小白架構師之路* @Date 2021/1/25* @Version 1.0**/
public class CommandQueue {//隊列private ArrayList<Command> commands = new ArrayList<Command>();//添加命令public void addCommand(Command command){commands.add(command);}//刪除命令public void delCommand(Command command){commands.remove(command);}//執行public void execute(){for (Command command : commands){command.execute();}}
}

2.改造調用者為隊列版FunctionButtonQueue

package com.yang.command;/*** @ClassName FunctionButtonQueue* @Description 調用者隊列版* @Author IT小白架構師之路* @Date 2021/1/25* @Version 1.0**/
public class FunctionButtonQueue {//隊列對象private CommandQueue commandQueue;public FunctionButtonQueue(CommandQueue  commandQueue){this.commandQueue = commandQueue;}//處理public void click(){commandQueue.execute();}
}

3.客戶端測試

package com.yang.command;/*** @ClassName ClientQueue* @Description 隊列版測試* @Author IT小白架構師之路* @Date 2021/1/25* @Version 1.0**/
public class ClientQueue {public static void main(String[] args) {CommandQueue commandQueue = new CommandQueue();//要發起訪問主頁命令Command command = new IndexCommand();commandQueue.addCommand(command);//要發起登錄命令command = new LoginCommand();commandQueue.addCommand(command);//要發起登出命令command = new LogOutCommand();commandQueue.addCommand(command);//執行FunctionButtonQueue functionButtonQueue = new FunctionButtonQueue(commandQueue);functionButtonQueue.click();}
}

4.執行結果

當前是主頁
登錄成功
您已退出

增加命令緩存來完成撤銷

1.增加臨時緩存類CommandCache

package com.yang.command;/*** @ClassName CommandCache* @Description 執行緩存* @Author IT小白架構師之路* @Date 2021/1/25* @Version 1.0**/
public class CommandCache {private static Command lastCommad;private static Command currentCommand;public static Command getLastCommad() {return lastCommad;}public static void setLastCommad(Command lastCommad) {CommandCache.lastCommad = lastCommad;}public static Command getCurrentCommand() {return currentCommand;}public static void setCurrentCommand(Command currentCommand) {CommandCache.currentCommand = currentCommand;}
}

2.優化功能按鈕類

package com.yang.command;/*** @ClassName FunctionButton* @Description 功能按鈕類* @Author IT小白架構師之路* @Date 2021/1/25* @Version 1.0**/
public class FunctionButton {/*** 命令*/private Command command;public FunctionButton(Command command){this.command = command;}/*** 點擊動作*/public void click(){Command lastCommad = CommandCache.getLastCommad();Command currentCommand = CommandCache.getCurrentCommand();//都為空則為本次,第一次撤銷無意義if(null == lastCommad && null == currentCommand){CommandCache.setCurrentCommand(command);CommandCache.setLastCommad(command);}else{//你不為空則把上次的最后一次進行執行CommandCache.setLastCommad(currentCommand);CommandCache.setCurrentCommand(command);}//執行命令command.execute();}public void revert(){System.out.println("--------撤銷開始------");Command lastCommad = CommandCache.getLastCommad();lastCommad.execute();System.out.println("--------撤銷結束------");}
}

3.測試撤銷Client

package com.yang.command;/*** @ClassName RevertClient* @Description 注釋* @Author IT小白架構師之路* @Date 2021/1/25* @Version 1.0**/
public class RevertClient {public static void main(String[] args) {//要發起訪問主頁命令Command command = new IndexCommand();//功能按鈕FunctionButton functionButton = new FunctionButton(command);//點擊functionButton.click();System.out.println("-------------------我是分割線-----------------------");functionButton.revert();//要發起登錄命令command = new LoginCommand();//功能按鈕functionButton = new FunctionButton(command);//點擊functionButton.click();System.out.println("-------------------我是分割線-----------------------");//撤銷functionButton.revert();}
}

4.測試結果,完成了撤銷操作,回到了上一個界面

當前是主頁
-------------------我是分割線-----------------------
--------撤銷開始------
當前是主頁
--------撤銷結束------
登錄成功
-------------------我是分割線-----------------------
--------撤銷開始------
當前是主頁
--------撤銷結束------

第四節

優缺點及適用場景

優點

1.可以降低系統的耦合度,由于請求者和接收者之間不存在直接調用,則請求者與接收者之間做到了完全解耦,相同的請求者也可以做到調用不同的接受者,同樣接收者可以給不同的請求者使用,互相獨立,故降低了耦合度。

2.新的命令可以更快的增加到系統中,創建新的具體命令類不會影響其他類

3.可以簡單的設計出一個隊列命令進行批量執行

4.為撤銷和恢復提供了一種設計和實現方案

缺點

1.當命令逐漸增加時,系統會增加很多的具體命令類。

2.當命令增多時,開發人員維護成本變高

適用場景

1.系統需要將調用者與接受者進行解耦,不需要兩者進行交互的場景下。

2.系統要在不同的時間指定請求,將請求進行排隊或者批量執行是。

3.系統需要增加通用的撤銷、恢復功能時。

4.系統需要將一組操作指令進行抽象,完成通用設計時。

掃描二維碼

關注我吧

IT小白架構師之路

image

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

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

相關文章

【AI繪畫】Stable Diffusion 全面指南:安裝、版本對比、功能解析與高級應用

引言&#xff1a;Stable Diffusion 概述 在人工智能圖像生成領域&#xff0c;商業工具如Midjourney憑借其集成化服務與高質量輸出占據市場&#xff0c;而Stable Diffusion&#xff08;簡稱SD&#xff09;則以開源特性構建了差異化優勢。與商業工具依賴云端資源、受限于訂閱費用…

kafka使用kraft

window 使用kafka-storage生成生成一個uuid .\kafka-storage.bat random-uuid格式化存儲 在這里插入代碼片.\kafka-storage.bat format -t 對應的uuid D:\configure\fisher\kafka\config\kraft\server.properties 啟動命令 .\kafka-server-start.bat D:\configure\fisher\kafka…

HCIA-Datacom認證筆記:IP路由基礎——核心概念與路由分類

網絡技術學習中&#xff0c;IP路由是繞不開的核心知識點&#xff0c;對于備考HCIA-Datacom認證的朋友來說&#xff0c;掌握路由基礎能為后續學習打下良好基礎。今天帶朋友們梳理一下IP路由的核心概念、路由表結構及路由分類一、路由核心概念什么是路由&#xff1f; 簡單來說&am…

FFmpeg 安裝與使用

文章目錄1. 環境部署&#xff08;Windows&#xff09;1.1. 安裝包下載1.2. 配置環境變量1.3. 驗證安裝2. FFmpeg 基礎使用教程2.1. 常用命令格式2.2. 基礎功能示例2.2.1. 視頻轉碼&#xff08;MP4 → MKV&#xff09;2.2.2. 調整分辨率&#xff08;1080p → 480p&#xff09;2.…

Python 數據分析(四):Pandas 進階

目錄 1. 概述2. 缺失項3. 分組聚合4. 數據合并5. 數據可視化 5.1 折線圖5.2 條形圖5.3 直方圖5.4 散點圖5.5 餅圖 1. 概述 我們在上一篇文章初識 Pandas中已經對 Pandas 作了一些基本介紹&#xff0c;本文我們進一步來學習 Pandas 的一些使用。 2. 缺失項 在現實中我們獲…

結構化文本文檔的內容抽取與版本重構策略

結構化文本文檔的內容抽取與版本重構策略 摘要 本文深入探討了結構化文本文檔處理領域中的兩大核心技術——內容抽取與版本重構。文章首先分析了結構化文檔的特點及其在現代信息管理中的重要性&#xff0c;隨后系統性地介紹了文檔內容抽取的技術路線與方法論&#xff0c;包括…

【BUUCTF系列】[HCTF 2018]WarmUp1

本文僅用于技術研究&#xff0c;禁止用于非法用途。 Author:枷鎖 點開題目顯示一個圖片&#xff0c;沒有任何交互功能&#xff0c;我們直接查看網頁源代碼我們可以看到有一個歆慕的注釋source.php&#xff0c;我們進行拼接&#xff0c;訪問一下這個文件在url后加上/source.php進…

Flutter Chen Generator - IconFont Generator

Flutter Chen Generator &#x1f680; 一個強大的Flutter代碼生成工具包&#xff0c;包含多個實用的代碼生成器。 ? 功能特性 &#x1f4c1; 資源生成器 (Assets Generator) &#x1f504; 自動掃描assets目錄并生成Dart常量&#x1f9e0; 智能駝峰命名轉換&#xff0c;保…

【MATLAB】(二)基礎知識

一.MATLAB命令1.指令行“頭首”的 “>>” 是 “指令輸入提示符” &#xff0c;它是自動輸入的。“>>” 為運算提示符&#xff0c;表示MATLAB處于準備就緒狀態。如在提示符后輸入一條命令或一段程序后按Enter鍵&#xff0c;MATLAB將給出對應的結果&#xff0c;并將結…

Day36| 1049. 最后一塊石頭的重量 II、494.目標和、474.一和零

文章鏈接 1049. 最后一塊石頭的重量 II 解題關鍵&#xff1a;找到重量和盡量相等的兩堆 確定dp數組以及下標的含義 dp[j]表示容量&#xff08;這里說容量更形象&#xff0c;其實就是重量&#xff09;為j的背包&#xff0c;最多可以背最大重量為dp[j]。 確定遞推公式 01背包…

【A*/BFS】P5507 機關

# P5507 機關 題目描述 這扇門上有一個機關&#xff0c;上面一共有12個旋鈕&#xff0c;每個旋鈕有4個狀態&#xff0c;將旋鈕的狀態用數字111到444表示 每個旋鈕只能向一個方向旋轉&#xff08;狀態&#xff1a;1->2->3->4->1&#xff09;&#xff0c;在旋轉時&am…

終結集成亂局:模型上下文協議(MCP)如何重構AI工具生態?

AI 助手正處于能力發展的初級階段。它們擅長處理獨立任務——例如解析 PDF、編寫 SQL 語句、等等——但當你要求它們在 Slack、Gmail 和 Jira 等平臺間協同操作時&#xff0c;整個流程就變得異常復雜且脆弱&#xff0c;如同調試一套由眾多 API 密鑰串聯的精密機械&#xff08;魯…

談談畢業工作一年后的變化

文章目錄談談畢業工作一年后的變化工作篇生活篇談談畢業工作一年后的變化 工作篇 2025.7.30 21:49 呼~再次打開這個網站發布文章&#xff0c;是多么陌生。仿佛有說不完的話&#xff0c;但如今時間卻不允許我無限制的長篇大論的寫下去了。 先說下工作吧。 畢業后工作好快啊&…

huggingface下載問題

國內使用git clone下載huggingfaceTOC 國內直接git clone連接不上問題 git clone https://huggingface.co/spaces/ZebangCheng/Emotion-LLaMA Cloning into ‘Emotion-LLaMA’… fatal: unable to access ‘https://huggingface.co/spaces/ZebangCheng/Emotion-LLaMA/’: Fai…

anaconda searchanaconda show | conda 檢索包資源安裝指定版本包指定源安裝命令package

conda issuehttp://t.csdnimg.cn/ndZZK 目錄 常規安裝 檢索包資源 獲取指定包的安裝源&安裝指令 安裝指定包 常規安裝 conda 常規安裝xxx包 conda install xxx conda install有可能會受限于channel導致報錯PackagesNotFoundError: The following packages are not av…

python cli命令 cli工具命令 自定義cli命名 開發 兼容 window、mac、linux,調用示例

前言需求背景整個項目基于Python開發&#xff0c;需求方期望不直接調用Python腳本執行&#xff0c;希望封裝為cli命令執行Python腳本&#xff0c;使其更為簡單而又“優雅”。類似直接使用 adb devices 的方式直接調用運行&#xff0c;而不是 python adbToolls.py devices的方式…

k8s pod生命周期、初始化容器、鉤子函數、容器探測、重啟策略

pod結構Pause容器 Pause容器是每個Pod都會有的一個根容器&#xff0c;它的作用有兩個 可以以它為根據&#xff0c;評估整個pod的健康狀態可以在根容器上設置IP地址&#xff0c;其他容器都以此IP&#xff08;Pod IP&#xff09;&#xff0c;以實現Pod內部的網絡通信&#xff0c;…

Redis:緩存雪崩、穿透、擊穿的技術解析和實戰方案

&#x1f6a8; 1、簡述 隨著系統規模擴大&#xff0c;Redis 緩存被廣泛用于數據預熱、熱點數據防護和高并發系統優化。然而在高并發環境中&#xff0c;緩存雪崩、穿透、擊穿等問題若處理不當&#xff0c;可能導致系統雪崩式崩潰。 本文從原理、原因出發&#xff0c;結合實際項目…

前端-html+CSS基礎到高級(二)html基礎

一、 為什么需要Web標準 瀏覽器差異問題&#xff1a;五大主流瀏覽器&#xff08;IE、Chrome、Firefox、Safari等&#xff09;使用不同渲染引擎&#xff0c;導致相同代碼解析效果存在差異。為什么需要Web標準&#xff1f;不同瀏覽器的渲染引擎不同&#xff0c;對于相同代碼解析的…

前端-移動Web-day2

目錄 1、空間-平移 2、視距 3、空間旋轉-Z軸 4、空間旋轉-X軸 5、空間旋轉-Y軸 6、立體呈現 7、案例-3D導航 8、空間-縮放 9、動畫-體驗 10、動畫-實現步驟 11、animation復合屬性 12、animation拆分寫法 13、案例-走馬燈 14、精靈動畫 15、多組動畫 16、案例-…