设计模式-行为型模式:命令模式

本文涉及的产品
日志服务 SLS,月写入数据量 50GB 1个月
简介: 设计模式-行为型模式:命令模式

1、简介

命令模式(Command Pattern)是一种行为型设计模式,它使得能够将请求封装成对象,并且让我们可以用不同的请求对客户端进行参数化,同时能够支持请求排队或记录请求日志,以及支持可撤销的操作。

2、组成部分

命令模式的核心结构包括以下四个部分:

  • Command(命令):声明了一个执行操作的接口。通常会包含一个 execute() 方法,当调用该方法时,接收者会执行相应的操作。
  • ConcreteCommand(具体命令):将一个接收者对象与一个动作(如一个方法调用)绑定起来。实现 execute() 方法,调用接收者相应的操作。
  • Receiver(接收者):知道如何实施与执行一个请求相关的操作。任何类都可能作为一个接收者。
  • Invoker(调用者):请求者,发起者。通过一个或多个命令对象来执行请求。它要求命令对象执行请求。

这些组件间的关系如下图所示:

3、优缺点

优点:

  1. 降低系统的耦合度:命令模式将请求和接收者对象解耦,使得系统更加灵活,并且可以方便地添加或删除命令,而不会对其他的对象产生影响。
  2. 容易扩展新的命令:命令模式使得添加新的命令非常容易,只需要实现新的命令对象,并将其加入到命令的集合中即可。
  3. 支持撤销和重做操作:命令模式可以记录所有执行过的命令,支持撤销和重做操作,这对于某些需要撤销操作的场景非常有用。
  4. 支持请求队列:命令模式可以将请求放入请求队列中,使得请求可以被延迟执行或者排队执行,这可以避免请求的发送者和接收者之间的时间耦合。

缺点:

  1. 可能会导致过多的具体命令类:每个具体命令都需要实现一个新的类,这可能会导致系统中存在大量的具体命令类,从而增加系统的复杂度。
  2. 可能会增加系统的代码复杂度:命令模式中需要定义多个类和接口,从而增加了系统的代码复杂度,这可能会增加开发成本和维护成本。

总之,命令模式是一种非常有用的设计模式,它可以使得系统更加灵活,并且可以方便地添加或删除命令,同时也支持撤销和重做操作。但是,在使用命令模式时,需要根据具体的情况权衡其优缺点,从而选择最适合的设计模式。

4、使用场景

命令模式是一种常用的设计模式,它适用于以下场景:

  1. 需要对请求进行排队或记录日志:命令模式可以将请求放入请求队列中,从而可以对请求进行排队或记录日志。例如,我们可以将用户的操作请求放入队列中,以便在系统繁忙时处理这些请求。
  2. 需要支持撤销和重做操作:命令模式可以记录所有执行过的命令,支持撤销和重做操作。例如,我们可以使用命令模式来实现文本编辑器中的撤销和重做功能。
  3. 需要支持事务操作:命令模式可以将一组相关的操作封装在一起,以支持事务操作。例如,我们可以使用命令模式来实现数据库中的事务处理。
  4. 需要支持日志记录和审计功能:命令模式可以记录每个命令的执行时间和执行者等信息,从而支持日志记录和审计功能。例如,我们可以使用命令模式来记录用户对系统的操作行为。
  5. 需要支持命令的撤销和重做操作:命令模式可以记录每个命令的执行状态,以支持撤销和重做操作。例如,在图形用户界面中,我们可以使用命令模式来实现对绘制命令的撤销和重做操作。
  6. 需要实现多级菜单或工具栏:命令模式可以将菜单或工具栏中的每个按钮都封装成一个命令,从而可以方便地添加或删除按钮,而不会对其他的按钮产生影响。

总之,命令模式可以解耦请求发送者和请求接收者之间的关系,使得系统更加灵活,同时也支持撤销和重做操作,日志记录和审计等功能。因此,命令模式在许多场景下都是非常有用的。

5、代码实现

下面是一个简单的例子来演示命令模式的使用场景。假设我们有一个遥控器,它能够控制各种设备,包括电视、音响等等。现在我们要实现一个遥控器,它具有打开电视、关闭电视、打开音响、关闭音响等功能。

首先,我们需要定义一个命令接口,其中包含了一个 execute() 方法:

1. public interface Command {
2. void execute();
3. }

然后,我们可以定义具体的命令类,如下所示:

1. public class TVOnCommand implements Command {
2. private TV tv;
3. 
4. public TVOnCommand(TV tv) {
5. this.tv = tv;
6.     }
7. 
8. @Override
9. public void execute() {
10.         tv.turnOn();
11.     }
12. }
1. public class TVOffCommand implements Command {
2. private TV tv;
3. 
4. public TVOffCommand(TV tv) {
5. this.tv = tv;
6.     }
7. 
8. @Override
9. public void execute() {
10.         tv.turnOff();
11.     }
12. }
1. public class StereoOnCommand implements Command {
2. private Stereo stereo;
3. 
4. public StereoOnCommand(Stereo stereo) {
5. this.stereo = stereo;
6.     }
7. 
8. @Override
9. public void execute() {
10.         stereo.turnOn();
11.     }
12. }
1. public class StereoOffCommand implements Command {
2. private Stereo stereo;
3. 
4. public StereoOffCommand(Stereo stereo) {
5. this.stereo = stereo;
6.     }
7. 
8. @Override
9. public void execute() {
10.         stereo.turnOff();
11.     }
12. }

其中,TVOnCommand、TVOffCommand、StereoOnCommand、StereoOffCommand 分别对应了打开电视、关闭电视、打开音响和关闭音响四种不同的命令。每个命令类都实现了 Command 接口,并且包含了一个接收者对象,用于执行实际的操作。

接下来,我们需要定义一个遥控器,它能够存储各种不同的命令,并且可以按下按钮来执行命令:

1. public class RemoteControl {
2. private Command[] onCommands;
3. private Command[] offCommands;
4. 
5. public RemoteControl() {
6.         onCommands = new Command[2];
7.         offCommands = new Command[2];
8.     }
9. 
10. public void setCommand(int slot, Command onCommand, Command offCommand) {
11.         onCommands[slot] = onCommand;
12.         offCommands[slot] = offCommand;
13.     }
14. 
15. public void onButtonWasPushed(int slot) {
16.         onCommands[slot].execute();
17.     }
18. 
19. public void offButtonWasPushed(int slot) {
20.         offCommands[slot].execute();
21.     }
22. }

在 RemoteControl 中,我们定义了两个数组,分别用于存储打开命令和关闭命令。setCommand() 方法用于设置命令,onButtonWasPushed() 和 offButtonWasPushed() 方法分别用于执行打开命令和关闭命令。

最后,我们需要定义接收者对象,也就是电视和音响:

1. public class TV {
2. public void turnOn() {
3.         System.out.println("TV is turned on");
4.     }
5. 
6. public void turnOff() {
7.         System.out.println("TV is turned off");
8.     }
9. }
10. 
11. public class Stereo {
12. public void turnOn() {
13.         System.out.println("Stereo is turned on");
14.     }
15. 
16. public void turnOff() {
17.         System.out.println("Stereo is turned off");
18.     }
19. }

现在,我们可以使用这些类来实现一个简单的遥控器,如下所示:

1. public static void main(String[] args) {
2. RemoteControl remote = new RemoteControl();
3. 
4. TV tv = new TV();
5. Stereo stereo = new Stereo();
6. 
7.     remote.setCommand(0, new TVOnCommand(tv), new TVOffCommand(tv));
8.     remote.setCommand(1, new StereoOnCommand(stereo), new StereoOffCommand(stereo));
9. 
10.     remote.onButtonWasPushed(0); // 打开电视
11.     remote.offButtonWasPushed(0); // 关闭电视
12.     remote.onButtonWasPushed(1); // 打开音响
13.     remote.offButtonWasPushed(1); // 关闭音响
14. }

输出结果为:

       TV is turned on

       TV is turned off

       Stereo is turned on

       Stereo is turned off

这个例子中,我们使用了命令模式,将请求封装成了对象,并且支持了请求排队、记录请求日志和支持可撤销的操作。这使得我们可以将遥控器的功能动态地配置,并且可以将不同的命令对象组合成新的组合命令,从而实现更多的功能。同时,由于每个命令对象都独立,所以可以方便地进行单元测试和模块化开发。

 

相关实践学习
日志服务之使用Nginx模式采集日志
本文介绍如何通过日志服务控制台创建Nginx模式的Logtail配置快速采集Nginx日志并进行多维度分析。
相关文章
|
3天前
|
设计模式
命令模式-大话设计模式
命令模式-大话设计模式
7 2
|
1天前
|
设计模式 Java uml
必知的技术知识:JAVA【设计模式】命令模式
必知的技术知识:JAVA【设计模式】命令模式
|
2天前
|
设计模式 Java
Java设计模式之命令模式详解
Java设计模式之命令模式详解
|
8天前
|
设计模式
设计模式之命令模式
设计模式之命令模式
|
1月前
|
设计模式 Java 调度
【设计模式系列笔记】命令模式
命令模式是一种行为设计模式,它将请求封装成一个对象,从而允许使用不同的请求、队列或日志请求参数化客户端对象,同时支持撤销操作。
36 1
|
1月前
|
设计模式 存储 Java
【搞懂设计模式】命令模式:从遥控器到编程的妙用!
【搞懂设计模式】命令模式:从遥控器到编程的妙用!
30 0
|
1月前
|
设计模式 Java 调度
小谈设计模式(24)—命令模式
小谈设计模式(24)—命令模式
|
1月前
|
设计模式 Java
23种设计模式,命令模式的概念优缺点以及JAVA代码举例
【4月更文挑战第7天】命令模式是一种行为设计模式,它将请求或简单操作封装为一个对象。这种模式允许用户通过调用对象来参数化其他对象的方法,并能保存、排队和执行方法调用。
35 1
|
1月前
|
设计模式 存储 算法
Java设计模式---行为型模式
Java设计模式---行为型模式
|
1月前
|
设计模式 Java C++
命令模式--设计模式
命令模式--设计模式
21 0

热门文章

最新文章