Java命令模式源码剖析及使用场景

命令模式

  • 一、原理与通俗理解
  • 二、项目开发日志功能
  • 三、Java源码中的命令模式
  • 四、总结优缺点以及使用经验

一、原理与通俗理解

命令模式将请求封装为一个命令对象,将发出请求的对象与执行请求的对象解耦。命令模式可以让你在不同时间点调用命令,将命令放入队列中,并实现对命令的撤销和恢复操作。

比如在餐馆点餐,你(调用者)跟服务员(调用对象)说要来一份炒饭(命令),服务员就去通知厨师(执行对象)去炒一份炒饭。

二、项目开发日志功能

需求:记录日志并支持撤销操作

实现:

  1. 定义命令接口Command,定义执行命令、撤销命令方法
  2. LogCommand 类实现了具体的日志记录命令,记录日志时备份当前日志,并在撤销时恢复到备份的日志状态。
  3. LogCommandInvoker 类负责执行和管理命令,执行命令时记录历史记录,并且支持撤销操作。
  4. LogManager 类负责实际的日志记录操作,包括记录日志、获取当前日志内容以及清空日志。
// 1. 定义命令接口
interface Command {void execute(); // 执行命令void undo(); // 撤销命令
}// 2. 实现具体的日志记录命令
class LogCommand implements Command {private LogManager logManager;private String logMessage;private String backupLog; // 用于撤销操作public LogCommand(LogManager logManager, String logMessage) {this.logManager = logManager;this.logMessage = logMessage;}@Overridepublic void execute() {backupLog = logManager.getLog(); // 备份当前日志logManager.log(logMessage); // 记录新日志}@Overridepublic void undo() {logManager.clearLog(); // 清空当前日志logManager.log(backupLog); // 恢复到执行之前的日志}
}// 3. 定义命令调用者
class LogCommandInvoker {private List<Command> commandHistory = new ArrayList<>();public void executeCommand(Command command) {command.execute(); // 执行命令commandHistory.add(command); // 将命令添加到历史记录中}public void undoCommand() {if (!commandHistory.isEmpty()) {Command command = commandHistory.remove(commandHistory.size() - 1); // 从历史记录中取出最后一个命令command.undo(); // 执行撤销操作}}
}// 4. 定义命令执行者
class LogManager {private StringBuilder log = new StringBuilder();public void log(String message) {log.append(message).append("\n"); // 记录日志信息System.out.println("Logged: " + message);}public String getLog() {return log.toString(); // 获取当前日志内容}public void clearLog() {log = new StringBuilder(); // 清空日志}
}

使用:

LogManager logManager = new LogManager();
LogCommandInvoker invoker = new LogCommandInvoker();// 记录日志
invoker.executeCommand(new LogCommand(logManager, "Log message 1"));
invoker.executeCommand(new LogCommand(logManager, "Log message 2"));// 撤销一条日志
invoker.undoCommand();// 再次记录日志
invoker.executeCommand(new LogCommand(logManager, "Log message 3"));

三、Java源码中的命令模式

  1. java.lang.Runnable

Runnable接口允许将一个命令封装为一个可执行的对象,然后可以将该对象传递给线程执行。

Thread thread = new Thread(new Runnable() {@Overridepublic void run() {// 执行命令}
});
thread.start();

首先,我们来看一下Runnable接口的定义,这是一个简单的函数式接口,只有一个抽象方法run()。

public interface Runnable {public abstract void run();
}

现在我们创建一个类来实现Runnable接口:

public class MyCommand implements Runnable {@Overridepublic void run() {// 执行具体的任务System.out.println("Executing command");}
}

现在我们可以创建一个线程并将MyCommand对象作为参数传递给线程:

public class Main {public static void main(String[] args) {MyCommand command = new MyCommand();Thread thread = new Thread(command);thread.start();  // 启动线程,调用command的run()方法}
}

在上面的例子中,MyCommand对象封装了需要被执行的任务,并且通过将其作为参数传递给线程,线程会调用其run()方法来执行具体的任务。这就是命令模式的应用,将操作封装成对象,并且能够在不同的上下文中执行这个命令。

因此,通过实现Runnable接口并重写run()方法,可以实现类似于命令模式的效果,封装命令并且能够在不同的上下文中执行。

四、总结优缺点以及使用经验

优点:

  1. 低耦合,命令发送者和执行者完全解耦
  2. 可以将命令存入队列,实现撤销/恢复操作
  3. 命令对象可以携带额外的执行信息
  4. 新增新命令非常方便,无需修改现有代码

缺点:

  1. 可能会导致系统有过多的具体命令类
  2. 命令对象本身冗长

使用经验:

  1. 适用于需要将操作请求作为对象进行参数化传递的场景
  2. 适用于需要支持命令队列、命令记录日志、撤销/恢复操作等功能的场景
  3. 可以考虑使用组合模式组合多个命令形成复合命令
  4. 在设计阶段就应该考虑是否需要支持撤销/恢复操作
  5. 命令模式可以为不同对象的相同操作提供统一的接口
  6. 在面向对象设计中,命令模式是常用的行为型设计模式

命令模式将请求与执行解耦,可以方便地扩展新的命令、实现命令队列和支持撤销/恢复操作等功能。在需要对操作进行参数化、队列化、日志记录、撤销/恢复等需求时,命令模式是一个不错的选择。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/740080.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Deep Q-Networks(DQN)

Deep Q-Networks&#xff08;DQN&#xff09;是一种将深度学习技术与Q学习算法相结合的强化学习方法。通过使用深度神经网络来近似Q函数&#xff0c;DQN能够有效地处理具有高维状态空间的复杂问题&#xff0c;这在传统的Q学习方法中是难以实现的。DQN的提出标志着强化学习在处理…

jeecg 启动 微服务 更改配置本地host地址

1. windows系统下&#xff0c;在开始—运行里面输入(找不到运行菜单可直接按WinR键)&#xff1a; C:\WINDOWS\system32\drivers\etc &#xff0c;如图所示&#xff1a; 2. 用记事本 打开这个文件 在最下面输入这个即可

根据索引策略对elasticsearch中的索引进行管理(附带图文教程)

前言 这是我在这个网站整理的笔记,有错误的地方请指出&#xff0c;关注我&#xff0c;接下来还会持续更新。 作者&#xff1a;神的孩子都在歌唱 一. 索引生命周期简介 想要了解更多可以看 &#xff1a; 索引生命周期 1.1 索引生命周期五种阶段 &#xff08;1&#xff09;Hot…

netstat命令常用的选项

-n:使用IP地址表示主机,而不是主机名;使用数字表示端口号,而不是服务名称, -a:显示结果中也包括监听socket; -t:仅显示TCP连接. -r:显示路由信息. -i:显示网卡接口的数据流量 -c:每隔1s输出一次. -o:显示socket定时器(比如保活定时器)的信息,-p:显示socket所属的进程的PI…

初学者必会的Python3文件操作

文件操作的步骤&#xff1a; 打开文件 -> 操作文件 -> 关闭文件 切记&#xff1a;最后要关闭文件。 打开文件 文件句柄 open(文件路径, 模式) 指定文件编码 文件句柄 open(文件路径,模式,encodingutf-8) 为了防止忘记关闭文件&#xff0c;可以使用上下文管理器来…

不知道显卡型号 用什么方法可以知道具体型号要下载驱动

环境&#xff1a; Win10 专业版 问题描述&#xff1a; 不知道显卡型号 用什么方法可以知道具体型号要下载驱动 解决方案&#xff1a; 通过以下几种方法来获取&#xff1a; 1.使用操作系统自带的设备管理器&#xff1a;在Windows操作系统中&#xff0c;你可以打开设备管理…

深入解析Java内存模型

一、背景 并发编程本质问题是&#xff1a;CPU、内存以及IO三者之间的速度差异。CPU速度快于内存、内存访问速度又远远快于IO&#xff0c;根据木桶理论&#xff0c;程序性能取决于最慢的操作&#xff0c;即IO操作。这样会出现CPU和内存交互时&#xff0c;CPU性能无法被充分利用…

GIS学习笔记(四):GIS数据可视化综合(矢量数据)

矢量数据 arcgis的主要可视化工具&#xff1a;属性 符号系统 符号系统 按类别 这里不会涉及到数字的大小因素&#xff0c;只是按照字符的分类去做可视化 “唯一值”的含义 “建筑年代”字段共有10个年份&#xff0c;一个年份也许有多个数据( eg.1990年的建筑有20个)&…

DayDreamInGIS 之 ArcGIS Pro二次开发 锐角检查

功能&#xff1a;检查图斑中所有的夹角&#xff0c;如果为锐角&#xff0c;在单独的标记图层中标记。生成的结果放在默认gdb中&#xff0c;以 图层名_锐角检查 的方式命名 大体实现方式&#xff1a;遍历图层中的所有要素&#xff08;多部件要素分别处理&#xff09;&#xff0…

C语言字符函数和字符串函数

前言 今天这篇博客咱们一起来认识一些特殊的函数&#xff0c;在编程的过程中&#xff0c;我们经常要处理字符和字符串&#xff0c;为了方便字符和字符串&#xff0c;C语言提供了一些库函数&#xff0c;让我们一起看看这些函数都有什么功能吧&#xff01;&#xff01;&#xff0…

Linux的目录结构(介绍主要的)

/&#xff1a;根目录&#xff0c;文件系统的起点&#xff0c;包含了所有目录和文件 /bin&#xff1a;存放基本的可执行命令&#xff0c;如ls&#xff0c;cp&#xff0c;rm /lib&#xff1a;主要存放动态链接库 /opt&#xff1a;供第三方软件安装的目录&#xff0c;通常将软件…

C#使用自定义的泛型节点类 Node<T>实现二叉树类BinaryTree<T>及其方法

目录 一、涉及到的知识点 1.Comparer.Default 属性 2.实现二叉树类BinaryTree步骤 &#xff08;1&#xff09;先设计一个泛型节点类 &#xff08;2&#xff09;再设计一个泛型的二叉树类 &#xff08;3&#xff09;最后设计Main方法 二、 使用泛型节点类 Node实现二叉树…

基础刷题50之八(数组元素积的符号)

文章目录 前言一、题目二、力扣官方解释文心一言解释总结 前言 刚上研一&#xff0c;有人劝我好好学C&#xff0c;当时用的不多就没学&#xff0c;现在毕业上班了。在此亡羊补牢了 在此感谢力扣和文心一言 一、题目 数组元素积的符号 已知函数 signFunc(x) 将会根据 x 的正负…

python读取execl里的图片

正常的读取图片 from openpyxl import load_workbook from PIL import Imagefrom openpyxl import load_workbook wb load_workbook(rC:\Users\Administrator\Downloads\output1111.xlsx) ws wb[wb.sheetnames[0]] for image in ws._images:data image.anchor._fromif image…

深耕大屏营销领域的酷开科技,为品牌方带来更多的收益

互联网作为一种新的发展趋势&#xff0c;更是为我们提供了无数的机会和无限可能性&#xff0c;从电子商务时代到社交网络时代&#xff0c;价值文化也成为了品牌与消费者之间紧密联系的关键纽带。而在此背景下&#xff0c;OTT大屏拥有着独特的优势&#xff0c;作为OTT行业内的独…

数据库三大范式设计原则

数据库三大范式 第一范式(确保每列保持原子性) 第一范式是最基本的范式。如果数据库表中的所有字段值都是不可分解的原子值&#xff0c;就说明该数据库表满足了第一范式。 第二范式(确保表中的每列都和主键相关) 第二范式在第一范式的基础之上更进一层。第二范式需要确保数据…

第十节 JDBC事务

如果JDBC连接处于自动提交模式&#xff0c;默认情况下&#xff0c;则每个SQL语句在完成后都会提交到数据库。 对于简单的应用程序可能没有问题&#xff0c;但是有三个原因需要考虑是否关闭自动提交并管理自己的事务 - 提高性能保持业务流程的完整性使用分布式事务 事务能够控…

网络工程师——2024自学

一、怎样从零开始学习网络工程师 当今社会&#xff0c;人人离不开网络。整个IT互联网行业&#xff0c;最好入门的&#xff0c;网络工程师算是一个了。 什么是网络工程师呢&#xff0c;简单来说&#xff0c;就是互联网从设计、建设到运行和维护&#xff0c;都需要网络工程师来…

03在ESP-IDF中使用C++面向对象编程

在ESP-IDF中使用C和C进行混合编译 ESP-IDF是Espressif Systems开发的官方IoT开发框架&#xff0c;用于编程和开发ESP32系列的微控制器。虽然ESP-IDF主要使用C语言编写&#xff0c;但它也支持使用C进行开发 为什么要进行混合编译&#xff1f; C是一种功能强大的编程语言&…

Win11右键菜单恢复经典样式

一、使用Cmd恢复Windows 11上的经典上下文菜单 1.使用管理员权限打开Cmd 2.复制并粘贴以下代码&#xff0c;然后按enter键 reg.exe add "HKCU\Software\Classes\CLSID\{86ca1aa0-34aa-4e8b-a509-50c905bae2a2}\InprocServer32" /f 二、使用Cmd恢复Windows 11上的默认…