基本介绍

我们日常的开发就很好地体现出了命令模式,比如:领导将开发任务指派给程序员去完成。其中领导就是“命令的发布者(调用者)”,程序员就是“命令的具体执行者(接收者)”,这个指派的动作就是“具体的命令”。命令将调用者和接收者进行连接,从而完成开发任务,这一套流程就可以看作是命令模式的执行原理。

命令模式使得请求的发送者与请求的执行者之间消除耦合,让对象之间的调用关系更加灵活。在命令模式中,会将一个命令封装成一个对象,同时命令模式也支持可撤销的操作。

命令模式UML类图

说出四种常用的设计模式(设计模式系列一文带你了解)(1)

UML类图讲解

Invoker:调用者角色。Command:抽象命令角色,封装了所有需要执行的命令,可以是抽象类或接口。Receiver:接收者角色,具体执行命令的类。ConcreteCommand:具体命令角色,实现了Command类,并聚合了Receiver类。该类的作用是将一个接收者对象与一个命令进行绑定。

案例讲解

通过上面的介绍相信大家对命令模式模式有了一个简单的认识,下面让我们通过一个案例来加深对该模式的理解。

案例:实现通过遥控器开关电视以及撤销上一次操作的功能。

命令接口 => 对应抽象命令角色

public interface Command { // 执行操作 void execute(); // 撤销操作 void undo(); }

电视 => 对应接收者角色

public class TVReceiver { public void on() { System.out.println("电视机打开了。"); } public void off() { System.out.println("电视机关闭了。"); } }

具体命令实现类

/** * 开电视 */ public class TVOnCommand implements Command { // 聚合TVReceiver private TVReceiver tv; public TVOnCommand(TVReceiver tv) { this.tv = tv; } @Override public void execute() { // 执行打开电视机命令 this.tv.on(); } @Override public void undo() { // 执行关闭电视机命令,因为打开电视对应的就是关闭。 this.tv.off(); } } /** * 关闭电视 */ public class TVOffCommand implements Command { // 聚合TVReceiver private TVReceiver tv; public TVOffCommand(TVReceiver tv) { this.tv = tv; } @Override public void execute() { // 执行关闭电视机命令 this.tv.off(); } @Override public void undo() { // 执行打开电视机命令,因为关闭电视机对应的就是打开。 this.tv.on(); } } /** * 空命令 * 该类默认实现Command接口,不执行任何命令。添加该类的作用是 * 为了省略执行操作时对空的判断。 */ public class NoCommand implements Command { @Override public void execute() { } @Override public void undo() { } }

遥控器 => 对应调用者角色

public class RemoteController { // 开按钮的命令 private Command onCommand = new NoCommand(); // 关按钮的命令 private Command offCommand = new NoCommand(); // 执行撤销的命令 private Command undoCommand = new NoCommand(); // 给按钮设置相关命令 public void setCommand(Command onCommand, Command offCommand) { this.onCommand = onCommand; this.offCommand = offCommand; } // 按下打开按钮 public void onButtonWasPushed() { this.onCommand.execute(); // 记录本次操作 this.undoCommand = this.onCommand; } // 按下关闭按钮 public void offButtonWasPushed() { this.offCommand.execute(); // 记录本次操作 this.undoCommand = this.offCommand; } // 按下撤销按钮 public void undoButtonWasPushed() { this.undoCommand.undo(); } }

客户端测试类

public class Client { public static void main(String[] args) { // 创建电视机接收者 TVReceiver tvReceiver = new TVReceiver(); // 创建电视机开关命令 TVOnCommand tvOnCommand = new TVOnCommand(tvReceiver); TVOffCommand tvOffCommand = new TVOffCommand(tvReceiver); // 创建遥控器 RemoteController remoteController = new RemoteController(); // 设置命令 remoteController.setCommand(tvOnCommand, tvOffCommand); System.out.println("======按下打开按钮======"); remoteController.onButtonWasPushed(); System.out.println("======按下关闭按钮======"); remoteController.offButtonWasPushed(); System.out.println("======撤销上次操作======"); remoteController.undoButtonWasPushed(); } }

执行结果

说出四种常用的设计模式(设计模式系列一文带你了解)(2)

总结

优点

1、调用者只需要调用命令对象的“执行”方法就可以让接收者工作,而不必知道具体是谁接收的命令,命令是如何被执行的。将发起命令请求的对象和执行命令的对象拆分开从而促使代码解耦,通过这样的设计将利于程序的扩展。2、通过添加一个“空命令”来省去判空的操作。3、通过添加撤销方法可以实现对命令的撤销重做。

缺点:

造成系统存在过多的具体命令类,增加系统的复杂度。

注意

命令对象负责让具体的接收者执行指定的操作,它就是连接“请求发起者”和“请求执行者”的桥梁。

今天的分享就到这里了,如果感觉“菜鸟”写的文章还不错,记得点赞关注呦!你们的支持就是我坚持下去的动力。文章哪里写的有问题的也希望大家可以指出,我会虚心受教。

说出四种常用的设计模式(设计模式系列一文带你了解)(3)

,