您当前的位置:首页 > 电脑百科 > 程序开发 > 编程百科

命令模式:将请求封装为对象

时间:2023-10-19 16:03:04  来源:微信公众号  作者:小李哥编程

命令模式:将请求封装为对象
什么是命令模式?

命令模式是一种行为型设计模式,它将请求或操作封装成独立的命令对象。这些命令对象包括了执行操作所需的所有信息,例如操作方法、参数和接收者。
命令模式允许您将命令发送者(客户端)和命令执行者(接收者)解耦,使得发送者无需知道接收者的具体类别。
在命令模式中,通常包含以下关键角色:
  1. 命令(Command):声明了执行操作的接口,通常包括一个 execute 方法。
  2. 具体命令(Concrete Command):实现了命令接口,包含了实际的操作逻辑。每个具体命令对象都与一个接收者相关联。
  3. 接收者(Receiver):执行命令实际操作的对象。
  4. 调用者(Invoker):负责调用命令对象来执行请求。
  5. 客户端(Client):创建命令对象并设置其接收者,然后将命令对象传递给调用者。

为什么需要命令模式?

命令模式有以下几个优点:
  1. 解耦:命令模式可以将发送者和接收者解耦,发送者无需知道接收者的具体实现,从而提高了系统的灵活性。
  2. 可扩展性:您可以轻松地添加新的命令类,而无需修改已有的代码。
  3. 撤销操作:命令对象通常会保存操作的状态,从而支持撤销操作。
  4. 日志记录和事务管理:您可以使用命令模式来记录所有执行的命令,以便进行事务管理或撤销。

命令模式的实现

让我们通过一个简单的示例来演示命令模式的实现。假设我们正在构建一个遥控器应用,用户可以通过遥控器执行不同的操作,例如打开电视、切换频道和调整音量。
首先,我们定义一个命令接口 Command,它包括了一个 execute 方法:

 
public interface Command {
void execute();
}
 
接下来,我们创建具体的命令类,例如 TurnOnCommandChangeChannelCommand 和 AdjustVolumeCommand,它们实现了 Command 接口,并分别执行相应的操作。

 
public class TurnOnCommand implements Command {
private Television television;

public TurnOnCommand(Television television) {
this.television = television;
}

public void execute() {
television.turnOn();
}
}

// 类似地实现 ChangeChannelCommand 和 AdjustVolumeCommand
 
然后,我们创建接收者类 Television,它包含了实际的操作逻辑:

 
public class Television {
public void turnOn() {
System.out.println("电视已打开");
}

public void changeChannel() {
System.out.println("切换频道");
}

public void adjustVolume() {
System.out.println("调整音量");
}
}
 
最后,我们创建调用者类 RemoteControl,它接收并执行命令:

 
public class RemoteControl {
private Command command;

public void setCommand(Command command) {
this.command = command;
}

public void pressButton() {
command.execute();
}
}
 
客户端代码如下:

 
public class Client {
public static void mAIn(String[] args) {
Television television = new Television();

Command turnOnCommand = new TurnOnCommand(television);
Command changeChannelCommand = new ChangeChannelCommand(television);
Command adjustVolumeCommand = new AdjustVolumeCommand(television);

RemoteControl remoteControl = new RemoteControl();

remoteControl.setCommand(turnOnCommand);
remoteControl.pressButton();

remoteControl.setCommand(changeChannelCommand);
remoteControl.pressButton();

remoteControl.setCommand(adjustVolumeCommand);
remoteControl.pressButton();
}
}
 
这个示例中,我们将不同的操作(打开电视、切换频道、调整音量)封装成了命令对象,通过遥控器执行这些命令,而不需要直接调用接收者的方法。

宏命令

宏命令是一种命令模式的扩展,它允许您将多个命令组合成一个更大的命令。宏命令本身也是一个命令,可以执行一系列子命令。这对于执行复杂的操作或者创建多级撤销机制非常有用。
让我们通过一个示例来了解宏命令。假设我们有一个文本编辑器,需要实现一个宏命令来执行以下操作:
  1. 打开文件
  2. 编辑文件
  3. 保存文件
首先,我们定义一个宏命令接口 macroCommand,它包含了 add 和 execute 方法:

 
public interface MacroCommand {
void add(Command command);
void execute();
}
 
接下来,我们创建一个具体的宏命令类 TextEditorMacro,它可以添加和执行多个子命令:

 
public class TextEditorMacro implements MacroCommand {
private List<Command> commands = new ArrayList<>();

public void add(Command command) {
commands.add(command);
}

public void execute() {
for (Command command : commands) {
command.execute();
}
}
}
 
然后,我们可以创建多个子命令,例如 OpenFileCommandEditFileCommand 和 SaveFileCommand,它们分别执行打开、编辑和保存文件的操作。
最后,我们可以使用宏命令将这些子命令组合成一个宏命令:

 
public class Client {
public static void main(String[] args) {
OpenFileCommand openFile = new OpenFileCommand();
EditFileCommand editFile = new EditFileCommand();
SaveFileCommand saveFile = new SaveFileCommand();

TextEditorMacro macro = new TextEditorMacro();
macro.add(openFile);
macro.add(editFile);
macro.add(saveFile);

// 执行宏命令,依次执行子命令
macro.execute();
}
}
 
这样,我们就实现了一个宏命令,可以一次性执行多个子命令,从而打开、编辑和保存文件。

撤销和重做

命令模式还支持撤销和重做操作。
为了实现撤销,我们需要在命令对象中保存执行前的状态,并提供一个 undo 方法来恢复到之前的状态。
让我们通过一个简单的示例来演示撤销和重做。假设我们有一个文本编辑器,可以执行添加文本、删除文本和撤销操作。
首先,我们定义一个命令接口 Command,包括了 execute 和 undo 方法:

 
public interface Command {
void execute();
void undo();
}
 
接下来,我们创建具体的命令类,例如 AddTextCommand 和 DeleteTextCommand,它们分别执行添加文本和删除文本的操作,并实现了 undo 方法来撤销操作。

 
public class AddTextCommand implements Command {
private TextEditor textEditor;
private String addedText;

public AddTextCommand(TextEditor textEditor, String addedText) {
this.textEditor = textEditor;
this.addedText = addedText;
}

public void execute() {
textEditor.addText(addedText);
}

public void undo() {
textEditor.deleteText(addedText);
}
}

// 类似地实现 DeleteTextCommand
 
然后,我们创建接收者类 TextEditor,它包含了实际的文本编辑逻辑,包括添加文本、删除文本和显示文本。

 
public class TextEditor {
private StringBuilder text = new StringBuilder();

public void addText(String addedText) {
text.Append(addedText);
}

public void deleteText(String deletedText) {
int start = text.lastIndexOf(deletedText);
if (start != -1) {
text.delete(start, start + deletedText.length());
}
}

public void displayText() {
System.out.println(text.toString());
}
}
 
最后,我们可以创建一个客户端来测试撤销和重做操作:

 
public class Client {
public static void main(String[] args) {
TextEditor textEditor = new TextEditor();

Command addCommand1 = new AddTextCommand(textEditor, "Hello, ");
Command addCommand2 = new AddTextCommand(textEditor, "Design Patterns!");
Command deleteCommand = new DeleteTextCommand(textEditor, "Patterns!");

// 执行添加和删除操作
addCommand1.execute();
addCommand2.execute();
deleteCommand.execute();

// 显示当前文本
textEditor.displayText(); // 输出: Hello, Design!

// 撤销删除操作
deleteCommand.undo();

// 显示当前文本
textEditor.displayText(); // 输出: Hello, Design Patterns!
}
}
 
通过上述代码,我们实现了撤销和重做操作,可以在执行操作后撤销到之前的状态,然后再重做。这在需要保留操作历史的应用程序中非常有用。

总结

命令模式是一种行为型设计模式,它将请求和操作解耦,允许将操作封装成独立的命令对象。这使得我们能够实现撤销、重做、宏命令等高级功能,并且更容易扩展新的命令。
在设计软件系统时,考虑使用命令模式来提高代码的可维护性和灵活性,特别是需要支持撤销和重做功能的应用程序。


Tags:封装   点击:()  评论:()
声明:本站部分内容及图片来自互联网,转载是出于传递更多信息之目的,内容观点仅代表作者本人,不构成投资建议。投资者据此操作,风险自担。如有任何标注错误或版权侵犯请与我们联系,我们将及时更正、删除。
▌相关推荐
命令模式:将请求封装为对象
什么是命令模式?命令模式是一种行为型设计模式,它将请求或操作封装成独立的命令对象。这些命令对象包括了执行操作所需的所有信息,例如操作方法、参数和接收者。命令模式允许...【详细内容】
2023-10-19  Search: 封装  点击:(257)  评论:(0)  加入收藏
Java内部类与匿名内部类:实现代码的封装与简化
Java内部类和匿名内部类是Java语言中的两种特殊类型的类。它们可以帮助我们实现代码的封装和简化,提高代码的可读性和可维护性。Java内部类是定义在另一个类内部的类,内部类可...【详细内容】
2023-10-19  Search: 封装  点击:(267)  评论:(0)  加入收藏
Springboot+Redisson封装分布式锁Starter
我们将分布式锁基于缓存扩展了一版,也就是说本starter即有分布式缓存功能,又有分布式锁功能。而注解版的分布式锁能够解决大多数场景的并核问题,小粒度的Lock锁方式补全其他场...【详细内容】
2023-08-28  Search: 封装  点击:(254)  评论:(0)  加入收藏
一次DOM曝光封装历程
随着最近曝光埋点的需求越来越频繁,就想把之前写好的曝光逻辑抽出来封装了一下作为公用。初版逻辑:window.scroll 监听滚动 + 使用 getBoundingClientRect() 相对于视口位置...【详细内容】
2023-08-02  Search: 封装  点击:(248)  评论:(0)  加入收藏
为何英伟达“独宠”台积电而非三星电子?封装技术才是王道
全球客户都在排着队购买英伟达的图形处理单元(GPU)。近年来,人工智能(AI)产业的快速发展推动了全球对GPU的需求,导致目前供不应求的局面。GPU可以被视作ChatGPT等生成式人工智能(AI...【详细内容】
2023-07-04  Search: 封装  点击:(68)  评论:(0)  加入收藏
App在线封装容易吗?是什么原理?
App在线封装是一种将网页应用封装成App的技术,通过这种技术,用户可以在不下载安装App的情况下,直接在浏览器中使用App的功能。相对于传统的App开发模式,App在线封装具有更低的开...【详细内容】
2023-06-30  Search: 封装  点击:(240)  评论:(0)  加入收藏
Vue3+Axios网络请求封装
Vue3是Vue.js框架的最新版本,它在语法、性能和开发体验等方面都进行了优化和改进。而Axios则是一个基于Promise的HTTP客户端,可以在浏览器和Node.js中使用。Axios可以帮助我们...【详细内容】
2023-05-30  Search: 封装  点击:(234)  评论:(0)  加入收藏
DOM怎么封装的?各种库是怎么写的?
DOM怎么封装的?各种库是怎么写的?(DOM库,AJAX库,动画 库,事件库)?在作用域套作用域的时候;子作用域内尽量不返回引用数据类型,因为闭包内的值,是另外一个子闭包的返回值的时候,如果子...【详细内容】
2023-05-19  Search: 封装  点击:(252)  评论:(0)  加入收藏
使用开源 Python API 封装器与你的集群对话
结合开放的 API 和 Python 编程语言的力量。围绕 API 创建封装器的开源项目正变得越来越流行。这些项目使开发人员更容易与 API 交互并在他们的应用中使用它们。openshift-p...【详细内容】
2023-05-08  Search: 封装  点击:(316)  评论:(0)  加入收藏
不要再封装各种Util工具类了,这个神级框架你值得拥有!
今天给大家推荐一个非常好用的Java工具类库,企业级常用工具类,基本都有,能避免重复造轮子及节省大量的开发时间,非常不错,值得大家去了解使用。Hutool谐音 “糊涂”,寓意追求 “万...【详细内容】
2023-02-27  Search: 封装  点击:(252)  评论:(0)  加入收藏
▌简易百科推荐
即将过时的 5 种软件开发技能!
作者 | Eran Yahav编译 | 言征出品 | 51CTO技术栈(微信号:blog51cto) 时至今日,AI编码工具已经进化到足够强大了吗?这未必好回答,但从2023 年 Stack Overflow 上的调查数据来看,44%...【详细内容】
2024-04-03    51CTO  Tags:软件开发   点击:(5)  评论:(0)  加入收藏
跳转链接代码怎么写?
在网页开发中,跳转链接是一项常见的功能。然而,对于非技术人员来说,编写跳转链接代码可能会显得有些困难。不用担心!我们可以借助外链平台来简化操作,即使没有编程经验,也能轻松实...【详细内容】
2024-03-27  蓝色天纪    Tags:跳转链接   点击:(12)  评论:(0)  加入收藏
中台亡了,问题到底出在哪里?
曾几何时,中台一度被当做“变革灵药”,嫁接在“前台作战单元”和“后台资源部门”之间,实现企业各业务线的“打通”和全域业务能力集成,提高开发和服务效率。但在中台如火如荼之...【详细内容】
2024-03-27  dbaplus社群    Tags:中台   点击:(8)  评论:(0)  加入收藏
员工写了个比删库更可怕的Bug!
想必大家都听说过删库跑路吧,我之前一直把它当一个段子来看。可万万没想到,就在昨天,我们公司的某位员工,竟然写了一个比删库更可怕的 Bug!给大家分享一下(不是公开处刑),希望朋友们...【详细内容】
2024-03-26  dbaplus社群    Tags:Bug   点击:(5)  评论:(0)  加入收藏
我们一起聊聊什么是正向代理和反向代理
从字面意思上看,代理就是代替处理的意思,一个对象有能力代替另一个对象处理某一件事。代理,这个词在我们的日常生活中也不陌生,比如在购物、旅游等场景中,我们经常会委托别人代替...【详细内容】
2024-03-26  萤火架构  微信公众号  Tags:正向代理   点击:(10)  评论:(0)  加入收藏
看一遍就理解:IO模型详解
前言大家好,我是程序员田螺。今天我们一起来学习IO模型。在本文开始前呢,先问问大家几个问题哈~什么是IO呢?什么是阻塞非阻塞IO?什么是同步异步IO?什么是IO多路复用?select/epoll...【详细内容】
2024-03-26  捡田螺的小男孩  微信公众号  Tags:IO模型   点击:(8)  评论:(0)  加入收藏
为什么都说 HashMap 是线程不安全的?
做Java开发的人,应该都用过 HashMap 这种集合。今天就和大家来聊聊,为什么 HashMap 是线程不安全的。1.HashMap 数据结构简单来说,HashMap 基于哈希表实现。它使用键的哈希码来...【详细内容】
2024-03-22  Java技术指北  微信公众号  Tags:HashMap   点击:(11)  评论:(0)  加入收藏
如何从头开始编写LoRA代码,这有一份教程
选自 lightning.ai作者:Sebastian Raschka机器之心编译编辑:陈萍作者表示:在各种有效的 LLM 微调方法中,LoRA 仍然是他的首选。LoRA(Low-Rank Adaptation)作为一种用于微调 LLM(大...【详细内容】
2024-03-21  机器之心Pro    Tags:LoRA   点击:(12)  评论:(0)  加入收藏
这样搭建日志中心,传统的ELK就扔了吧!
最近客户有个新需求,就是想查看网站的访问情况。由于网站没有做google的统计和百度的统计,所以访问情况,只能通过日志查看,通过脚本的形式给客户导出也不太实际,给客户写个简单的...【详细内容】
2024-03-20  dbaplus社群    Tags:日志   点击:(4)  评论:(0)  加入收藏
Kubernetes 究竟有没有 LTS?
从一个有趣的问题引出很多人都在关注的 Kubernetes LTS 的问题。有趣的问题2019 年,一个名为 apiserver LoopbackClient Server cert expired after 1 year[1] 的 issue 中提...【详细内容】
2024-03-15  云原生散修  微信公众号  Tags:Kubernetes   点击:(6)  评论:(0)  加入收藏
站内最新
站内热门
站内头条