常用设计模式系列(十七)—命令模式

常用设计模式系列(十七)—命令模式

第一节、前言

各位老铁好!
今天我来跟大家分享对象行为型模式第二章节——《命令模式》,“命令”一词,通俗易懂,我们在生活中经常会发出各种各样的命令,就像你告诉你手机上的“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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈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、案例-…