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

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

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

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

 

相关实践学习
通过日志服务实现云资源OSS的安全审计
本实验介绍如何通过日志服务实现云资源OSS的安全审计。
相关文章
|
9月前
|
设计模式 网络协议 Java
【设计模式】【行为型模式】状态模式(State)
一、入门 什么是状态模式? 状态模式(State Pattern)是一种行为设计模式,允许对象在其内部状态改变时改变其行为,使其看起来像是改变了类。状态模式的核心思想是将对象的状态封装成独立的类,并将
369 16
|
9月前
|
设计模式 算法 前端开发
【设计模式】【行为型模式】职责链模式(Chain of Responsibility)
一、入门 什么是职责链模式? 职责链模式是一种行为设计模式,它允许你将请求沿着一条链传递,直到有对象处理它为止。每个对象都有机会处理请求,或者将其传递给链中的下一个对象。 为什么需要职责链模式? 使用
349 16
|
9月前
|
设计模式 存储 Java
【设计模式】【行为型模式】备忘录模式(Memento)
一、入门 什么是备忘录模式? 备忘录模式(Memento Pattern)是一种行为设计模式,用于在不破坏封装性的前提下,捕获并外部化一个对象的内部状态,以便在需要时恢复该状态。它通常用于实现撤销操作
305 8
|
9月前
|
设计模式 消息中间件 Java
【设计模式】【行为型模式】命令模式(Command)
一、入门 什么是命令模式? 命令模式是一种行为设计模式,它将请求或操作封装为对象,从而使你可以用不同的请求对客户进行参数化,并支持请求的排队、记录、撤销等操作。 命令模式的核心是将“请求”封装为独立的
275 15
|
9月前
|
设计模式 算法 搜索推荐
【设计模式】【行为型模式】策略模式(Strategy)
一、入门 什么是策略模式? 策略模式是一种行为设计模式,允许在运行时选择算法或行为。它将算法封装在独立的类中,使得它们可以互换,而不影响客户端代码。 为什么需要策略模式? 策略模式的主要目的是解决算法
199 14
|
9月前
|
设计模式 数据采集 算法
【设计模式】【行为型模式】模板方法模式(Template Method)
一、入门 1.1、什么是模板方法模式? 模板模式(Template Method Pattern)是一种行为设计模式,它定义了一个算法的框架,并允许子类在不改变算法结构的情况下重新定义算法的某些步骤。
295 13
|
9月前
|
设计模式 Java 编译器
【设计模式】【行为型模式】解释器模式(Interpreter)
一、入门 什么是解释器模式? 解释器模式(Interpreter Pattern)是一种行为设计模式,用于定义语言的语法表示,并提供一个解释器来处理该语法。它通常用于需要解释和执行特定语言或表达式的场
221 11
|
9月前
|
设计模式 存储 JavaScript
【设计模式】【行为型模式】迭代器模式(Iterator)
一、入门 什么是迭代器模式? 迭代器模式(Iterator Pattern)是一种行为设计模式,它提供了一种顺序访问聚合对象中元素的方法,而不需要暴露其底层表示。迭代器模式将遍历逻辑从聚合对象中分离出
252 11
|
9月前
|
设计模式 XML JSON
【设计模式】【行为型模式】访问者模式(Visitor)
一、入门 什么是访问者模式? 访问者模式(Visitor Pattern)是一种行为设计模式,允许你将算法与对象结构分离。通过这种方式,可以在不改变对象结构的情况下,向对象结构中的元素添加新的操作。
294 10
|
9月前
|
设计模式 Java 程序员
【设计模式】【行为型模式】中介者模式(Mediator)
一、入门 什么是中介者模式? 中介者模式(Mediator Pattern)是一种行为设计模式,旨在减少对象之间的直接依赖,通过引入一个中介者对象来协调多个对象之间的交互。这种模式特别适用于对象间存在
229 9